web-dev-qa-db-ja.com

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

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

13
Mark Warner

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

オラクルにそれをするように言ってください:

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セーフな等価演算子を取得しますが、Oracleではサポートされていません)

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

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

魔法の値なしで、すべてのタイプで機能する別のオプション:

              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値の組み合わせを選択する必要がありますか?上記の例では、すべてのnull値のクロス結合のようなものになります。

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

または、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 FROM演算子。Oracleではまだサポートされていません。

6
Andriy M

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

_on decode(t1.id, t2.id, 1, 0) = 1
_

decodeはnullを等しいものとして扱うため、これは「マジック」番号なしで機能します。 2つの列は同じデータ型でなければなりません。

最も読みやすいコードにはなりませんが、おそらくt1.id = t2.id or (t1.id is null and t2.id is null)より優れています。

2
Tamás Bárász

完全を期すために、関数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ドキュメントのリファレンスは Basic Materialized Views-Choosing Indexes for Materialized Views にあります。

2
BriteSponge

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

  • NULL = NULL
  • NULL <> NULL

そのため、IS NULL/IS NOT NULL null値を確認します。
これをテストするために、あなたは単に行うことができます:

SELECT * FROM table_name WHERE NULL = NULL

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

一貫性を保つために、結合ではnullをnullと同じにすることはできないと思います。比較演算子の通常の動作を無視します。

1