NOT EXISTS в Postgresql

Кто-нибудь знает, как выполнить такой запрос в Postgresql?

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

Когда я выполняю такой запрос, postgresql жалуется на "ERROR: Greenplum Database does not yet support that query."

EDIT: И как насчет этого:

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

РЕДАКТИРОВАТЬ:
Я тестировал в postgresql 8.2.15 для 4 ответов, предоставленных @ypercube. Выводы:

1) Первое не работает в этой версии postgresql, как я сказал выше в вопросе. Сообщение об ошибке также можно найти там.

2) Для остальных трех ответов скорость выполнения: (3) LEFT JOIN > (4) ЗА ИСКЛЮЧЕНИЕМ → (2) NOT IN.
В частности, для запросов, имеющих один и тот же синтаксис, (3) LEFT JOIN занимает около 5580 мс, (4) EXCEPT занимает около 13502 мс, а (2) NOT IN занимает более 100000 (на самом деле я не ожидал,).
Есть ли какие-то особые причины для того, чтобы предложение NOT IN было настолько медленным?
Cheng

Ответы

Ответ 1

Существует 3 (основных) способа выполнения такого рода запросов:

  • NOT EXISTS коррелированный подзапрос

  • NOT IN Подзапрос

  • LEFT JOIN с IS NULL проверить:

Вы обнаружили, что первый способ работает в Greenplum. @Marco и @juergen предоставили второй путь. Здесь третий, он может обойти ограничения Greenplum:

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

Этот (4-й путь) также работает в Postgres (который поддерживает оператор EXCEPT):

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

Протестировано в SQL-Fiddle (все 4 работы в Postgres).

Ответ 2

Часть ошибки, которую вы оставили вне, могла бы указать вам в правильном направлении. Я думаю, он сказал: "ДЕТАЛИ: запрос содержит коррелированный подзапрос". Поэтому вы должны переписать их с помощью соединений или некоррелированных подзапросов.

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

Что касается второго запроса, попробуйте

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

Ответ 3

SELECT * FROM tabA 
WHERE id not in  (SELECT id FROM tabB)