2009-08-07 38 views
5

Làm thế nào để so sánh sự bình đẳng của giá trị trong SQL với null?Làm thế nào để so sánh bình đẳng trong SQL với hành vi giống như C#?

Đối với những người quen thuộc với C#, đây là kết quả của việc so sánh giá trị nullable:

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 

Giải pháp đơn giản nhất tôi tìm thấy trong SQL là coalesced các lĩnh vực nullable vào một số giá trị trọng điểm (ví dụ như 'scoobydoo') sau đó so sánh chúng

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

Nhưng đó là đồng bằng kludge nếu ai đó sử dụng giá trị trọng điểm, nếu A xảy ra là NULL và B là 'scoobydoo', sau đó biểu thức trên sẽ mang lại thật

Đây chính là mục đích của tôi về yêu cầu logic của đoạn mã trên (T-SQL UPDATE trigger):

-- detect if the value changes 

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

    -- do something to summary tables here 

end 

Làm thế nào để làm so sánh bình đẳng trong SQL với C# -like hành vi?

[EDIT: Tìm thấy câu trả lời here]

Tested mã (Postgres đẹp boolean hỗ trợ, 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: kiểm tra mã của Jon, câu trả lời của mình trên các loại bình đẳng của bán -Làm (chỉ cần đối xử với null như sai anyway), nhưng câu trả lời của mình vào bất bình đẳng bom ra]

Tested mã (Postgres đẹp hỗ trợ boolean, 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: posted khác question liên quan đến một này]

[EDIT: đăng tải kết quả dựa trên điều tra Jon về ngữ nghĩa không làm việc để so sánh sự bất bình đẳng]

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) 

ngữ nghĩa không làm việc cho bất bình đẳng nhắc tôi để đăng bài khác question :-)

[EDIT: Tested Jon của câu trả lời mới]

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) 

Kết quả:

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/xóa/xóa/trong mẫu cuối cùng. Đưa ra giá trị ban đầu cho paul & john một cách rõ ràng? –

+1

Ngắt của http://stackoverflow.com/questions/680824/sql-equality-inequality-comparison-with-nullable-values ​​ –

+0

Nếu đây là T-SQL, nó chắc chắn là một bản sao của một câu hỏi Postgres? Câu trả lời tương tự có hoạt động không? –

Trả lời

5

Sửa lại ... coalescing kết quả nên làm việc và làm cho mọi thứ đơn giản hơn một chút:

Bình đẳng:

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

Tôi đồng ý nó không phải là khủng khiếp vừa ý .

CHỈNH SỬA: Vilx đã chỉ ra sự cố với A <> B.Tôi nghĩ rằng điều này sẽ làm việc mặc dù:

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

Nó có thể đơn giản hơn để làm mặc dù điều này:

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

+1 để cung cấp dưới ngữ nghĩa-mui xe của IS DISTINCT TỪ – Hao

+1

Umm ... tha thứ cho tôi nếu tôi sai, nhưng sẽ không phải là thứ hai thất bại nếu A sẽ là NULL và B sẽ không được? –

+0

@Vilx: Bạn quan tâm đến điều gì? 'A <> B' sẽ là true, và' (A không phải là null hoặc B không null) 'sẽ là true bởi vì B không phải là null - vì vậy kết quả tổng thể là đúng, như mong muốn. –

3

Nếu đó là Microsoft SQL Server, sau đó bạn đang tìm kiếm các lựa chọn ANSI_NULLS. Nếu đó là một DBMS khác, bạn sẽ phải đọc tài liệu cho nó. Một số người trong số họ không hỗ trợ điều này cả.

Đã thêm: Ồ, tôi nhận thấy bạn đề cập đến T-SQL. Nó MSSQL sau đó! :)

+0

Tôi thích nó ! Tôi biết nó không phải là * tiêu chuẩn *, nhưng chết tiệt! Cảm ơn. – Kieron

+1

Về lý thuyết, nó cũng có thể là Sybase. –

+0

Umm, OK, không biết điều đó. :) –

Các vấn đề liên quan