web-dev-qa-db-ja.com

NULL値に対するSQLの「結合」

私の制御が及ばない理由で、2つのテーブルを結合する必要があり、一致させるにはnull値が必要です。私が考えることができる最高のオプションは、UUIDを吐き出してそれを私の比較値として使用することでしたが、それは醜いようです

SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL,'f44087d5935dccbda23f71f3e9beb491') = 
   nvl(T2.SOMECOL,'f44087d5935dccbda23f71f3e9beb491')

どうすればもっとうまくできますか?これは、問題がある場合はOracleにあり、コンテキストは、ユーザーがアップロードしたデータのバッチを既存のデータのバッチと比較して、一致する行があるかどうかを確認する必要があるアプリケーションです。振り返ってみると、どちらのデータセットの結合列にもnullが含まれないようにする必要がありましたが、実際にはそれを行わずに済むようにしました。

編集:明確にするために、私はonlyではありません。列がnullでない場合、実際の値と一致させる必要があります。

23
Dan

多分これはうまくいくかもしれませんが、私は実際に試したことはありません:

SELECT * 
FROM T1 JOIN T2 
ON T1.SOMECOL = T2.SOMECOL OR (T1.SOMECOL IS NULL AND T2.SOMECOL IS NULL)
43
Eric Petroelje

SQL Serverでは、次のように使用しました。

WHERE (a.col = b.col OR COALESCE(a.col, b.col) IS NULL)

ORのせいで明らかに効率的ではありませんが、予約された値がない限り、曖昧さや折りたたみなしで両側にNULLをマッピングできます。これは、できる限りの最善の方法です(ある場合、デザインでNULLが許可されていたのはなぜですか。) 。)

6
Cade Roux

この種のタスクでは、Oracleはドキュメント化されていない関数sys_op_map_nonnull()を内部的に使用し、クエリは次のようになります。

SELECT *
FROM T1 JOIN T2 ON sys_op_map_nonnull(T1.SOMECOL) = sys_op_map_nonnull(T2.SOMECOL)

文書化されていないため、このルートを使用する場合は注意してください。

3
David Aldridge

あなたはこれ以上良いことはできませんが、あなたが持っているJOINは実際の "JOIN"を決して行いません(T1.SOMECOLとT2.SOMECOLの間には相関関係がありません。カラム)。基本的に、これは、NULLに対してJOINを使用して行が一致するかどうかを確認することができないことを意味します。

NULLが別のNULLと等しくなることはありません。未知の値の何かが他の未知の値の何かとどのように等しいことができますか?

3
Ken White

単純です。COALESCEを使用します。これにより、最初のnull以外のパラメーターが返されます。

SELECT * FROM T1 JOIN T2 ON 
  COALESCE(T1.Field, 'magic string') = 
     COALESCE(T2.Field, 'magic string')

心配する必要があるのは、「マジックストリング」がどちらのテーブルの結合フィールドの有効な値にも含まれないことです。

3
Michael Hays

値がnullの場合にテーブルを結合できるようにしますか?結合述語で考えられるnull値を単に除外することはできませんか? 2つのテーブルの行がnull値によって関連付けられることを理解するのは難しいと思います。 table1.col_aに100個のnullがあり、table2.col_bに100個のnullがある場合、nullのある行についてのみ10000行が返されます。それは正しくないようです。

しかし、あなたはそれが必要だと言っていました。文字の比較には比較的コストがかかるため、null列を小さな文字列に結合することを提案できますか?さらに、列のデータがテキストになる場合は、nullを整数に結合します。次に、非常に迅速な「比較」が行われ、既存のデータと衝突する可能性は低くなります。

1
Josh Smeaton

あなたはまだあなたが参加のためにnvl()を使うことができると信じています:

SELECT *
FROM T1
JOIN T2 ON NVL(T2.COL1,-1)=NVL(T1.COL1,-1);

ただし、列col1に関数ベースのインデックスを追加する必要があります。

CREATE INDEX IND_1 ON T1 (NVL(COL1,-1));
CREATE INDEX IND_2 ON T2 (NVL(COL1,-1));

インデックスは、NVL(..)での結合の速度を大幅に改善するはずです。

0
Cloud

これを捨てるだけです-空の文字列のように、それらのnullを既知の値に合体させる方法はありますか?テーブルのレイアウトがよくわからないということは、その意味が失われるかどうか確信が持てないということです。つまり、空の文字列は「ユーザーが電話番号の入力を拒否した」ことを表し、NULLは「忘れてしまった」それについて尋ねる」、またはそのような何か?

確率はそれが不可能だと思いますが、可能であれば、比較する既知の値があり、そのように合法的に参加することができます。

0
Jim Dagg

なぜそのようなものではないのですか?

SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL、 'null')= nvl(T2.SOMECOL、 'null')

UUIDを使用している理由がわかりません。列に存在しない任意の文字列を使用できます。たとえば、「null」という文字列を使用して、メモリフットプリントを小さくできます。また、nvlを使用したソリューションは、Eric Petroeljeが提案したor ... is nullを使用したソリューションよりもはるかに高速です。

0
Alexis Dufrenoy

両方の列にnullが存在するかどうかを確認するのと同じではありませんか?

SELECT * FROM T1, T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL

または

SELECT * FROM T1 CROSS JOIN T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL
0
Gambler

@サラス・アヴァナヴ

これは最善の方法ではありません。 TA.COL1が値0を保持し、TB.COL2がNULLの場合、それらのレコードが結合されますが、これは正しくありません。

SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);
0

decodeを使用してnull値を結合できます。

_    SELECT * FROM T1 JOIN T2 ON DECODE(T1.SOMECOL, T2.SOMECOL, 1, 0) = 1
_

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

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

0
Tamás Bárász

以下のクエリで使用してみてください。

SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);
0
Sarath Avanavu