5

SQLの値の同等性をnullと比較する方法は?

C#に精通している方のために、null許容値を比較した結果を次に示します。

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で見つけた最も簡単な解決策は、null許容フィールドをいくつかの番兵値(例:'scoobydoo')に合体させてから、それらを比較することです。

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

しかし、誰かが番兵の値を使用している場合、それは明白な恨みです。AがたまたまNULLで、Bが'scoobydoo'である場合、上記の式はtrueになります。

これはまさに、上記のコードのロジック(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をfalseとして扱います)が、不平等に関する彼の答えは爆破されます]

コードをテストしました(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)
4

2 に答える 2

5

もう一度編集してください...結果を合体させるとうまくいくはずで、物事が少し簡単になります。

平等:

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)
于 2009-08-07T08:08:36.323 に答える
3

Microsoft SQL Serverの場合は、 ANSI_NULLSオプションを探しています。別のDBMSの場合は、そのドキュメントを読む必要があります。それらのいくつかはこれをまったくサポートしていません。

追加:ああ、T-SQLについて言及していることに気づきました。それではMSSQLです!:)

于 2009-08-07T08:10:33.903 に答える