SQLサーバーでは、where句にnullParam=NULL
がある場合、常にfalseと評価されます。これは直感に反し、多くのエラーを引き起こしました。 IS NULL
およびIS NOT NULL
キーワードが正しい方法であると理解しています。しかし、なぜSQLサーバーはこのように動作しますか?
その場合、nullは「不明」(または「存在しない」)と考えてください。どちらの場合も、どちらの価値もわからないため、等しいとは言えません。したがって、null = nullはtrueではない(システムによってはfalseまたはnull)と評価されます。これは、値が等しいことを示す値がわからないためです。この動作は、ANSI SQL-92標準で定義されています。
編集:これは ansi_nulls 設定に依存します。 ANSI_NULLSがオフの場合、これはtrueと評価されます。例として次のコードを実行します...
set ansi_nulls off
if null = null
print 'true'
else
print 'false'
set ansi_nulls ON
if null = null
print 'true'
else
print 'false'
フランクは何歳ですか?わかりません(null)。
シャーリーは何歳ですか?わかりません(null)。
フランクとシャーリーは同じ年齢ですか?
正解は、「いいえ」ではなく「わからない」(null)である必要があります。フランクとシャーリーmightは同じ年齢であるため、単純にわかりません。
ここで、私の立場を明確にしたいと思います。
NULL = NULL
がFALSE
に評価されるのは間違っています。ハッカーとミスターはNULL
と正しく答えました。その理由は次のとおりです。 Dewayne Christensenが Scott Ivey へのコメントで私に書いた:
12月なので、季節的な例を使用してみましょう。ツリーの下に2つのプレゼントがあります。今、あなたは私が同じものを2つ手に入れたかどうかを教えてくれます。
それらは異なる場合もあれば、等しい場合もありますあなたは知らない両方のプレゼントを開くまで。知るか?あなたはお互いを知らない2人を招待しましたが、両方とも同じ贈り物をしました-まれですが、不可能ではありません§。
質問:これら2つのUNKNOWNは同じ(等しい、=)を提示していますか?正解はUNKNOWN(つまりNULL
)です。
この例はデモンストレーションを目的としています「..(false
またはnull
、システムに応じて)..」は正しい答えです-そうではありませんonlyNULL
は3VLで正しい(または間違った答えを返すシステムを受け入れても大丈夫ですか?)
この質問に対する正しい答えは、この2つの点を強調する必要があります。
繰り返しになりますが、SQLは、平等の再帰的特性を解釈するように強制するのは適切ではありません。
for any x, x = x
§§(平易な英語:言説の宇宙が何であれ、「もの」は常にそれ自身に等しい)。
.. 3VLで(TRUE
、FALSE
、NULL
)。人々の期待は、2VL(TRUE
、FALSE
、SQLでも他のすべての値に有効)に準拠します。つまり、x = x
常に評価TRUE
、可能なxの値-例外なし。
NULLは有効な「non-values」(謝罪者がふりをする)であり、これは関係変数の一部として属性値(??)として割り当てることができることに注意してください。したがって、論理式のタイプだけでなく、すべてのタイプ(ドメイン)の許容値です。
そして、これは私のポイントでした:NULL
は、値として「奇妙な獣」です。 up曲表現なしで、私は言うことを好む:ナンセンス。
この定式化は、はるかに明確で議論の余地が少ないと思います-私の英語力の低さを申し訳ありません。
これは、NULLの問題のoneのみです。可能であれば、それらを完全に回避することをお勧めします。
§心配しているvaluesここでは、2つのプレゼントがalwaysであるという事実は、有効な異議;納得できない場合、申し訳ありませんが、これは値と「オブジェクト」セマンティクスの違いを説明する場所ではありません(リレーショナル代数には最初から値セマンティクスがあります-Coddの情報原則を参照してください。SQLDBMSの実装者の中には、 '共通のセマンティクスさえ気にしない)。
§§私の知る限り、これは古代から受け入れられている公理である(形式や別の形式であるが、常に2VLで解釈される)exactlyとても直感的だから。 3VL(実際にはロジックのファミリー)は、はるかに最近の開発です(しかし、いつ最初に開発されたかはわかりません)。
サイドノート:誰かが紹介する場合 下 、 ユニット 、および オプション SQL NULLを正当化する試みとしてタイプします。 NULLを使用したSQL実装の健全な型システムを示し、最後にNULL(これらの「値ではなく値」)が実際にどのようなものであるかを明らかにする非常に詳細な調査の後にのみ確信してください。
以下では、著者を引用します。 すべてのエラーまたは省略は、おそらく私のものであり、元の著者のものではありません。
SQL NULLのジョーセルコ
Joe Celkoがこのフォーラムでよく引用されているのを見ます。どうやら彼はここで非常に尊敬される著者です。だから、私は自分に言った:「彼はSQL NULLについて何を書いたのか?彼はどのようにNULLの多くの問題を説明したのか?」私の友人の1人が電子書籍版のJoe CelkoのSQL for smarties:Advanced SQL programming、3rd editionを持っています。どれどれ。
まず、目次。私を最も驚かせるのは、NULLが言及されている回数と、さまざまなコンテキストでのことです。
3.4算術演算とNULL 109
3.5値のNULLとの間の変換110
3.5.1 NULLIF()関数110
6 NULL:SQL 185にデータがありません
6.4 NULLの比較190
6.5 NULLおよびロジック190
6.5.1サブクエリ述語のNULL 191
6.5.2標準SQLソリューション193
6.6数学とNULL 193
6.7関数とNULL 193
6.8 NULLおよびホスト言語194
6.9 NULLの設計アドバイス195
6.9.1ホストプログラムからのNULLの回避197
6.10複数のNULL値に関する注意198
10.1 IS NULL述語241
10.1.1 NULLのソース242
...
等々。それは私にとって「厄介な特別なケース」です。
著作権上の理由から、私はこの本からの抜粋でこれらのケースのいくつかに入り、自分自身を本質的なものに制限しようとします。これらの引用は「公正使用」doctrineに収まり、本を買うように刺激することさえできると思う-だから誰も文句を言わないことを願う(そうでなければ、全部ではないにしても、ほとんどを削除する必要がある) 。さらに、同じ理由でコードスニペットを報告することは控えます。ごめんなさい本を購入して、詳細な推論について読んでください。
続く括弧内のページ番号。
NOT NULL制約(11)
最も重要な列制約はNOT NULLです。これは、列でのNULLの使用を禁止します。この制約は定期的に使用し、正当な理由がある場合にのみ削除してください。データに対してクエリを実行するときにNULL値の複雑さを回避するのに役立ちます。
値ではありません;値が入る可能性のある場所を保持するマーカーです。
繰り返しますが、この「価値はありますが、まったく価値がない」というナンセンスです。残りは私にとって非常に賢明なようです。
(12)
要するに、NULLはSQLで多くの不規則な機能を引き起こします。これについては後で説明します。最善の策は、回避できない場合にNULLの状況とルールを記憶することです。
SQL、NULL、および無限の適切:
(104)第3章:SQLの数値データ
SQLは、いくつかの理由で数学のIEEEモデルを受け入れていません。
...
数学のIEEE規則がSQLで許可されている場合、無限の型変換規則と、変換後に無限の正確な数値を表す方法が必要になります。 NULLには十分な問題があるため、そこに行かないようにしましょう。
特定のコンテキストで実際にNULLが何を意味するかについてのSQL実装は未定です。
3.6.2指数関数(116)
問題は、(x <= 0)の場合に対数が未定義になることです。 一部のSQL実装はエラーメッセージを返し、一部はNULLおよびDB2/400を返します。バージョン3リリース1は、結果として* NEGINF(「負の無限大」の略)を返しました。
ジョー・セルコがデビッド・マクゴバンとC・J・デートを引用:
6 NULL:SQLの欠落データ(185)
David McGoveranとCJ Dateは、本A Guide to Sybase and SQL Serverで次のように述べています。「少なくとも現在SQLで定義および実装されているNULLよりも、この作家の意見です。価値があり、避けるべきよりもはるかに多くのトラブル。それらは非常に奇妙で一貫性のない動作を示し、エラーと混乱の豊富な原因になります。 (これらのコメントと批判は、SQL Serverだけでなく、SQLスタイルのNULLをサポートするすべてのシステムに適用されることに注意してください。)
薬物中毒としてのNULL:
(186/187)
この本の残りの部分では、それらを使用しないように促します、これは矛盾しているように見えるかもしれませんが、そうではありません。 NULLをドラッグと考えてください。それを適切に使用し、それはあなたのために働くが、それを濫用し、それはすべてを台無しにすることができる。 できる限りNULLを避け、必要なときに適切に使用することが最善のポリシーです。
ここでの私の唯一の異議は、「適切に使用する」ことです。これは、特定の実装動作と相互作用します。
6.5.1サブクエリ述語のNULL(191/192)
サブクエリはしばしばNULLとの比較を隠すことを人々は忘れています。次の2つのテーブルを検討してください。
...
結果は空になります。これはcounterintuitiveですが、正しいです。
(セパレーター)
6.5.2標準SQLソリューション(193)
SQL-92は、次の形式の新しい述語を追加することにより、3VL(3値論理)の問題のいくつかを解決しました。
<検索条件> IS [NOT] TRUE | FALSE |未知の
しかし、UNKNOWNはそれ自体が問題の原因であるため、C。J. Dateは、以下に引用した彼の著書で、章4.5を推奨しています。 SQLでのヌルの回避:
- どのようなコンテキストでもキーワードUNKNOWNを使用しないでください。
UNKNOWNで "ASIDE" を読み、以下もリンクします。
6.8 NULLとホスト言語(194)
ただし、NULLをホストプログラムに渡す必要がある場合のNULLの処理方法を知っておく必要があります。埋め込みが定義されている標準のホスト言語はNULLをサポートしていません。これは、データベーススキーマでNULLを使用することを避けるもう1つの理由です。
(セパレーター)
6.9 NULLの設計アドバイス(195)
可能な限り、すべての列でNOT NULL制約を使用してすべてのベーステーブルを宣言することをお勧めします。 NULLはSQLを知らない人を混乱させ、NULLは高価です。
異論:NULLは、SQLをよく知っている人でさえ混乱させます。以下を参照してください。
(195)
NULLは、外部キーでは避ける必要があります。 SQLはこの「疑いの恩恵」関係を許可しますが、結合を含むクエリで情報が失われる可能性があります。たとえば、OrdersテーブルによってFOREIGN KEYとして参照されるInventoryの部品番号コードを指定すると、NULLを持つ部品のリストを取得する際に問題が発生します。これは必須の関係です。存在しない部品は注文できません。
(セパレーター)
6.9.1ホストプログラムからのNULLの回避(197)
何らかのプログラミング規則を使用して、ホストプログラムからデータベースにNULLを入れないようにすることができます。
...
- 不足しているデータがプログラミングとレポートに与える影響を判断します。集計関数を使用したクエリでは誤解を招く可能性があるため、NULLのある数値列が問題になります。
(セパレーター)
(227)
空のセットのSUM()は常にNULLです。このトリックを使用するときに発生する最も一般的なプログラミングエラーの1つは、複数の行を返す可能性があるクエリを記述することです。あなたがそれについて考えなかったなら、あなたは最後の例を次のように書いたかもしれません:...
(セパレーター)
10.1.1 NULLのソース(242)
NULLが発生する可能性のある場所を覚えておくことが重要です。 これらは列の可能な値以上のものです。空の集合、OUTER JOIN、NULLを含む算術式、およびOLAP演算子の集計関数はすべてNULLを返します。これらの構造は、多くの場合、VIEWの列として表示されます。
(セパレーター)
(301)
IN述語をEXISTS述語に変換しようとすると、NULLに関する別の問題が見つかります。
(セパレーター)
16.3 ALL述語および極値関数(313)
これらの2つの述語がSQLで同じではないことは、最初は直観に反します。
...
ただし、極値関数のルールを覚えておく必要があります。最大値または最小値を返す前に、すべてのNULLを削除します。 ALL述部はNULLをドロップしないため、結果でNULLを取得できます。
(セパレーター)
(315)
ただし、標準の定義はネガティブで表現されているため、NULLは疑問の恩恵を受けます。 ...
ご覧のとおり、UNIQUE制約でNULLを使用しないことをお勧めします。
GROUP BYについて議論する:
NULLはすべて等しいとみなされるとして扱われ、独自のグループを形成します。次に、各グループは、古い結果テーブルを置き換える新しい結果テーブルの単一の行に縮小されます。
つまり、GROUP BY句では、NULL = NULLは3VLのようにNULLに評価されませんが、TRUEに評価されます。
SQL標準はわかりにくいです:
ORDER BYとNULL(329)
NULLのソートキー値がNULL以外の値よりも大きいか小さいとみなされるかどうかは、実装定義ですが、...
...どちらの方法でもそれを行うSQL製品があります。
1999年3月、Chris Farrarが彼の開発者の1人から質問を持ち出しました。それにより、彼は私が理解したと思うSQL標準の一部を調べました。クリスは仕様の一般的な理解と実際の文言の違いを見つけました。
等々。 Celkoで十分だと思います。
C。 J. SQL NULLの日付
C. J.日付はNULLについてより過激です。SQLの期間、NULLは避けてください。実際、彼のSQLおよびリレーショナル理論:正確なSQLコードの書き方の第4章は、タイトルが "NO DUPLICATES、NO NULLS"で、サブチャプター "4.4 What's Wrong's with Nulls?」 および「4.5 SQLでのNullの回避」(リンクをたどる:Googleブックスのおかげで、オンラインでいくつかのページを読むことができます)。
SQL NULLのファビアンパスカル
データベース管理における実用的な問題-思考実践者のためのリファレンスから(オンラインの抜粋はありません、申し訳ありません):
10.3実用的な意味
10.3.1 SQL NULL
... SQLは、3VLに固有の問題に加えて、多くの癖、複雑さ、直観に反する、完全なエラー[10、11]に悩まされています。その中には次のものがあります。
- 集計関数(SUM()、AVG()など)は、NULLを無視します(COUNT()を除く)。
- 行のないテーブルのスカラー式は、0ではなくNULLと誤って評価されます。
- 式 "NULL = NULL"はNULLと評価されますが、実際にはSQLでは無効です。 ORDER BYはNULLを等しいものとして扱います(「通常の」値の前または後にあるものはすべてDBMSベンダーに任されます)。
- 式 "x IS NOT NULL"は、2VLの場合のように、 "NOT(x IS NULL)"と等しくありません。
...
商業的に実装されているすべてのSQLダイアレクトはこの3VLアプローチに従っているため、これらの問題を引き起こすだけでなく、製品によって異なる特殊な実装の問題もありますです。
場合によっては異なりますが、NULL=NULL
はNULL
に評価されると思っていました。これは、オペランドとしてNULLを使用するほとんどの操作と同様です。
2つのことが分からないからといって、それらが等しいという意味ではありません。 NULL
を考えるときに“ NULL”(文字列)を考える場合、PostgresqlのIS DISTINCT FROM
AND IS NOT DISTINCT FROM
のような別の同等性テストがおそらく必要です。
PostgreSQLドキュメント()「比較関数と演算子」 から
式
IS DISTINCT FROM
式式
IS NOT DISTINCT FROM
式NULL以外の入力の場合、
IS DISTINCT FROM
は<>
演算子と同じです。ただし、両方の入力がnullの場合はfalseを返し、一方の入力のみがnullの場合はtrueを返します。同様に、IS NOT DISTINCT FROM
はnull以外の入力の=
と同じですが、両方の入力がnullの場合はtrueを返し、一方の入力のみがnullの場合はfalseを返します。したがって、これらのコンストラクトは、nullが「不明」ではなく通常のデータ値であるかのように効果的に機能します。
technet では、null値の動作方法についての適切な説明があります。
Nullは不明を意味します。
したがって、ブール式
値= null
falseと評価されず、nullと評価されますが、それがwhere句の最終結果である場合、何も返されません。 nullを返すことは考えにくいため、これは実際的な方法です。
次のことを理解することは興味深く、非常に重要です:
クエリ内にある場合
where (value=@param Or @param is null) And id=@anotherParam
そして
それから
「value = @ param」はnullと評価されます
"@ param is null"はtrueと評価されます
"id = @ anotherParam"はtrueと評価されます
したがって、評価される式は
(nullまたはtrue)そしてtrue
ここで、「null Or true」はnullと評価されるため、式全体がnullになり、行は返されないと考えられるかもしれません。
そうではありません。どうして?
「null Or true」はtrueと評価されるため、非常に論理的です。Or演算子で一方のオペランドがtrueの場合、もう一方のオペランドの値に関係なく、演算はtrueを返すためです。したがって、他のオペランドが不明(null)であっても問題ありません。
したがって、最終的にtrue = trueとなり、行が返されます。
注:「null Or true」がtrueに評価されるのと同じ明確なロジックでは、「null And true」はnullに評価されます。
更新:
OK、それを完成させるために、ここにも残りの部分を追加したいと思います。
「null Or false」はnullと評価され、「null And false」はfalseと評価されます。 :)
もちろん、ロジックは以前と同じように自明です。
NULLの概念は、控えめに言っても疑わしいです。 Coddは、リレーショナルモデルとコンテキストのNULLの概念を紹介しました(さらに、1種類以上のNULLを提案しました!)しかし、関係理論はCoddのオリジナルの執筆以来進化してきました。そして、他の人は決してキャッチしませんでした(シータ演算子など)。現代の関係理論(真の関係理論、私は強調する必要があります)NULLは単に存在しません。 The Third Manifestoを参照してください。 http://www.thethirdmanifesto.com/
SQL言語には、後方互換性の問題があります。 NULLがSQLに組み込まれ、私たちはそれで立ち往生しています。おそらく、SQLのNULL
の実装には欠陥があります(SQL Serverの実装は、そのANSI_NULLS
オプションにより事態をさらに複雑にします)。
実表ではNULL可能列の使用を避けることをお勧めします。
誘惑されるべきではないかもしれませんが、SQLでNULL
がどのように機能するかについて、自分自身の修正を主張したかっただけです。
NULL
= NULL
はUNKNOWN
と評価されます。
UNKNOWN
は論理値です。
NULL
はデータ値です。
これは簡単に証明できます。
SELECT NULL = NULL
sQL Serverでエラーを正しく生成します。結果がデータ値である場合、ここで(誤って)いくつかの答えが示唆するように、NULL
が表示されることが予想されます。
論理値UNKNOWN
は、SQL DMLとSQL DDLでそれぞれ異なる方法で処理されます。
SQL DMLでは、UNKNOWN
により、結果セットから行が削除されます。
例えば:
CREATE TABLE MyTable
(
key_col INTEGER NOT NULL UNIQUE,
data_col INTEGER
CHECK (data_col = 55)
);
INSERT INTO MyTable (key_col, data_col)
VALUES (1, NULL);
INSERT
条件はNULL = NULL
に解決されますが、CHECK
はこの行で成功します。これは、SQL-92(「ANSI」)標準で定義されているためです。
11.6テーブル制約の定義
3)
テーブル制約がチェック制約定義の場合、SCをチェック制約定義にすぐに含まれる検索条件とし、Tを対応するテーブル制約記述子に含まれるテーブル名とします。次の場合にのみ、テーブル制約は満たされません。
存在(SELECT * FROM T WHERE NOT(SC))
本当です。
ロジックに従って、注意深く読み直してください。
平易な英語では、上記の新しい行には、UNKNOWN
であり、通過が許可されているという「疑いの利点」が与えられています。
SQL DMLでは、WHERE
句の規則ははるかに簡単です。
検索条件はTの各行に適用されます。where句の結果は、検索条件の結果が真であるTの行のテーブルです。
簡単な英語では、UNKNOWN
と評価される行は結果セットから削除されます。
混乱は、NULLの使用から生じる間接性(抽象化)のレベルから発生します。
「クリスマスツリーの下にあるもの」の類推に戻ると、「不明」は、ボックスAにあるものに関する知識の状態を説明しています。
ボックスAの内容がわからない場合は、「不明」と言いますが、「不明」がボックス内にあるという意味ではありません。箱の中に未知のもの以外のもの、おそらくある種のオブジェクトが入っているか、箱の中に何もない可能性があります。
同様に、ボックスBの内容がわからない場合は、コンテンツに関する知識の状態を「不明」とラベル付けできます。
キッカーは次のとおりです。Box Aに関する知識の状態は、Box Bに関する知識の状態と同じです。 (どちらの場合も、あなたの知識の状態は「不明」または「ボックスに何が入っているかわかりません」)。しかし、ボックスの内容は等しくても等しくなくてもかまいません。
SQLに戻って、理想的には、値が何であるかを知っている場合にのみ値を比較できるようにする必要があります。 残念ながら、知識の欠如を記述するラベルはセル自体に格納されていますなので、値として使用したいと思います。しかし、ボックスAの内容がわからない場合、および/またはボックスBの内容がわからない場合、「ボックスAの内容はボックスBの内容と等しくなります。 (論理的に、「ボックスAの内容がわからない場合、およびボックスBの内容がわからない場合、ボックスAの内容=ボックスBの内容」という意味は偽です。)
イェイ、死んだ馬。
NULLはそれ自体ではなく、何にも等しくありません。 NULLの動作を理解するための私の個人的な解決策は、可能な限りそれを使用しないことです:)。
MSDNには、nullについてのわかりやすい説明 記事 と、生成される3つの状態ロジックがあります。
要するに、SQL92仕様ではNULLが不明として定義されており、次の演算子でNULを使用すると、未開始に対して予期しない結果が生じます。
= operator NULL true false
NULL NULL NULL NULL
true NULL true false
false NULL false true
and op NULL true false
NULL NULL NULL false
true NULL true false
false false false false
or op NULL true false
NULL NULL true NULL
true true true true
false NULL true false
NULL
は「不明な値」を意味し、2つの不明な値を等しくすることはできないためです。
したがって、ロジックにNULL
N°1がNULL
N°2と等しい場合、何らかの方法でそれを伝える必要があります。
SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)
既知の値-1
N°1は-1
N°2と等しい
質問:
1つの未知は別の未知と同等ですか?
(NULL = NULL)
この質問は誰も答えることができないため、ansi_nulls設定に応じてデフォルトでtrueまたはfalseに設定されます。
しかし、質問:
この不明な変数は不明ですか?
この質問はまったく異なり、trueで回答できます。
nullVariable = nullは値を比較しています
nullVariableがnullの場合、変数の状態を比較しています
sQLではnullは不明であるため、2つの未知の値が同じであることは期待できません。
ただし、ANSI_NULLSをOff(デフォルトではOn)に設定すると、その動作を得ることができます。nullには=演算子を使用できます
SET ANSI_NULLS off
if null=null
print 1
else
print 2
set ansi_nulls on
if null=null
print 1
else
print 2
ここでの答えはすべてCSの観点から来ているようですので、開発者の観点から答えを追加したいと思います。
開発者にとって、NULLは非常に便利です。ここでの答えは、NULLは不明を意味すると言うことです。CS理論では、それは本当かもしれません。しかし実際の開発では、少なくとも私の経験では、それは約1%の時間で発生します。他の99%は、値が不明ではないが、存在しないことがわかっている場合に使用されます。
例えば:
Client.LastPurchase
、新しいクライアント用。不明ではありませんが、彼はまだ購入していないことが知られています。
Table per ClassHierarchy マッピングでORMを使用する場合、一部の値は特定のクラスにマッピングされません。
ツリー構造 をマッピングするとき、ルートは通常Parent = NULL
を持ちます。
などなど...
ほとんどの開発者は、ある時点でWHERE value = NULL
を書いたが、結果が得られなかったと確信しており、それがIS NULL
構文について学んだ方法です。この質問とリンクされた質問の投票数を見てください。
SQLデータベースはツールであり、ユーザーが理解しやすい方法で設計する必要があります。
他の素晴らしい答えへの追加:
AND: The result of true and unknown is unknown, false and unknown is false,
while unknown and unknown is unknown.
OR: The result of true or unknown is true, false or unknown is unknown, while unknown or unknown is unknown.
NOT: The result of not unknown is unknown
2つのNULLに対してtrueを返す式を探している場合は、次を使用できます。
SELECT 1
WHERE EXISTS (
SELECT NULL
INTERSECT
SELECT NULL
)
あるテーブルから別のテーブルにデータを複製する場合に役立ちます。