結合でnull値を使用できないのはなぜですか?


13

row_number() over (partition by... を使用してクエリの問題を解決しました。これは、結合でNULL値を持つ列を使用できない理由に関するより一般的な質問です。結合のためにnullをnullと等しくできないのはなぜですか?

回答:


31

結合のためにnullをnullと等しくできないのはなぜですか?

Oracleにそれを行うように指示するだけです。

select *
from one t1 
  join two t2 on coalesce(t1.id, -1) = coalesce(t2.id, -1);

(標準SQLではt1.id is not distinct from t2.id、null-safeの等価演算子を取得するために使用できますが、Oracleはそれをサポートしていません)

ただし、これは、置換値(上記の例では-1)が実際にテーブルに表示されない場合にのみ機能します。そのような数値の「マジック」値を見つけることは可能かもしれませんが、文字値にとっては非常に困難です(特にOracleは空の文字列も処理するためnull

さらに、id列のインデックスは使用されません(ただし、式で関数ベースのインデックスを定義できますcoalesce())。

マジック値なしで、すべてのタイプで機能する別のオプション:

              on t1.id = t2.id or (t1.id is null and t2.id is null)

しかし、本当の質問は次のとおりです。これは理にかなっていますか?

次のサンプルデータを検討してください。

表1

id
----
1
2
(null)
(null)

表2

id
----
1
2
(null)
(null)
(null)

ヌル値の組み合わせのどれを結合で選択する必要がありますか?上記の例では、すべてのnull値のクロスジョインのような結果になります。

T1_ID  | T2_ID 
-------+-------
     1 |      1
     2 |      2
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)

6

またはINTERSECT、等値演算子として2つのnullを互いに一致させることができます。

SELECT
  *
FROM
  t1
  INNER JOIN t2
    ON EXISTS (SELECT t1.ID FROM DUAL INTERSECT SELECT t2.ID FROM DUAL)
;

図については、このDBFiddleデモを参照してください。

もちろん、これはかなり口に見えますが、実際にはBriteSpongeの提案よりもそれほど長くはありません。しかし、もしあなたがしゃれを許せば、コメントの標準的な方法で前述した簡潔さ、つまりIS NOT DISTINCT FROMOracleでまだサポートされていない演算子とは一致しません。


2

完全を期すためSYS_OP_MAP_NONNULLに、12cのドキュメントに記載されているように、nullの値を比較するために関数を安全に使用できることに言及します。これは、Oracleが単にランダムにそれを削除してコードを壊さないことを意味します。

SELECT *
FROM   one t1 
       JOIN two t2
         ON SYS_OP_MAP_NONNULL(t1.id) = SYS_OP_MAP_NONNULL(t2.id)

利点は、「マジック」番号の問題に出くわさないことです。

Oracleドキュメントのリファレンスは、「基本マテリアライズドビュー-マテリアライズドビューのインデックスの選択」にあります。


それで、それは今文書化されていますか?のでAskTomは(2003年に)次のように述べています-それは文書化されていないですので、離れて行くかの機能変更のリスクポーズ 停止がそこに行くと、あなたは次のリリースでは本当に怒っているかもしれない『読んで十分であることを人々は作るべきであると述べました』。唯一の正しい方法は次のとおり where (a = b or (a is null and b is null)) です。期間。それが私の考えです。私は使用を検討しませんsys_op_map_nonnull、カーテンの後ろのその男を無視します。」
ypercubeᵀᴹ

リンクがある場合は、質問に追加してください。12c関数には言及していませんが、Oracleのドキュメントと特定のバージョンを検索するのはかなり困難です。
ypercubeᵀᴹ

2

デコードを使用してnull値を結合できます。

on decode(t1.id, t2.id, 1, 0) = 1

decodenullを等しいものとして扱うため、「マジック」番号なしで機能します。2つの列は同じデータ型である必要があります。

最も読みやすいコードを作成することはできませんが、おそらく、 t1.id = t2.id or (t1.id is null and t2.id is null)


1

結合でnull値を使用できないのはなぜですか?Oracleでは、次の両方がtrueと評価されません。

  • NULL = NULL
  • NULL <> NULL

これが、null値をチェックするIS NULL/ を持っている理由IS NOT NULLです。
これをテストするには、次のようにします。

SELECT * FROM table_name WHERE NULL = NULL

結合はブール条件を評価しており、異なる動作をするようにプログラムしていません。結合条件に大なり記号を入れて、他の条件を追加できます。ブール式として評価するだけです。

一貫性を保つために、結合でnullをnullと等しくすることはできません。比較演算子の通常の動作を無視します。


NULL = anythingNULLSQL標準がそう言うので、結果。行が結合条件を満たしているのは、式が真の場合のみです。
ローレンツアルベ

1
リテラル実装の詳細(常にそうであるとは限らない:一部のDBには、一部またはすべての目的でNULLとNULLを同等にするオプションがあります)には論理的な理由があります:NULLは不明です。NULLとNULLを比較するとき、「この未知のものはこの他の未知のものと等しい」と答えていますが、合理的な答えは「未知」です-もう1つのNULL(比較状況ではfalseにマップされます)。
デビッドスピレット

-4

ほとんどのリレーショナルデータベースのNULL値は、不明と見なされます。すべてのHEXゼロと混同しないでください。何かにnull(不明)が含まれている場合は、比較できません。

Unknown = Known False
Unknown = Unknown False
Unknown >= Known False
Known >= Unknown False

つまり、ブール式のオペランドとしてnullがある場合、else部分は常にtrueになります。

開発者によるnullに対する一般的な嫌悪とは反対に、nullには代わりがあります。不明な場合は、nullを使用します。


6
実際にあなたが持っているすべての例の比較、収率 UNKNOWNではなくFALSE;)
ypercubeᵀᴹ17年

あなたは正しいですが、ブール式の目的はtrueまたはfalseのみを返すことなので、ここで狂わないようにしましょう:)。
十二郎
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.