私の制御が及ばない理由で、2つのテーブルを結合する必要があり、一致させるにはnull値が必要です。私が考えることができる最高のオプションは、UUIDを吐き出してそれを私の比較値として使用することでしたが、それは醜いようです
SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL,'f44087d5935dccbda23f71f3e9beb491') =
nvl(T2.SOMECOL,'f44087d5935dccbda23f71f3e9beb491')
どうすればもっとうまくできますか?これは、問題がある場合はOracleにあり、コンテキストは、ユーザーがアップロードしたデータのバッチを既存のデータのバッチと比較して、一致する行があるかどうかを確認する必要があるアプリケーションです。振り返ってみると、どちらのデータセットの結合列にもnullが含まれないようにする必要がありましたが、実際にはそれを行わずに済むようにしました。
編集:明確にするために、私はonlyではありません。列がnullでない場合、実際の値と一致させる必要があります。
多分これはうまくいくかもしれませんが、私は実際に試したことはありません:
SELECT *
FROM T1 JOIN T2
ON T1.SOMECOL = T2.SOMECOL OR (T1.SOMECOL IS NULL AND T2.SOMECOL IS NULL)
SQL Serverでは、次のように使用しました。
WHERE (a.col = b.col OR COALESCE(a.col, b.col) IS NULL)
ORのせいで明らかに効率的ではありませんが、予約された値がない限り、曖昧さや折りたたみなしで両側にNULLをマッピングできます。これは、できる限りの最善の方法です(ある場合、デザインでNULLが許可されていたのはなぜですか。) 。)
この種のタスクでは、Oracleはドキュメント化されていない関数sys_op_map_nonnull()を内部的に使用し、クエリは次のようになります。
SELECT *
FROM T1 JOIN T2 ON sys_op_map_nonnull(T1.SOMECOL) = sys_op_map_nonnull(T2.SOMECOL)
文書化されていないため、このルートを使用する場合は注意してください。
あなたはこれ以上良いことはできませんが、あなたが持っているJOINは実際の "JOIN"を決して行いません(T1.SOMECOLとT2.SOMECOLの間には相関関係がありません。カラム)。基本的に、これは、NULLに対してJOINを使用して行が一致するかどうかを確認することができないことを意味します。
NULLが別のNULLと等しくなることはありません。未知の値の何かが他の未知の値の何かとどのように等しいことができますか?
単純です。COALESCE
を使用します。これにより、最初のnull以外のパラメーターが返されます。
SELECT * FROM T1 JOIN T2 ON
COALESCE(T1.Field, 'magic string') =
COALESCE(T2.Field, 'magic string')
心配する必要があるのは、「マジックストリング」がどちらのテーブルの結合フィールドの有効な値にも含まれないことです。
値がnullの場合にテーブルを結合できるようにしますか?結合述語で考えられるnull値を単に除外することはできませんか? 2つのテーブルの行がnull値によって関連付けられることを理解するのは難しいと思います。 table1.col_aに100個のnullがあり、table2.col_bに100個のnullがある場合、nullのある行についてのみ10000行が返されます。それは正しくないようです。
しかし、あなたはそれが必要だと言っていました。文字の比較には比較的コストがかかるため、null列を小さな文字列に結合することを提案できますか?さらに、列のデータがテキストになる場合は、nullを整数に結合します。次に、非常に迅速な「比較」が行われ、既存のデータと衝突する可能性は低くなります。
あなたはまだあなたが参加のために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(..)での結合の速度を大幅に改善するはずです。
これを捨てるだけです-空の文字列のように、それらのnullを既知の値に合体させる方法はありますか?テーブルのレイアウトがよくわからないということは、その意味が失われるかどうか確信が持てないということです。つまり、空の文字列は「ユーザーが電話番号の入力を拒否した」ことを表し、NULLは「忘れてしまった」それについて尋ねる」、またはそのような何か?
確率はそれが不可能だと思いますが、可能であれば、比較する既知の値があり、そのように合法的に参加することができます。
なぜそのようなものではないのですか?
SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL、 'null')= nvl(T2.SOMECOL、 'null')
UUIDを使用している理由がわかりません。列に存在しない任意の文字列を使用できます。たとえば、「null」という文字列を使用して、メモリフットプリントを小さくできます。また、nvl
を使用したソリューションは、Eric Petroeljeが提案したor ... is null
を使用したソリューションよりもはるかに高速です。
両方の列に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
@サラス・アヴァナヴ
これは最善の方法ではありません。 TA.COL1が値0を保持し、TB.COL2がNULLの場合、それらのレコードが結合されますが、これは正しくありません。
SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,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)
より優れています。
以下のクエリで使用してみてください。
SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);