2009-08-07 12 views
5

Jak porównać równość wartości w SQL z wartością null?Jak zrobić porównanie równości w SQL z zachowaniem podobnym do C#?

Dla obeznanych z C#, tutaj są wyniki porównania wartości pustych:

null == null : true 
null == john : false 
null == paul : false 
john == null : false 
john == john : true 
john == paul : false 
paul == null : false 
paul == john : false 
paul == paul : true 

Najprostszym rozwiązaniem znalazłem w SQL jest aby połączyły się zerowalne pola do pewnej wartości wskaźnikowych (np „scoobydoo”), a następnie porównać je

coalesce(A, 'scoobydoo') = coalesce(B, 'scoobydoo') 

Ale to jest zwykły kludge jeśli ktoś używa wartości wskaźnikowych, jeśli a dzieje się NULL i B „scoobydoo”, wówczas wyrażenie powyżej przyniesie prawdziwe

To jest dokładnie mój cel na prosząc o logice powyższym kodzie (T-SQL UPDATE wyzwalania):

-- detect if the value changes 

if (select invoice_date from inserted) <> 
    (select invoice_date from deleted) begin 

    -- do something to summary tables here 

end 

Jak zrobić porównanie równości w SQL z C# -Jak zachowania?

[EDIT: znalazłem odpowiedź here]

Testowany kod (Postgres ładny logiczna wsparcia, FTW!):

select 

    A, B, 

    A = B, 
    A IS NOT DISTINCT FROM B, -- "logically" same as above 

    A <> B, 
    A IS DISTINCT FROM B -- "logically" same as above 

from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 

[EDIT: Testowany kod Jon, jego odpowiedź na rodzaju równości na pół -work (tylko traktować null jako fałszywe i tak), ale jego odpowiedź na nierówności bomb out]

Testowany kod (Postgres ładny logiczna wsparcia, FTW!):

select 

    A, B, 

    A = B, 
    A IS NOT DISTINCT FROM B, -- "logically" same as above 
    coalesce((A = B) or (A is null and B is null), false), 
    -- tested Jon's code for ==, semi-work, coalesced to make it true/false only 


    A <> B, 
    A IS DISTINCT FROM B, -- "logically" same as above 
    (A <> B) and (A is not null or B is not null) 
    -- tested Jon's code for !=, bombs out 

from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 

[EDIT: pisał inny question podobne do tego]

[EDIT: wysłane wyniki na podstawie dochodzenia Jona dniu wolnym od pracy semantyki dla porównania nierówności]

select 

    A, B, 

    A = B, 
    A IS NOT DISTINCT FROM B, -- "logically" same as above 
    (A = B) or (A is null and B is null), 
    -- tested Jon's code for == 


    A <> B, 
    A IS DISTINCT FROM B -- "logically" same as above, 
    (A <> B) and (A is not null or B is not null) 
    -- tested Jon's code for !=, bombs out 

from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 


    a | b | ?column? | ?column? | ?column? | ?column? | ?column? | ?column? 
------+------+----------+----------+----------+----------+----------+---------- 
null | null | null  | t  | t  | null  | f  | f 
null | john | null  | f  | null  | null  | t  | null 
null | paul | null  | f  | null  | null  | t  | null 
john | null | null  | f  | null  | null  | t  | null 
john | john | t  | t  | t  | f  | f  | f 
john | paul | f  | f  | f  | t  | t  | t 
paul | null | null  | f  | null  | null  | t  | null 
paul | john | f  | f  | f  | t  | t  | t 
paul | paul | t  | t  | t  | f  | f  | f 
(9 rows) 

semantyki wolne od pracy dla nierówność skłoniło mnie aby umieścić kolejną question :-)

[EDIT: Testowany nowy odpowiedź Jona]

select 

    A, B, 

    A = B as e, 
    A IS NOT DISTINCT FROM B AS e_works, -- "logically" same as above 
    (A = B) or (A is null and B is null) AS e_semi_work, -- tested Jon's code for ==, works if we treat null as false 


    A <> B as ie, 
    A IS DISTINCT FROM B as ie_works, -- "logically" same as above, 
    (A <> B) and (A is not null or B is not null) as ie_not_work, -- tested Jon's code for !=, bombs out 

    (A <> B) or ((A is null or B is null) and (A is not null or B is not null)) as ie_semi_works, -- this works(well it is, if you treat null as false), 

    not ((A = B) or (A is null and B is null)) as ie_not_work2 -- this doesn't work 


from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 

Wyniki:

a | b | e | e_works | e_semi_work | ie | ie_works | ie_not_work | ie_semi_works | ie_not_work2 
------+------+------+---------+-------------+------+----------+-------------+---------------+-------------- 
null | null | null | t  | t   | null | f  | f   | null   | f 
null | john | null | f  | null  | null | t  | null  | t    | null 
null | paul | null | f  | null  | null | t  | null  | t    | null 
john | null | null | f  | null  | null | t  | null  | t    | null 
john | john | t | t  | t   | f | f  | f   | f    | f 
john | paul | f | f  | f   | t | t  | t   | t    | t 
paul | null | null | f  | null  | null | t  | null  | t    | null 
paul | john | f | f  | f   | t | t  | t   | t    | t 
paul | paul | t | t  | t   | f | f  | f   | f    | f 
(9 rows) 
+0

s/usuń/usuń/w ostatniej próbce. Podaj wartości początkowe dla Paula i Johna jawnie? –

+1

Dup of http://stackoverflow.com/questions/680824/sql-equality-inequality-comparison-with-ululble-values ​​ –

+0

Jeśli jest to T-SQL, czy jest to na pewno duplikat pytania PostgreS? Czy ta sama odpowiedź zadziała? –

Odpowiedz

5

Edytuj ponownie ... koalescencyjny wynik powinien działać i robi rzeczy nieco prostsze:

równości:

where COALESCE((A = B) or (A is null and B is null), false) 

Zgadzam to nie jest strasznie przyjemne .

EDYCJA: Vilx wskazał problem z A <> B.Myślę, że to będzie działać, choć:

where (A <> B) or ((A is null or B is null) and 
        (A is not null or B is not null)) 

To może być prostsze do wykonania tej jednak:

where !(COALESCE((A = B) or (A is null and B is null)), false) 
+0

+1 za dostarczenie semantyka IS IS DISTINCT OD – Hao

+1

Umm ... wybacz mi, jeśli się mylę, ale czy druga nie zawiodłaby, gdyby A byłaby NULL, a B nie byłaby? –

+0

@Vilx: Z czego się martwisz? 'A <> B' będzie prawdziwe, a' (A nie jest puste lub B nie jest puste) 'będzie prawdziwe, ponieważ B nie ma wartości null - więc ogólny wynik jest prawdziwy, zgodnie z potrzebami. –

3

Jeśli to Microsoft SQL Server, a następnie szukasz opcji ANSI_NULLS. Jeśli jest to kolejny DBMS, będziesz musiał przeczytać dokumentację dla niego. Niektóre z nich wcale tego nie wspierają.

Dodano: Och, zauważyłem, że wspomniałeś o T-SQL. To jest MSSQL wtedy! :)

+0

Podoba mi się ! Wiem, że to nie jest * standard *, ale cholera! Dzięki. – Kieron

+1

Teoretycznie może to być także Sybase. –

+0

Umm, OK, tego nie wiedziałem. :) –