Klauzula IN z wartością NULL lub IS NULL

84

Bazą danych jest Postgres

Czy mogę użyć wartości NULL dla klauzuli IN? przykład:

SELECT *
FROM tbl_name
WHERE id_field IN ('value1', 'value2', 'value3', NULL)

Chcę ograniczyć się do tych czterech wartości.

Wypróbowałem powyższą instrukcję i nie działa, cóż, wykonuje, ale nie dodaje rekordów z NULL id_fields.

Próbowałem również dodać warunek LUB, ale to po prostu sprawia, że ​​zapytanie jest uruchamiane i uruchamiane bez końca.

SELECT *
FROM tbl_name
WHERE other_condition = bar
AND another_condition = foo
AND id_field IN ('value1', 'value2', 'value3')
OR id_field IS NULL

Jakieś sugestie?

Phill Pafford
źródło
10
inOświadczenie będzie analizowany identycznie field=val1 or field=val2 or field=val3. Umieszczenie tam wartości zerowej sprowadzi się do tego, field=nullco nie zadziała.
Marc B
1
drugie zapytanie powinno być poprawne. jakie inne rzeczy są w twojej whereklauzuli?
Daniel A. White
@Daniel A. White, zaktualizowany, aby odzwierciedlić zapytanie z większą liczbą warunków
Phill Pafford

Odpowiedzi:

124

inOświadczenie będzie analizowany identycznie field=val1 or field=val2 or field=val3. Umieszczenie tam wartości zerowej sprowadzi się do tego, field=nullco nie zadziała.

( Komentarz przez Marc B )

Zrobiłbym to dla jasności

SELECT *
FROM tbl_name
WHERE 
(id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL)
Daniel A. White
źródło
Ach, to się udało, dzięki! Więc zawijanie pól dodaje oba warunki do klauzuli WHERE? Dla wyjaśnienia
Phill Pafford
1
@Phill - to był problem z kolejnością operacji.
Daniel A. White
20

Twoje zapytanie nie powiodło się z powodu pierwszeństwa operatorów . ANDwiąże się wcześniej OR!
Potrzebujesz pary nawiasów, co nie jest kwestią „jasności”, ale czystą logiczną koniecznością .

SELECT *
FROM   tbl_name
WHERE  other_condition = bar
AND    another_condition = foo
AND   (id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL)

Dodane nawiasy zapobiegają ANDwcześniejszemu wiązaniu OR. Gdyby nie było innych WHEREwarunków (nie AND), nie potrzebowałbyś nawiasów. Przyjęta odpowiedź jest pod tym względem nieco myląca.

Erwin Brandstetter
źródło
15
SELECT *
FROM tbl_name
WHERE coalesce(id_field,'unik_null_value') 
IN ('value1', 'value2', 'value3', 'unik_null_value')

Aby wyeliminować zero z czeku. Biorąc pod uwagę wartość null w id_field, funkcja łączenia zamiast null zwróciłaby „unik_null_value”, a dodając „unik_null_value do listy IN-lista, zapytanie zwróciłoby posty, w których id_field ma wartość 1-3 lub null.

Ove Halseth
źródło
2
Małe wyjaśnienie byłoby pomocne dla przyszłych czytelników. W jaki sposób Twój kod pomaga rozwiązać problem?
showdev
9

Pytanie, na które odpowiedział Daniel, jest całkowicie w porządku. Chciałem zostawić notatkę dotyczącą wartości NULLS. Należy zachować ostrożność przy używaniu operatora NOT IN, gdy kolumna zawiera wartości NULL. Nie otrzymasz żadnych danych wyjściowych, jeśli kolumna zawiera wartości NULL i używasz operatora NOT IN. Oto jak to zostało wyjaśnione tutaj http://www.oraclebin.com/2013/01/beware-of-nulls.html , bardzo dobry artykuł, na który natknąłem się i pomyślałem o udostępnieniu go.

Sushant Butta
źródło
Nie jestem pewien, ilu użytkowników napotkało ten problem, ale miałem dokładnie ten problem z mieszaniem wartości null i operatorem NOT IN i sprawdzałem go przez ostatnie dwie godziny. TO jest sprawca ...
Govind Rai
1
Link nie działa.
Dag Høidahl
1
To coś teraz żyje.
zawsze uczący się
3

Uwaga: Ponieważ w odpowiedzi Sushant Butta ktoś twierdził, że link zewnętrzny jest martwy , opublikowałem tutaj treść jako oddzielną odpowiedź.

Uważaj na NULLS .

Dzisiaj natknąłem się na bardzo dziwne zachowanie zapytania podczas używania IN i NOT INoperatorów. Właściwie chciałem porównać dwie tabele i dowiedzieć się, czy wartość z table bistniała w, table aczy nie, i dowiedzieć się, jak zachowuje się, jeśli kolumna zawiera nullwartości. Dlatego właśnie stworzyłem środowisko do testowania tego zachowania.

Stworzymy tabelę table_a.

SQL> create table table_a ( a number);
Table created.

Stworzymy tabelę table_b.

SQL> create table table_b ( b number);
Table created.

Wstaw niektóre wartości do table_a.

SQL> insert into table_a values (1);
1 row created.

SQL> insert into table_a values (2);
1 row created.

SQL> insert into table_a values (3);
1 row created.

Wstaw niektóre wartości do table_b.

SQL> insert into table_b values(4);
1 row created.

SQL> insert into table_b values(3);
1 row created.

Teraz wykonamy zapytanie, aby sprawdzić istnienie wartości table_a, sprawdzając jej wartość table_bza pomocą INoperatora.

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

Wykonaj poniższe zapytanie, aby sprawdzić, czy nie istnieje.

SQL> select * from table_a where a not in (select * from table_b);
         A
----------
         1
         2

Wynik przyszedł zgodnie z oczekiwaniami. Teraz wstawimy nullwartość do tabeli table_bi zobaczymy, jak zachowują się powyższe dwa zapytania.

SQL> insert into table_b values(null);
1 row created.

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

SQL> select * from table_a where a not in (select * from table_b);

no rows selected

Pierwsze zapytanie zachowało się zgodnie z oczekiwaniami, ale co się stało z drugim zapytaniem? Dlaczego nie otrzymaliśmy żadnych wyników, co powinno się stać? Czy jest jakaś różnica w zapytaniu? Nie .

Zmiana jest w danych tabeli table_b. Wprowadziliśmy nullwartość do tabeli. Ale dlaczego tak się zachowuje? Podzielmy dwa zapytania na "AND"i "OR"operator.

Pierwsze zapytanie:

Pierwsze zapytanie będzie obsługiwane wewnętrznie, mniej więcej w ten sposób. Więc a nullnie spowoduje tutaj problemu, ponieważ moje pierwsze dwa operandy będą obliczane na truelub false. Ale mój trzeci operand a = nullnie będzie obliczany do trueani false. Oceni nulltylko.

select * from table_a whara a = 3 or a = 4 or a = null;

a = 3  is either true or false
a = 4  is either true or false
a = null is null

Drugie zapytanie:

Drugie zapytanie zostanie obsłużone jak poniżej. Ponieważ używamy "AND"operatora i wszystko inne niż truew którymkolwiek z operandów nie da mi żadnego wyniku.

select * from table_a whara a <> 3 and a <> 4 and a <> null;

a <> 3 is either true or false
a <> 4 is either true or false
a <> null is null

Jak więc sobie z tym radzimy? Wszystkie not nullwartości z tabeli wybierzemy table_bużywając NOT INoperatora.

SQL> select * from table_a where a not in (select * from table_b where b is not null);

         A
----------
         1
         2

Dlatego zawsze uważaj na NULLwartości w kolumnie podczas używania NOT INoperatora.

Uważaj na NULL !!

1000111
źródło
Doskonała odpowiedź. Właśnie odkryłem problem w swojej pracy. Bardzo, bardzo dziwne zachowanie Oracle.
oputyk
0

Wiem, że jest późno na odpowiedź, ale może być przydatna dla kogoś innego. Możesz użyć zapytania podrzędnego i przekonwertować wartość null na 0

SELECT *
FROM (SELECT CASE WHEN id_field IS NULL 
                THEN 0 
                ELSE id_field 
            END AS id_field
      FROM tbl_name) AS tbl
WHERE tbl.id_field IN ('value1', 'value2', 'value3', 0)
ch2o
źródło
Jest to podobne do odpowiedzi Ove Halsetha przy użyciu koalescencji.
user890332
0

Nullodnosi się do braku danych. Nulljest formalnie zdefiniowana jako wartość niedostępna, nieprzypisana, nieznana lub niemożliwa do zastosowania (OCA Oracle Database 12c, SQL Fundamentals I Exam Guide, str. 87). Dlatego możesz nie widzieć rekordów z kolumnami zawierającymi wartości null, gdy te kolumny są ograniczone za pomocą klauzul „in” lub „not in”.

Roger Rowe
źródło