繁体   English   中英

如何在SQL中使用类似C#的行为进行等式比较?

[英]How to do equality comparison in SQL with C#-like behavior?

如何比较SQL中的值的等价与null?

对于熟悉C#的人,以下是比较可空值的结果:

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

我在SQL中找到的最简单的解决方案是将可空字段合并为一些sentinel值(例如'scoobydoo')然后比较它们

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

但是,如果有人使用sentinel值,那么这就是普通的kludge,如果A恰好是NULL而B是'scoobydoo',那么上面的表达式会产生真值

这正是我要求上面代码逻辑的目的(T-SQL UPDATE触发器):

-- detect if the value changes

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

    -- do something to summary tables here

end

如何在SQL中使用类似C#的行为进行等式比较?

[编辑:在这里找到答案]

测试了代码(Postgres很好的布尔支持,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)

[编辑:测试了Jon的代码,他对平等各种半工作的回答(无论如何只是将null视为假),但他对不平等的回答是炸弹的]

测试了代码(Postgres很好的布尔支持,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)

[编辑:发布了与此相关的另一个问题 ]

[编辑:根据Jon对不平等比较的非工作语义的调查发布结果]

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)

不平等的非工作语义促使我发布另一个问题 :-)

[编辑:测试乔恩的新答案]

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)

结果:

  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)

再次编辑...合并结果应该有效并使事情变得更简单:

平等:

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

我同意这不是非常愉快。

编辑:Vilx指出A <> B的问题。 我认为这会有效:

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

这样做可能更简单:

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

如果是Microsoft SQL Server,那么您正在寻找ANSI_NULLS选项。 如果它是另一个DBMS,您将必须阅读它的文档。 他们中的一些根本不支持这一点。

补充:哦,我注意到你提到了T-SQL。 MSSQL! :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM