Звідси можна зробити висновок, що NOT IN (subquery)не обробляє нулі правильно і слід уникати їх на користь NOT EXISTS. Однак такий висновок може бути передчасним. У наступному сценарії, зарахований до Кріса Дата (Програмування та проектування баз даних, т. 2, № 9, вересень 1989 р.), Саме він NOT INобробляє нулі правильно і не повертає правильний результат, а не NOT EXISTS.
Розглянемо таблицю spдля представлення постачальників ( sno), яким відомо, що постачають деталі ( pno) у кількості ( qty). В даний час таблиця містить такі значення:
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
Зауважте, що кількість є нульовою, тобто, щоб мати можливість фіксувати факт, що постачальник, як відомо, постачає деталі, навіть якщо не відомо, в якій кількості.
Завдання полягає в тому, щоб знайти постачальників, яким відомий номер поставки «P1», але не в кількості 1000.
Для NOT INправильної ідентифікації постачальника "S2" використовується лише наступне :
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND 1000 NOT IN (
SELECT spy.qty
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
);
Однак, поданий нижче запит використовує ту саму загальну структуру, але з результатом, NOT EXISTSале неправильно включає постачальника 'S1' в результаті (тобто для якого кількість є нульовою):
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND NOT EXISTS (
SELECT *
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
AND spy.qty = 1000
);
Так NOT EXISTSце не срібна куля, можливо, вона з’явилася!
Звичайно, джерелом проблеми є наявність нулів, тому «справжнім» рішенням є усунення цих нулів.
Цього можна досягти (серед інших можливих конструкцій) за допомогою двох таблиць:
sp відомі постачальники деталей
spq постачальники, відомі, що постачають деталі у відомих кількостях
зауваживши, що, мабуть, має бути зовнішнє ключове обмеження, де spqпосилання sp.
Потім результат можна отримати за допомогою реляційного оператора "мінус" (який є EXCEPTключовим словом у стандартному SQL), наприклад
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1' ),
( 'S2', 'P1' ),
( 'S3', 'P1' ) )
AS T ( sno, pno )
),
spq AS
( SELECT *
FROM ( VALUES ( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT sno
FROM spq
WHERE pno = 'P1'
EXCEPT
SELECT sno
FROM spq
WHERE pno = 'P1'
AND qty = 1000;
NOT INна серію<> andзмінює смислову поведінку не в цій множині на щось інше?