2012-06-28 7 views
14

Ktoś wie, jak wykonać takie zapytanie w Postgresql?Klauzula NOT EXISTS w Postgresql

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

Kiedy wykonać takie zapytanie, PostgreSQL narzeka "ERROR: Greenplum Database does not yet support that query".

EDIT: I jak o tym jednym:

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

EDIT:
testowałem w PostgreSQL 8.2.15 dla 4 odpowiedzi udzielone przez @ypercube. Wnioski są następujące:

1) Pierwszy nie działa w tej wersji postgresql, jak wspomniałem powyżej w pytaniu. Tam też można znaleźć komunikat o błędzie.

2) Dla pozostałych trzech odpowiedzi prędkość wykonania wynosi: (3) LEWY DOŁĄCZ> (4) Z WYJĄTKIEM >> (2) NIE IN.
W szczególności dla zapytań, które mają tę samą składnię, (3) LEWY POŁĄCZENIE trwa około 5580 ms, (4) WYJĄTEK zajmuje około 13502 ms, a (2) NIE przyjmuje więcej niż 100000 (W rzeczywistości nie czekałem, aż skończy się).
Czy istnieją jakieś szczególne powody, dla których klauzula NOT IN jest tak powolna?
Cheng

+2

PostgreSQL 8.2 jest stary i nie jest już obsługiwany. Nastąpiły poważne zmiany w działaniu zapytań "EXISTS" i "NOT EXISTS". http://www.postgresql.org/support/versioning/ – kgrittn

+0

Jeśli chcesz znaleźć najbardziej efektywne zapytania, myślę, że najpierw musisz sprawdzić indeksy na tabelach.Nie wspomnisz o wielkości tabel, ale 5 sekund dla zapytania oznacza (99%) albo wielkie tabele, albo brak indeksów. Sugeruję dodanie nowego pytania, w tym definicji ('CREATE TABLE') dwóch tabel, zapytań i planów wykonania. –

Odpowiedz

21

Istnieją 3 (główne) sposoby wykonywania tego rodzaju zapytania:

  1. NOT EXISTS skorelowane podzapytanie

  2. NOT IN podzapytanie

  3. LEFT JOIN z IS NULL czeku:

Znaleźliście że pierwszy sposób działa w Greenplum. @Marco i @juergen zapewniły drugi sposób. Oto 3rd jeden, może ominąć ograniczenia Greenplum za:

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

Ta (4 way) działa również w PostgreSQL (który obsługuje EXCEPT operatora):

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

Testowany w SQL-Fiddle (czyli wszystkich 4 pracować w Postgres).

+0

@cheng: Z ciekawości, czy to działa? –

+0

Nie, nie ma. Myślę, że powodem jest filtr "tabB.id IS NULL" zastosowany przed LEWYM DOŁĄCZEM, a nie po LEWYM DOŁĄCZU. – cheng

+0

Jak zaimplementować tę kwerendę za pomocą NOT EXISTS? Czy możesz zaoferować pomoc? – cheng

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

Zaktualizowałem moje pytanie, jak wykonać zaktualizowane zapytanie w postgresql? – cheng

3

Część błędu opuściłeś mogło wskazał w dobrym kierunku. Myślę, że powiedział: "DETAIL: zapytanie zawiera skorelowane podkwerendy." Musisz więc przepisać je za pomocą sprzężeń lub nieskorelowanych podkwerend.

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

Co do drugiego zapytania, spróbuj

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

Dziękuję za odpowiedź tak szybko. Zaktualizowałem moje pytanie. A co z nowym zapytaniem? – cheng

+0

Tak, mówi "zapytanie zawiera skorelowane podkwerendy". Tego rodzaju zapytanie jest bezpośrednio obsługiwane przez mysql. Myślałem, że postgresql również to obsługuje. – cheng

+0

Postgres ma o wiele więcej skomplikowanych rzeczy, ale greenplum nie robi, ponieważ musi zrzucić funkcjonalność ze względu na wydajność. –