2016-09-13 13 views
45

なぜ次の両方がゼロを返しますか?確かに2番目は最初の否定ですか? SQL Server 2008を使用しています。「否定」が否定でないのはいつですか?

DECLARE 
    @a VARCHAR(10) = NULL , 
    @b VARCHAR(10) = 'a' 

SELECT 
    CASE WHEN ((@a IS NULL 
         AND @b IS NULL 
        ) 
        OR @a = @b 
       ) THEN 1 
     ELSE 0 
    END , -- Returns 0 
    CASE WHEN NOT ((@a IS NULL 
         AND @b IS NULL 
        ) 
        OR @a = @b 
       ) THEN 1 
     ELSE 0 
    END -- Also returns 0 
+4

クエリの前に 'set ansi_nulls off;'を置くと、その違いが表示されます。そして、少なくとも一つのオペランドが 'NULL'で' false'である比較から 'NULL'を得ることはありません。 –

+1

@ Luaanの答えは100%正しいです。しかし、 'IS DISTICT FROM'演算子(MySQLでは' <=> ')を探しているかもしれません。 – Owen

答えて

50

否定です。しかし、ANSI NULLを理解する必要があります - NULLの否定もNULLです。そして、NULLは偽の真理値です。

したがって、いずれかの引数がnullの場合、@a = @bの結果はnull(偽)になり、その否定もnull(偽)になります。

ネゲーションを使いたい場合は、NULLを取り除く必要があります。しかし、単に代わりに、比較の結果を逆にする方が簡単かもしれません:常にあなたの1, 00, 1のいずれかを与える

case when (...) then 1 else 0 end, 
case when (...) then 0 else 1 end 

を。

EDIT:jpmc26が指摘したように

、あなたが単一NULLNULLすべてのものを作るという考えを取得しないようにヌルがどのように動作するかのビットを拡張すると便利かもしれません。それらの引数のうちの1つがnullの場合、常にnullを返す演算子はありません。最も明白な例はis nullです。

より広範な例では、T-SQL内の論理演算子はそうのようなOR式の真理値を定義クリーネの代数(または同様のもの)を、使用することが:

| T | U | F 
T | T | T | T 
U | T | U | U 
F | T | U | F 

ANDが類似している、など

他の引数が不明( "null")でも、少なくとも1つの引数が真であれば、結果も真になることがわかります。 F or UUで、not(U)がfalsyである、またUあるので、 - 。またnot(F or U)F or Uがfalsyているにもかかわらず、あなたにfalsy真理値を与える一方でnot(T or U)は、あなたにfalsy真理値を与えることを意味しています

これは、両方の引数がnullの場合に式が動作する理由を説明するために重要です。@a is null and @b is nullはtrueと評価され、true or unknowntrueと評価されます。

+1

2008年以降のSQL Serverのバージョンでは、ANSI Nullをオフにすることはできません。つまり、ストアドプロシージャを再構築すると、これらのバージョンでは「正しい」動作が強制され、誤った動作に依存するレガシーコードがある場合は厄介です。あなたは何度も書き直すことができます。ここでは、悪いansi nullsの良いブログ記事です:http://www.sqlservercentral.com/blogs/sqlstudies/2014/07/28/what-is-ansi_nulls-and-why-will-i-be-glad-最後に去るとき/ – mickeyf

+0

「偽の真実の価値」とはどういう意味ですか? – NoSaidTheCompiler

+0

'@a IS NULLかつ@b IS NULL'がfalseの場合、' NULL'は 'OR'条件の外に伝播しませんか? – jpmc26

4

この値のいずれかがnullの場合は、コードの下にしようとした場合、それは問題

になりますbはそれが正しい結果に

DECLARE 
    @a VARCHAR(10) = NULL , 
    @b VARCHAR(10) = 'a' 

SELECT 
    CASE WHEN ((@a IS NULL 
         AND @b IS NULL 
        ) 
        OR @a = @b 
       ) THEN 1 
     ELSE 0 
    END , -- returns 0 
    CASE WHEN NOT ((@a IS NULL 
         AND @b IS NULL 
        ) 
        OR ISNULL(@a,-1) = ISNULL(@b,-1) 
       ) THEN 1 
     ELSE 0 
    END -- also returns 0 
+2

'ISNULL'を使うと' @a IS NULLと@b IS NULL'チェックが不要になります。これはまた、値が '-1'になることはできないと仮定しています。型が' VARCHAR'のときに '-1'を置くこともできますか? – jpmc26

8

この「奇妙な行動を与える@ A = @の問題ですあなたが遭遇しているのはNULLの値によって引き起こされます。

NOT (Something that returns NULL)の否定は、TRUEではありません。まだNULLです。

E.G.ここで言われて何に加えて

SELECT * FROM <Table> WHERE <Column> = null -- 0 rows 
SELECT * FROM <Table> WHERE NOT (<Column> = null) -- Still 0 rows 

、あなたはオプティマイザが正常値としてNULLを扱い、TRUE\FALSEを返すようにできるようになる

SET ANSI_NULLS OFF 

を使用して、その動作を回避することができます。これはまったくお勧めできませんので、避けてください。

0

NOTは常に否定です。 T-SQLのこの動作の理由は、nullの値がデータベース構成の設定(ansi_nulls)に応じて特別な方法で処理されるためです。この設定に応じて、nullは他の値と同じ方法で扱われるか、または「値が設定されていません」として扱われます。この場合、ヌル値を含むすべての式は無効と見なされます。

はまた、式

(@a IS NULL AND @b IS NULL) 
OR 
@a = @b 

@a又は@bいずれかNULLときNULLある両方の変数は、それがケースに対処しない場合のみを覆っています。その場合、結果はansi_nullsの設定に依存します。onの場合、NULLの場合、@a = @bの結果は常にfalseになります。

ansi_nullsoffの場合、NULLは値として処理され、予期したとおりに動作します。

は、次のようにあなたはすべてのケースをカバーする必要があり、そのような予期しない動作を回避するには:

DECLARE 
    @a VARCHAR(10) = 'a', 
    @b VARCHAR(10) = null 

SELECT 
    CASE 
     WHEN (@a IS NOT null AND @b IS null) THEN 0 
     WHEN (@a IS null AND @b IS NOT null) THEN 0 
     WHEN (@a IS null AND @b IS null) THEN 1 
     WHEN (@[email protected]) THEN 1 
    ELSE 0 
    END 

この例では、すべてのヌルの場合はCASE文で(@[email protected]ケースが確認される前に対処していること、 WHENは表示された順に処理され、条件が一致すると処理は終了し、指定された値が返されます)。 nullは、このスクリプトで言い換えれば

result of query

、:

DECLARE @combinations TABLE (
    a VARCHAR(10),b VARCHAR(10) 
    ) 

INSERT INTO @combinations 
    SELECT 'a', null 
    UNION SELECT null, 'b' 
    UNION SELECT 'a', 'b' 
    UNION SELECT null, null 
    UNION SELECT 'a', 'a' 

SELECT a, b, 
    CASE 
     WHEN (a IS NOT null AND b IS null) THEN 0 
     WHEN (a IS null AND b IS NOT null) THEN 0 
     WHEN (a IS null AND b IS null) THEN 1 
     WHEN (a=b) THEN 1 
    ELSE 0 
    END as result 
from @combinations 
order by result 

それが返されます。


は、このスクリプトを使用することができ、すべての可能な(関連する)の​​組み合わせをテストするには値として扱われるため、a='a'b=null0を返す期待される。両方の変数が等しい場合(または両方ともnull)、1を返します。

関連する問題