2011-09-29 13 views
39

Sto cercando di trovare le righe che si trovano in una tabella ma non un'altra, entrambe le tabelle sono in database differenti e hanno anche nomi di colonne differenti sulla colonna che sto usando per abbinare .Seleziona da una tabella dove non in un altro

Ho una query, codice qui sotto, e penso che probabilmente funziona ma è troppo lento:

SELECT `pm`.`id` 
FROM `R2R`.`partmaster` `pm` 
WHERE NOT EXISTS (
    SELECT * 
    FROM `wpsapi4`.`product_details` `pd` 
    WHERE `pm`.`id` = `pd`.`part_num` 
) 

Quindi la query sta cercando di fare come segue:

selezionare tutti i ID dal database R2R.partmaster che non si trovano nel database wpsapi4.product_details. Le colonne che sto cercando sono partmaster.id & product_details.part_num

+0

Per me esiste/non esiste è il modo migliore in quanto espresso chiaramente vuoi che tu voglia ottenere. Ma sembra essere il modo più lento (su MySQL). Controlla questo: http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/ – DavidEG

risposta

64

Ampliando di Sjoerd anti-join, è anche possibile utilizzare il facile da capire SELECT WHERE X NOT IN (SELECT) modello.

SELECT pm.id FROM r2r.partmaster pm 
WHERE pm.id NOT IN (SELECT pd.part_num FROM wpsapi4.product_details pd) 

noti che è solo bisogno di utilizzare ` backticks sulle parole riservate, i nomi con spazi e tali, non con i nomi di colonna normali.

Su MySQL 5+ questo tipo di query è piuttosto veloce.
Su MySQL 3/4 è lento.

assicurarsi di avere indici sui campi in questione
è necessario avere un indice su pm.id, pd.part_num.

+1

Grazie per la tua risposta, non ha funzionato abbastanza velocemente ma la query è buona, ma non sul mio DB. Ho elaborato un'altra solitaria ma stackOverflow non mi consente di postare fino a 3 ore. – Drahcir

+1

Basti pensare che una query simile come sopra ha richiesto circa 10 minuti su MySQL 5.1.73a. Quando ho aggiornato a MySQL 5.6.22 ci sono voluti circa 456ms. –

+0

Questo funziona per me, la cosa buona è che posso capirlo molto bene, così semplice. –

44

Puoi SINISTRA UNIRE i due tavoli. Se non ci sono righe corrispondenti nella seconda tabella, i valori saranno NULL.

SELECT id FROM partmaster LEFT JOIN product_details ON (...) WHERE product_details.part_num IS NULL 
+4

Questa dovrebbe essere la risposta accettata. In questo caso non vedo il punto di una sotto-selezione:/ –

+2

La sottoselezione è più semplice da comprendere per i neofiti. – Johan

3

Quindi ci sono un sacco di post sul web che mostrano come fare questo, ho trovato 3 modi, come indicato da Johan & Sjoerd. Non sono riuscito a far funzionare nessuna di queste query, ovviamente funzionano bene, il mio database non funziona correttamente e quelle query sono tutte lente.

Così ho elaborato un altro modo che qualcun altro potrebbe trovare utile:

La jist di base di esso è quello di creare una tabella temporanea e riempirlo con tutte le informazioni, quindi rimuovere tutte le righe che sono nell'altra tavolo.

Così ho fatto queste 3 domande, e ha funzionato rapidamente (in un paio di momenti).

CREATE TEMPORARY TABLE 

`database1`.`newRows` 

SELECT 

`t1`.`id` AS `columnID` 

FROM 

`database2`.`table` AS `t1` 

.

CREATE INDEX `columnID` ON `database1`.`newRows`(`columnID`) 

.

DELETE FROM `database1`.`newRows` 

WHERE 

EXISTS(
    SELECT `columnID` FROM `database1`.`product_details` WHERE `columnID`=`database1`.`newRows`.`columnID` 
) 
+0

Funziona velocemente perché si sta solo confrontando il primo prodotto, o non vedo questo giusto ?! – MPaulo

2

Per espandere sulla risposta Johan, se la colonna part_num nel sub-select può contenere valori nulli allora la query si romperà.

Per correggere questo, aggiungere un controllo di nulla ...

SELECT pm.id FROM r2r.partmaster pm 
WHERE pm.id NOT IN 
     (SELECT pd.part_num FROM wpsapi4.product_details pd 
        and pd.part_num is not null) 
  • dispiace ma non potrei aggiungere un commento come non ho il rappresentante!
+1

'non in 'sicuramente può essere sgradevole – Drew

Problemi correlati