7

SQL サーバーで単純なブール代数を取得できません。msdn によると、次のステートメントは "1" を返すはずですが、私のサーバーでは "0" を返します。手伝って頂けますか?

SET ANSI_NULLS ON
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END

msdnをご覧ください。そこでは、「NULL を NULL 以外の値と比較すると、常に FALSE になります」と明確に述べられています。- ANSI_NULLS 設定が何であれ。したがって、"1=NULL" は FALSE で、NOT(FALSE) は TRUE である必要があり、ステートメントは "1" を返す必要があります。

しかし、私のマシンでは、「0」が返されます!

1つの説明は、「1 = NULL」が「UNKNOWN」と評価されるということです。NOT(UNKNOWN) はまだ UNKNOWN ( msdn ) であり、CASE ステートメントを ELSE に強制します。

しかし、equals-operator の公式ドキュメントは間違っているでしょう。それは信じられないよ!

誰でもこの動作を説明できますか?

助けてくれてありがとう!

編集 (2012-03-15):

私が見つけた 1 つのことは、あなたの一部にとって興味深いかもしれません:

CREATE TABLE #FooTest (Value INT)
ALTER TABLE #FooTest WITH CHECK ADD CONSTRAINT ccFooTestValue CHECK (Value>1)
PRINT '(NULL>1) = ' + CASE WHEN NULL>1 THEN 'True' ELSE 'False' END
INSERT INTO #FooTest (Value) VALUES (NULL)

print-Statement は「False」を書き込みますが、挿入はエラーなしで実行されます。SQL-Server は、制約チェックを満たさない行を検索するためにチェック制約を無効にしているようです。

IF EXISTS (SELECT * FROM inserted WHERE NOT(Value>NULL)) <Generate error>

check-constraint は UNKNOWN と評価されるため、否定も UNKNOWN であり、SqlServer は check-constraint に違反する行を検出しません。

4

7 に答える 7

6

はい、そのリンクは間違っています。Microsoft Connectでドキュメンテーション バグを報告します。

SQL は、ブール論理ではなく、3 つの値を持つ論理を使用します。truefalse、およびunknown

ほとんどの比較演算子 (つまり、 を除くIS [NOT] NULL) を含むNULL結果は、unknownnotTrueまたはになりFalseます。ここに示す真理値表に従って、unknown を否定すると、unknown が生成されます。

于 2012-03-14T17:57:40.620 に答える
5

リンク先の Equals の MSDN ページは、間違いなく間違っているように見えます。

MSDN ページでSET ANSI_NULLSを確認してください。

SET ANSI_NULLS が ON の場合、NULL 値に対するすべての比較は UNKNOWN と評価されます。

この例の SQL ステートメントを期待どおりに動作させるには、等号演算子 (=) を使用する代わりに、「IS NULL」または「IS NOT NULL」を使用して比較を使用する必要があります。例えば:

SELECT CASE WHEN NOT(1 IS NULL) THEN 1 ELSE 0 END

また

SELECT CASE WHEN (1 IS NOT NULL) THEN 1 ELSE 0 END

于 2012-03-14T18:01:27.763 に答える
2

のドキュメントANSI_NULLSを読みたいとします。SQL は実際には、ブール論理ではなく 3 値論理を実装しており、比較演算の結果が真、偽、または未定義になる可能性があります。基本的に、これはあなたが提供した説明が正しいことを意味します。

これは、次のクエリで実証できます。

SET ANSI_NULLS ON
SELECT CASE
  WHEN (1=NULL) THEN 0
  WHEN NOT(1=NULL) THEN 1    
  ELSE -1
END

-1私のマシン(SQL Server 2005 Enterprise)で結果が得られます。最初の行を変更すると、期待どおりにSET ANSI_NULLS OFF生成1されます。

では、公式ドキュメントは間違っていますか?私はそれがやや誤解を招くと思います。結果がFALSEになると書かれています。明らかにこれは間違っています。ドキュメントが言おうとしていたのは、null 以外を NULL と比較すると、値も に依存する不一致が常に発生するということですANSI_NULLS

もちろん、SQL Server 2012ではANSI_NULLS設定が削除されているため、どのように設定しても結果は変わりません。

于 2012-03-14T18:00:42.330 に答える
2

それはブール論理ではなく、その 3 項論理です: {True, False, I Don't Know.} 次のように分解します。

IF 1=NULL
    print 'True'
else
    print 'False'

equals 、別名「not True」でFalseあるため生成します1=NULLNULL

IF not(1=NULL)
    print 'True'
else
    print 'False'

equals equals 、別名「not True」でFalseあるため、生成されます。これにより、not(1=NULL)not(NULL)NULL

SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END

上記と同じです

SELECT CASE WHEN NULL THEN 1 ELSE 0 END

これNULLは真ではないため、ELSE節に解決されます。

要するに、私に関する限り、ドキュメントは正しくありません。悲惨ですが、ユニークではなく、まったく驚くべきことではありません。

于 2012-03-14T18:08:32.567 に答える
0

サブクエリでEXISTSを使用してみてください。これは 2 つの値を持つロジックを使用し、探している true/false を返します。

于 2012-03-14T18:05:55.490 に答える
0

BOL から ( Thomasへのクレジット):

SET ANSI_NULLS ON は、比較のオペランドの 1 つが NULL の変数またはリテラル NULL である場合にのみ比較に影響します。比較の両側が列または複合式である場合、設定は比較に影響しません。

NOTしたがって、操作は不明なものをチェックしていると思い1=NULLます。これは変数またはリテラル NULL ではないため、仮定したように比較の ELSE 部分を取得します。

于 2012-03-14T18:17:27.970 に答える
0

1=NULL は、ANSI_NULLS が OFF の場合にのみ FALSE を返すようです。それ以外の場合は不定です。その点を明確にするために、おそらく msdn ページを編集する必要があります。

SET ANSI_NULLS OFF
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns true
go

SET ANSI_NULLS ON
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
go
于 2012-03-14T18:29:14.830 に答える