PostgreSQL 'NOT IN' та підзапит


89

Я намагаюся виконати цей запит:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (select consols.mac from consols)

Але я не отримую результатів. Я перевірив його і знаю, що в синтаксисі щось не так. У MySQL такий запит працює чудово. Я додав рядок, щоб переконатися, що macв consolsтаблиці є такий, якого немає , але все одно він не дає результатів.


4
Чи є consols.macстовпець NULLабо NOT NULL?
Марк Байерс

Відповіді:


167

Використовуючи NOT IN, слід переконатися, що жодне зі значень не має значення NULL:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (
    SELECT mac
    FROM consols
    WHERE mac IS NOT NULL -- add this
)

4
Примітка: WHERE mac IS NOT NULLпункт у підзапиті не потрібен, оскільки In(...)завжди видаляє NULL (і дублікати). Оскільки набір не може містити NULL
wildplasser

7
@wildplasser Я не знаю про це. Це не працювало для мене, поки я не додав IS NOT NULL. Вкладене SELECTповертало кілька NULLS, і це спотикалося IN(SELECT...).
robins35

2
Я був би дуже вдячний за пояснення, чому IS NOT NULLпричини цього працюють.
mbarkhau,

7
Здається, використання NULLв NOT INреченні не працює, оскільки порівняння з NULLне є ні істинним, ні хибним. sqlbadpractices.com/using-not-in-operator-with-null-values
mbarkhau

2
Запит не поверне жодного рядка за відсутності, is not nullякщо підзапит не дає відповідних значень і принаймні одне nullзначення. З розділу 9.22 поточного (версія 10) посібника PostgreSQL: "[...] якщо немає рівних правих значень і принаймні один правий рядок дає нуль, результат конструкції NOT IN буде нульовим, а не істинним . "
Крістофер Льюїс

29

Використовуючи NOT IN, ви також повинні врахувати NOT EXISTS, який мовчки обробляє нульові регістри. Див. Також PostgreSQL Wiki

SELECT mac, creation_date 
FROM logs lo
WHERE logs_type_id=11
AND NOT EXISTS (
  SELECT *
  FROM consols nx
  WHERE nx.mac = lo.mac
  );

3
Також зверніть увагу на величезну втрату продуктивності при використанні NOT EXISTSvs... NOT IN
IcanDivideBy0

1
@ IcanDivideBy0 У більшості випадків вони генерують однаковий план запитів. Ви перевіряли?
wildplasser

1
Також підвищується продуктивність використання NOT IN замість NOT EXISTS, у разі підзапитів. Дивіться wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_NOT_IN
Гербранд

8

Ви також можете скористатися умовою LEFT JOIN та IS NULL:

SELECT 
  mac, 
  creation_date 
FROM 
  logs
    LEFT JOIN consols ON logs.mac = consols.mac
WHERE 
  logs_type_id=11
AND
  consols.mac IS NULL;

Індекс у стовпцях "mac" може покращити продуктивність.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.