2015-11-04 12 views
5

Desidero trovare le coppie distinte di nomi nella tabella che hanno gli stessi elementi esatti nella colonna degli articoli. Per esempio:Restituisce coppie distinte di nomi che hanno gli stessi elementi esatti nella colonna

CREATE TABLE t 
(
    name VARCHAR(255), 
    item VARCHAR(255) 
); 

INSERT INTO t VALUES("Alice", "Orange"); 
INSERT INTO t VALUES("Alice", "Pear"); 
INSERT INTO t VALUES("Alice", "Lemon"); 
INSERT INTO t VALUES("Bob", "Orange"); 
INSERT INTO t VALUES("Bob", "Pear"); 
INSERT INTO t VALUES("Bob", "Lemon"); 
INSERT INTO t VALUES("Charlie", "Pear"); 
INSERT INTO t VALUES("Charlie", "Lemon"); 

La risposta qui sarebbe Alice,Bob perché hanno preso gli stessi elementi esatti.

Voglio farlo con doppia negazione (utilizzando NON ESISTE/NON IN) solo che penso sia più adatto a questa domanda, ma non ho potuto trovare nulla che sia lontanamente vicino all'essere funzionale.

Questo è in qualche modo simile a this domanda ma sto usando SQLite, quindi non posso usare group_concat() ma mi chiedevo come sarebbe stato fatto utilizzando divisione relazionale utilizzando NON ESISTE/NON IN.

+0

Ti ho creato un SQLFiddle per giocare con h ere ~ http://sqlfiddle.com/#!5/b70cd – Phil

+0

Quanti oggetti diversi puoi avere nella tua tabella? –

+0

@TimBiegeleisen Quanto vuoi. Suppongo che non influisca su nulla, purché possa ancora restituire coppie che contengono lo stesso identico insieme di elementi. – maregor

risposta

1

Con compound queries:

SELECT t1.name, t2.name 
FROM t AS t1, t AS t2 
GROUP BY t1.name, t2.name 
HAVING t1.name < t2.name 
    AND NOT EXISTS (SELECT item FROM t WHERE name = t1.name 
        EXCEPT 
        SELECT item FROM t WHERE name = t2.name) 
    AND NOT EXISTS (SELECT item FROM t WHERE name = t2.name 
        EXCEPT 
        SELECT item FROM t WHERE name = t1.name); 

Utilizzando NON IN è possibile, po esprime esattamente lo stesso meccanismo con maggiore complessità:

SELECT t1.name, t2.name 
FROM t AS t1, t AS t2 
GROUP BY t1.name, t2.name 
HAVING t1.name < t2.name 
    AND NOT EXISTS (SELECT item 
        FROM t 
        WHERE name = t1.name 
        AND item NOT IN (SELECT item 
             FROM t 
             WHERE name = t2.name)) 
    AND NOT EXISTS (SELECT item 
        FROM t 
        WHERE name = t2.name 
        AND item NOT IN (SELECT item 
             FROM t 
             WHERE name = t1.name)); 
0

Probabilmente ho trovato una soluzione al problema. Il mio è stato testato usando MySQL, ma non sta usando GROUP_CONCAT(). Potrebbe funzionare per il tuo database SQLite. La mia query viene utilizzata per trovare persone che hanno acquistato gli stessi elementi esatti.

Provare ad usare questa dichiarazione: SELECT DISTINCT e1.name, e2.name from t e1, t e2 WHERE e1.item=e2.item AND e1.name != e2.name GROUP BY e1.item HAVING count(*) >1;

https://gyazo.com/5e5e9d0ddfb33cb47439a674297108ed

0

Questo sembra funzionare con SqlLite

select t1.name 
    from t t1 
     join t t2 on t1.name <> t2.name and t1.item = t2.item 
     join (select name, count(*) as cnt from t group by name) t3 on t3.name = t1.name 
     join (select name, count(*) as cnt from t group by name) t4 on t4.name = t2.name 
    group by t1.name, t3.cnt, t4.cnt 
    having count(*) = max(t3.cnt, t4.cnt) 
1

Per ottenere il numero di elementi comuni tra tutte le coppie di nomi che è possibile utilizzare il seguente richiesta:

SELECT t1.name AS name1, t2.name AS name2, COUNT(*) AS cnt 
FROM t AS t1 
INNER JOIN t AS t2 ON t1.item = t2.item AND t1.name < t2.name 
GROUP BY t1.name, t2.name 

uscita:

name1 name2  cnt 
------------------------ 
Alice Bob   3 
Alice Charlie  2 
Bob  Charlie  2 

Ora tutto quello che vuoi è quello di filtrare (name1, name2) paia aventi un titolo che non è uguale al numero di elementi di name1 e name2. È possibile farlo utilizzando una clausola HAVING con subquery correlate:

SELECT t1.name AS name1, t2.name AS name2 
FROM t AS t1 
INNER JOIN t AS t2 ON t1.item = t2.item AND t1.name < t2.name 
GROUP BY t1.name, t2.name 
HAVING COUNT(*) = (SELECT COUNT(*) FROM t WHERE name = t1.name) AND 
     COUNT(*) = (SELECT COUNT(*) FROM t WHERE name = t2.name) 

Demo here

Problemi correlati