2015-05-02 16 views
6

Così ho due tabelle:Selezionare 2 righe dalla tabella 1 (con UNION) se coppia non esiste nella tabella 2

Tabella Uno:

id  | gender | lf 
------------------------- 
abc |  1  | 2 
cde |  2  | 1 
efg |  1  | 2 

tabella duo:

id1 | id2 
------------------------- 
abc | cde 

mio lavoro (finora) interrogazione seleziona esattamente 2 righe dalla tabella Uno:

(SELECT 
    * 
FROM 
    uno 
WHERE gender = 1 
    AND lf = 2 
ORDER BY RAND() 
LIMIT 1) 
UNION 
(SELECT 
    * 
FROM 
    uno 
WHERE gender = 2 
    AND lf = 1 
ORDER BY RAND() 
LIMIT 1) 

che restituisce:

id | gender  | lf 
------------------------- 
abc |  1  | 2 
cde |  2  | 1 

Che cosa ho bisogno (e non ho capito se è fattibile con una query) è quello di restituire 2 ids che non sono accoppiati nella tabella duo.

In questo esempio, la query precedente non deve restituire abc e cde perché sono già in tabella duo (le coppie possibili sono efg e abc, efg e cde poiché non si trovano nella tabella duo).

Grazie!

UPDATE: Con l'aiuto di chiliNUT Sono venuto con questo:

(SELECT 
    id,gender,lf 
FROM 
    uno u1 
WHERE NOT EXISTS 
    /* id1-centric exclusion rule */ 
    /* look at id1 FROM duo, exclude it IF it IS IN uno AND id2 IS also IN uno */ 
    (SELECT 
    d.id1, 
    d.id2, 
    u2.id 
    FROM 
    duo d 
    LEFT JOIN uno u2 /* note the JOIN order, duo on uno */ 
     ON d.id2 = u2.id 
    WHERE d.id1 = u1.id) 
    /* id2-centric exclusion rule */ 
    /* look at id1 FROM duo, exclude it IF it IS IN uno AND id2 IS also IN uno */ 
    AND NOT EXISTS 
    (SELECT 
    d.id1, 
    d.id2, 
    u2.id 
    FROM 
    uno u2 
    LEFT JOIN duo d /* note the JOIN order, uno on duo */ 
     ON d.id1 = u2.id 
    WHERE d.id2 = u1.id) and (gender=1 and lf=2)order by rand() limit 1)UNION(SELECT 
    id,gender,lf 
FROM 
    uno u1 
WHERE NOT EXISTS 
    /* id1-centric exclusion rule */ 
    /* look at id1 FROM duo, exclude it IF it IS IN uno AND id2 IS also IN uno */ 
    (SELECT 
    d.id1, 
    d.id2, 
    u2.id 
    FROM 
    duo d 
    LEFT JOIN uno u2 /* note the JOIN order, duo on uno */ 
     ON d.id2 = u2.id 
    WHERE d.id1 = u1.id) 
    /* id2-centric exclusion rule */ 
    /* look at id1 FROM duo, exclude it IF it IS IN uno AND id2 IS also IN uno */ 
    AND NOT EXISTS 
    (SELECT 
    d.id1, 
    d.id2, 
    u2.id 
    FROM 
    uno u2 
    LEFT JOIN duo d /* note the JOIN order, uno on duo */ 
     ON d.id1 = u2.id 
    WHERE d.id2 = u1.id) and (gender=2 and lf=1) order by rand() limit 1) 

ho dovuto modificato in modo che si presenti con 2 ids (con diverso genere e lf). Questo di sicuro non è ottimizzato e probabilmente bloccherà il mio DB ma è un inizio! Grazie chiliNUT!

+0

@chiliNUT: ri-modificare la parte della query per occupare poche righe ma non 1 parola per riga. –

+0

@RavinderReddy Sto utilizzando le impostazioni di formattazione automatica predefinite dal mio sql gui (sqlyog) – chiliNUT

+0

@RavinderReddy se conosci un insieme "migliore" o più "standard" di regole di formattazione, condividili! Sarei felice di modificare la modifica. Dato che non conosco la convenzione di formattazione a cui ti riferisci, non posso apportare la modifica. Inoltre, sentiti libero di apportare la modifica da solo se sai come potrebbe essere meglio formattato. – chiliNUT

risposta

2

La seguente query selezionerà tutti id s in uno, in cui il id non è un membro di una coppia id1,id2. Esamina ogniin uno, quindi controlla se corrisponde a duo.id1 e, in caso affermativo, controlla se lo duo.id2 associato è anche in uno. Quindi, nell'altra direzione, controlla se il numero id in uno corrisponde a duo.id2 e quindi controlla se lo duo.id1 si trova anch'esso in uno.

SELECT 
    id 
FROM 
    uno u1 
WHERE NOT EXISTS 
    /* id1-centric exclusion rule */ 
    /* look at id1 FROM duo, exclude it if it is in uno AND id2 is also in uno */ 
    (SELECT 
    d.id1, 
    d.id2, 
    u2.id 
    FROM 
    duo d 
    LEFT JOIN uno u2 /* note the JOIN order, duo on uno */ 
     ON d.id2 = u2.id 
    WHERE d.id1 = u1.id) 
    /* id2-centric exclusion rule */ 
    /* look at id2 FROM duo, exclude it id it is in uno AND id1 is also in uno */ 
    AND NOT EXISTS 
    (SELECT 
    d.id1, 
    d.id2, 
    u2.id 
    FROM 
    uno u2 
    LEFT JOIN duo d /* note the JOIN order, uno on duo */ 
     ON d.id1 = u2.id 
    WHERE d.id2 = u1.id) 

|id | 
+---+ 
|efg| 

Se si rimuove la clausola secondo esistenza, restituisce cde, ma non abc. se si rimuove la prima clausola di esistenza, restituisce abc, ma non cde. Quindi entrambi sono necessari.

+0

hm, una lunga, è necessario testarla e tornare indietro 2U. grazie – Theodoros80

+1

sì, la coppia (o in generale, la tupla) che controlla le query può diventare grande. Haha potrebbe esserci una soluzione più compatta, ma questo è quello che mi è venuto in mente :-) – chiliNUT

+0

@ Theodoros80 siete i benvenuti! Anche se la query è un po 'grande, con una buona indicizzazione, potrebbe non essere terribilmente inefficiente. – chiliNUT

Problemi correlati