MSSQL 2000: теоретический вопрос по NULL (ANSI_NULLS ON)
От: sadomovalex Россия http://sadomovalex.blogspot.com
Дата: 11.12.06 17:12
Оценка: 1 (1)
привет
Есть две связанные таблицы: parent и child. Таблица parent:
parent_id
---------
|      1|
|      2|
|      3|
---------

child:
 id    parent_fk
--------------
|   1|   NULL|
|   2|      1|
|   3|   NULL|
|   4|      3|
--------------

При этом запрос:
SELECT * FROM parent
WHERE parent_id NOT IN (SELECT parent_fk
                        FROM child)

возвращает 0 записей. А запрос
SELECT * FROM parent
WHERE parent_id NOT IN (SELECT parent_fk
                        FROM child
                        WHERE parent_fk IS NOT NULL)

возвращает 1 запись как и нужно (с parent_id = 2). Получается, что в первом случае из-за присутствия NULL в результате подзапроса ниодна запись из внешнего запроса не удовлетворяет условию NOT IN ..., т.е. все записи из parent должны удовлетворять условию IN:
1 IN (NULL, 1, NULL, 3) - true
2 IN (NULL, 1, NULL, 3) - тоже получается true :)
3 IN (NULL, 1, NULL, 3) - true

Вопрос во второй выделенной строке — что за поведение? Отмечу, что тот же запрос с простым IN отрабатывает нормально, т.е. возвращает две записи (parent_id = 1 и parent_id=3):
SELECT * FROM parent
WHERE parent_id IN (SELECT parent_fk
                    FROM child)
"Что не завершено, не сделано вовсе" Гаусс
Re: MSSQL 2000: теоретический вопрос по NULL (ANSI_NULLS ON)
От: noesis  
Дата: 11.12.06 18:35
Оценка:
Здравствуйте, sadomovalex, Вы писали:

S>Вопрос во второй выделенной строке — что за поведение?


Вероятно из:
[msdn]
...Computations involving NULL evaluate to NULL because the result must be UNKNOWN
[/msdn]

но спасибо, что обратили внимание (мое в частности), запросы довольно популярные, можно проворонить.
Хотя (имхо конечно), лучше использовать:
SELECT * FROM parent
WHERE not exists(select parent_id from child where parent_fk = parent_id)
icq 323-145-728
Re: MSSQL 2000: теоретический вопрос по NULL (ANSI_NULLS ON)
От: GreatDrag Украина  
Дата: 11.12.06 18:54
Оценка: 24 (4)
Здравствуйте, sadomovalex, Вы писали:

[...]

Имено эта ситуация подробно рассматривается в книге http://www.ozon.ru/context/detail/id/1952041/
Автор(ы): Джо Селко
Издательство: Лори
Цена: 365р.

Книга "SQL для профессионалов" стала первым изданием, посвященным исключительно сложным технологиям SQL, освоение которых способно сделать читателя экспертом в этой области. В нынешнем обновленном издании автор книги Джо Селко в увлекательной и
на странице 96-97:
SELECT col1 FROM Table2 WHERE col1 NOT IN (SELECT col1 FROM Table1);
определяется как
SELECT col1 FROM Table2 WHERE NOT (col1 IN (SELECT col1 FROM Table1));
Раскрывая предикат IN получим:
SELECT col1 FROM Table2 WHERE NOT (col1 = ANY (SELECT col1 FROM Table1));
Что в свою очередь означает следующее:
SELECT col1 FROM Table2 WHERE NOT ((col1=first_value_in_domain) OR (col1=second_value_in_domain) OR ... OR (col1 = NULL));
Выражение (col1 = NULL) всегда дает в результате UNKNOWN. Раскрывая по правилам Де Моргана дизъюнкции, получаем:
... WHERE ((col1<>first_value_in_domain) AND (col1<>second_value_in_domain) AND ... AND UNKNOWN)
То есть начальный запрос эквиваленен (при наличии NULL-ов в Table1.col1)
SELECT col1 FROM Table2 WHERE UNKNOWN
Этому запросу не удовлетворяет ни одна строка.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.