dil: (Default)
dil ([personal profile] dil) wrote2010-02-19 05:16 pm

Грабельки SQLные – часть очередная

Выбираем данные из некоторой таблички:

SELECT foo,bar FROM table1 WHERE условия;

Всё отлично, данные выбираются. Но мне нужны не все, а только те, которые не встречаются в другой табличке.Проверяю парочку:

SELECT * FROM table2 WHERE foo='foo1';

Ура, ничего не находится. Значит, они должны появиться в итоговой выборке. Пишем окончательный запрос:

SELECT foo,bar FROM table1 WHERE условия
AND foo NOT IN (SELECT foo FROM table2);

И.. получаем индейскую национальную избу. 0 rows, и всё тут. Данных в table2 совершенно точно нет, но и из table1 они выбираться перестали.

Профессиональные DBA уже, наверное, догадались, в чём дело, но поскольку я не, мне на это понадобилось минут 10..

Оригинал этой записи. Комментировать можно тут или там.

Любые материалы из этого блога запрещается использовать на сайте livejournal.ru в любой форме и любом объёме

[identity profile] pcmag-ru.livejournal.com 2010-02-19 07:19 pm (UTC)(link)
Ну, классика же, "трехзначная" логика в SQL, да...

http://pcmag.ru/solutions/detail.php?ID=31704

[identity profile] dil.livejournal.com 2010-02-20 10:17 am (UTC)(link)
ага, она самая. кто ж знал, что она в NOT IN так вредно срабатывает..

[identity profile] pcmag-ru.livejournal.com 2010-02-21 08:58 pm (UTC)(link)
Оно еще много где, грабельки там разложены вдумчиво и со вкусом, да... ;-)

[identity profile] http://users.livejournal.com/_windwalker_/ 2010-02-19 10:48 pm (UTC)(link)
Лучше уж outer join делать на 2-ю таблицу. Так будет очевиднее что в 1-м варианте было нечто inner join.

PS. Только гадаю

[identity profile] dil.livejournal.com 2010-02-20 10:18 am (UTC)(link)
не лучше. поскольку из неё ничего не выбирается, а она используется только для проверки, то IN/NOT IN будет работать быстрее. По крайней мере, так мне сказали наши DBA

[identity profile] dmarck.livejournal.com 2010-02-20 02:33 pm (UTC)(link)
И каково же правильное/эффективное решение?

[identity profile] dil.livejournal.com 2010-02-20 05:13 pm (UTC)(link)
в данном конкретном случае:
SELECT foo,bar FROM table1 WHERE условия
AND foo NOT IN (SELECT foo FROM table2 WHERE foo IS NOT NULL);

[identity profile] kranov.livejournal.com 2010-02-20 08:19 pm (UTC)(link)
а субд какая? а размер таблицы2 какой?

в общем _windwalker_ прав. Только есть нюанс преджойн и постджойн предикаты. В информиксе надо использовать ansi синтаксис left outer join, синтаксис outer не подойдет (он все предикаты воспринимает как преджойн).

а я бы написал:

SELECT foo,bar FROM table1 WHERE условия
AND not exists (SELECT 1 FROM table2 WHERE table1.foo=foo);

[identity profile] dil.livejournal.com 2010-02-20 10:37 pm (UTC)(link)
информикс. таблица 2 сильно большая, а таблица1 - вообще временная, полученная в результате пары других непростых запросов

[identity profile] kranov.livejournal.com 2010-02-21 07:54 am (UTC)(link)
тогда попробуй not exists, скорее всего select 1 выполнится столько раз сколько строк в остается в (SELECT FROM table1 WHERE условия), причем это будут поиски по индексу, в саму таблицу даже заходить не надо. А в твоем варианте (SELECT foo FROM table2 WHERE foo IS NOT NULL) может выполняться очень долго.

С другой стороны оптимизатор умеет одно превращать в другое. Надо план смотреть.

[identity profile] drug123.livejournal.com 2010-02-20 09:45 pm (UTC)(link)
Ггг, так это же ANSI NULL processing. Сам залип на днях на этом :о)