Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет Abu Antos' ([info]syarzhuk)
@ 2009-02-06 09:55:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Музыка:Лаэртский - Карлица
Entry tags:code, sql

Трохзначная лёгіка наносіць удар у адказ. / Three-valued logic strikes back
Аналітыкі адлавілі багафічу. IN працуе як звычайнае параўнаньне з кожным значэньнем са сьпіса ( x IN(a,b,c) == (x=a OR x=b OR x=c) ), таму калі ў сьпісе значэньняў у IN трапляецца NULL, x=NULL неазначана і рэзультат нечакана пусты. Лечыцца дадаткам IS NOT NULL у падзапыце.

CREATE TABLE #temp(i int, flag bit NOT NULL)
INSERT INTO #temp VALUES(1, 1)
INSERT INTO #temp VALUES(2, 0)
INSERT INTO #temp VALUES(NULL, 0)

--returns 2 and NULL
SELECT i FROM #temp WHERE flag=0

--returns 1
SELECT i FROM #temp WHERE flag=1

--you would expect this to return 1, just like the query before, but it returns nothing!
SELECT i FROM #temp WHERE i not in (SELECT i FROM #temp WHERE flag=0)

--this corrected query returns 1, as it should
SELECT i FROM #temp WHERE i not in (SELECT i FROM #temp WHERE flag=0 AND i IS NOT NULL)


(Добавить комментарий)


[info]sergiej.livejournal.com
2009-02-06 23:10 (ссылка)
Каліб гэта быў оракл, то лепш карыстацца з NVL там дзе дазволенныя null каб прывесьці яго да "параўнальнага" тыпу ды пазбегнуць непеўнасьці.
SELECT i FROM #temp WHERE i not in (SELECT NVL(i, -1) FROM #temp WHERE flag=0)

(прымаючы канвенцыю што null гэта -1 ў інту)

а ўвогуле за "NOT IN" трэба забіваць, яно прыказвае прабегчы ўсю табліцу для кожнага параўнання, IN - толькі да "першага спаткання".

Вось гэтае
SELECT i FROM #temp WHERE i in (SELECT i FROM #temp WHERE flag=1)

на 100% адпавядае
SELECT i FROM #temp WHERE i not in (SELECT i FROM #temp WHERE flag=0 AND i IS NOT NULL)

а працуе нашмат хутчэй

(Ответить) (Ветвь дискуссии)


[info]syarzhuk
2009-02-06 23:19 (ссылка)
Re: NVL -- Ну дык у MSSQL таксама ёсьць нават дзьве функцыі - IsNull і Coalesce

Re: "на 100% адпавядае"
Ну, не зусім, гэта я трывіяльны прыклад даў.
У іх там было так, што маглі быць два запісы - адзін з флагам 1, другі з 0 - з тым жа самым кодам "i", і па бізнэс-лёгіцы менавіта трэба было адфільтраваць усё, што мела хаця-б адзін 0. Канешне, цераз JOINs яно працуе лепей, але араклёідам зь іх (+) гэтага не зразумець :)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]sergiej.livejournal.com
2009-02-10 00:08 (ссылка)
а што перашкаджае писаць JOIN ў оракле :)
як казаў знаёмы DBA, калі я не перераблю твой "not in" ў нармальны запыт - стаюлю ланч, калі перераблю - ставіш ты. Наколькі я ведаю ён ніколі не прайграў...

(Ответить) (Уровень выше)