web-dev-qa-db-ja.com

セットが空のときに「NULL NOT IN」を理解するにはどうすればよいですか?

この質問のSQLはOracle用です。ただし、単にFROM dualは、SQL Server(Oracleと同じ結果を返す)で動作するようにします。

次のSQLがあります。

SELECT 1
FROM dual
WHERE NULL IN (SELECT 1 FROM dual WHERE 1 = 0);

SELECT 1
FROM dual
WHERE NULL NOT IN (SELECT 1 FROM dual WHERE 1 = 0);

空のセットと1をそれぞれ返します。 NULLを他の値に置き換えると、まったく同じ結果が得られます。

SELECT 1
FROM dual
WHERE 33 IN (SELECT 1 FROM dual WHERE 1 = 0);

SELECT 1
FROM dual
WHERE 33 NOT IN (SELECT 1 FROM dual WHERE 1 = 0);

では、NULLと空の結果セットの比較はここでどのように機能しますか?

3
Just a learner

次の2つの条件で何が起こるかを見てみましょう。

WHERE NULL IN (SELECT 1 FROM dual WHERE 1 = 0);

WHERE NULL NOT IN (SELECT 1 FROM dual WHERE 1 = 0);

サブクエリは空のテーブルを生成するので、それらを疑似コードで書くことができます:

WHERE NULL IN (<empty_table>);

WHERE NULL NOT IN (<empty_table>);

したがって、最初の質問では、いくつかの(NULL)値が空のテーブルにあるかどうかを尋ねます。 テーブルが空であるため、そのような条件の結果は、値がnullかどうかに関係なく、常にFALSEになります。

2番目の条件で同じ推論を適用すると、値とは無関係に、常にTRUEになります。

ブール型なので、これらの条件の結果の値がPostgresで簡単に確認できます。 dbfiddle.uk を参照してください。最初の行はf(FALSE)を示し、2番目の行はt(TRUE)を示します。


上記の結果、2つのクエリを実行すると、次のようになります。

SELECT 1
FROM dual
WHERE FALSE ;

空の結果を返す(WHERE条件はFALSEであるため、正しい)
そして

SELECT 1
FROM dual
WHERE TRUE ;

1行を与える(再び正しい)。

5
ypercubeᵀᴹ

これは、SQLに固有の、いわゆる「3値ロジック」の問題です。 TRUEおよびFALSEで機能する他のプログラミング言語とは異なり、SQLにもUNKNOWN(NULL)があります。また、SQLのさまざまな要素がUNKNOWNを処理する方法には一貫性がありません。

ONWHEREおよびHAVINGはすべてUNKNOWNをFALSEと見なします。空の結果セットはSQLによってNULLと見なされます。したがって、NOT INは偽のステートメントを探しており、WHEREはNULLをFALSEとして解釈するため、出力を受け取ります。 2つのNULL値を比較すると、UNKNOWNも返されます。

一方、CHECK制約はNULLをTRUEと見なします。たとえば、売上高が0より大きい場合にCHECK制約を作成すると、NULL> 0はUNKNOWNと評価されますが、ルールは、制約がFALSEと評価されてはならないため、最終的にはTRUEとなるというルールです。 (Lennartのコメントに基づいて編集)。

詳細な説明:

SELECT 1
WHERE NULL IN (SELECT 1 WHERE 1 = 0);

(SQL Server構文)

空のセットを返します。空のデータセットはSQLによってNULLと見なされるため、実際に行っていることは次のとおりです。

SELECT 1
WHERE NULL IN (NullSet/EmptySet);

具体的には、比較対象はすべての行のテーブル= NULLです。

https://www.oreilly.com/library/view/sql-and-relational/9781449319724/ch12s07.html

If a row subquery evaluates to an empty table, that empty table is coerced to a row of all nulls.

あなたはそれの数学の部分も持っています:

http://www.solving-math-problems.com/null-set-empty-set.html

2つのNULLを比較すると、結果は常にUNKNOWNとなり、WHEREステートメントはUNKNOWNをFALSEと見なします。

したがって、最初のコードでは:

SELECT 1
WHERE NULL IN (NullSet/EmptySet);

WHEREステートメントは基本的にNULLがNULLセット内に存在するかどうかをチェックします。NULLの比較はUNKNOWNであり、UNKNOWNはFALSEと見なされるため、結果は得られません。

しかし、ここで:

SELECT 1
WHERE NULL NOT IN (NULL);

あなたは、WHERE NULLがNULLセット内に存在しないと言っています。この場合も、UNKNOWNはFALSEと見なされるため、出力が得られます。

これは、比較した理由も説明します。

SELECT 1
FROM dual
WHERE 33 NOT IN (SELECT 1 FROM dual WHERE 1 = 0);

出力を受け取りました。 33がNULLセット/空セット内の要素にないからです。

0
Chessbrain