2012-06-28 13 views
14

Qualcuno sa come eseguire tale query in Postgresql?Clausola NOT EXISTS in Postgresql

SELECT * 
FROM tabA 
WHERE NOT EXISTS (
    SELECT * 
    FROM tabB 
    WHERE tabB.id = tabA.id 
) 

Quando eseguo tale interrogazione, PostgreSQL si lamenta "ERROR: Greenplum Database does not yet support that query."

EDIT: E che ne dite di questo:

SELECT * 
FROM tabA 
WHERE NOT EXISTS (
    SELECT * 
    FROM tabB WHERE tabB.id = tabA.id AND tabB.id2 = tabA.id2 
) 

EDIT:
ho provato in PostgreSQL 8.2.15 per i 4 risposte fornite dal @ypercube. Le conclusioni sono:

1) Il primo non funziona in questa versione di postgresql, come ho detto sopra nella domanda. Il messaggio di errore può essere trovato anche lì.

2) Per le altre tre risposte, la velocità di esecuzione è: (3) SINISTRA IN SINISTRA> (4) TRANNE >> (2) NON IN.
In particolare, per le query che hanno la stessa sintassi, (3) LEFT JOIN richiede circa 5580 ms, (4) EXCEPT impiega circa 13502ms e (2) NOT IN ne richiede più di 100000 (In effetti non ho aspettato util it finished).
C'è qualche motivo particolare per cui la clausola NOT IN è così lenta?
Cheng

+2

PostgreSQL 8.2 è vecchio e non è più supportato. Ci sono stati importanti cambiamenti nel modo in cui le query "EXISTS" e "NOT EXISTS" funzionano da allora. http://www.postgresql.org/support/versioning/ – kgrittn

+0

Se vuoi trovare la più efficiente delle query, penso che prima devi controllare gli indici che hai sulle tabelle.Non si menziona la dimensione dei tavoli ma 5 secondi per una query significa (99%) o tabelle enormi o mancanza di indici. Suggerisco di aggiungere una nuova domanda, comprese le definizioni ('CREATE TABLE') delle due tabelle, le query e i piani di esecuzione. –

risposta

21

Ci sono 3 (principali) modi per fare questo tipo di query:

  1. NOT EXISTS subquery correlata

  2. NOT IN subquery

  3. LEFT JOIN con IS NULL controllo:

hai trovato che il primo modo funziona in Greenplum. @Marco e @juergen hanno fornito il 2 ° modo. Ecco il terzo uno, si può bypassare le limitazioni di Greenplum:

SELECT tabA.* 
FROM 
    tabA 
    LEFT JOIN 
    tabB 
     ON tabB.id = tabA.id 
     AND tabB.id2 = tabA.id2 
WHERE tabB.id IS NULL ; 

Questo (4 ° andata) funziona anche in Postgres (che supporta EXCEPT dell'operatore):

SELECT a.* 
FROM a 
WHERE id IN 
     (SELECT id 
     FROM a 
     EXCEPT 
     SELECT id 
     FROM b 
    ) ; 

Testato SQL-Fiddle (che tutti i 4 lavori in Postgres).

+0

@cheng: Per curiosità, funziona? –

+0

No, non è così. Penso che il motivo sia il filtro "tabB.id IS NULL" è applicato prima di SINISTRA UNISCI, non dopo LEFT JOIN. – cheng

+0

Come implementare questa query con NOT EXISTS? Puoi offrire qualche aiuto? – cheng

2
SELECT * FROM tabA 
WHERE id not in (SELECT id FROM tabB) 
+0

Ho aggiornato la mia domanda, come eseguire la query aggiornata in postgresql? – cheng

3

La parte dell'errore hai lasciato fuori potrebbe hai puntato nella giusta direzione. Penso che abbia detto "DETTAGLIO: la query contiene una sottoquery correlata". Quindi devi riscriverli con join o subquery non correlate.

SELECT * FROM tabA WHERE id NOT IN (SELECT id FROM tabB); 

quanto riguarda la seconda interrogazione, provare

SELECT * FROM tabA WHERE (id, id2) NOT IN (SELECT id, id2 FROM tabB); 
+0

Grazie per aver risposto così presto. Ho aggiornato la mia domanda. E la nuova query? – cheng

+0

Sì, dice "La query contiene una sottoquery correlata". Questo tipo di query è direttamente supportato da mysql. Pensavo che anche Postgresql lo supporti. – cheng

+0

fa postgres, con cose molto più complesse, ma greenplum non lo fa perché deve rinunciare alla funzionalità per motivi di prestazioni. –