2015-09-15 32 views
5

いくつかのカラムで2つのテーブルの間にFULL OUTER JOINを使用したいが、両方のカラムがnullの場合、ジョインの間に等しいと見なされないため、2つの異なるローが得られる。どうすればNULL列が等しいと見なされるので、結合を書くことができますか?nullカラムのSQL:FULL OUTER JOIN

私は簡単な例を設定している:

create table t1 (
id number(10) NOT NULL, 
field1 varchar2(50), 
field2 varchar2(50), 
CONSTRAINT t1_pk PRIMARY KEY (id) 
); 

create table t2 (
    id number(10) NOT NULL, 
    field1 varchar2(50), 
    field2 varchar2(50), 
    extra_field number(1), 
    CONSTRAINT t2_pk PRIMARY KEY (id) 
); 

insert into t1 values(1, 'test', 'test2'); 
insert into t2 values(1, 'test', 'test2', null); 

insert into t1 values(2, 'test1', 'test1'); 
insert into t2 values(2, 'test1', 'test1', null); 

insert into t1 values(3, 'test0', null); 
insert into t2 values(3, 'test0', null, 1); 

insert into t2 values(4, 'test4', 'test0', 1); 

select * 
from t1 
full outer join t2 using (id, field1, field2); 

結果が得られる:期待enter image description here

結果:enter image description here

SQLFiddle

+0

なぜなら、それぞれのテーブルの主キーなので、ID列を結合しないのはなぜですか? – Sentinel

答えて

1

使用NVL()とNULLを代用するユニークな文字列:

select t1.id,t1.field1,t1.field2,t2.extra_field 
from t1 
full outer join t2 ON 
t1.id=t2.id 
AND NVL(t1.field1,'UID_INSTEAD_OF_NULL')=NVL(t2.field1,'UID_INSTEAD_OF_NULL') 
AND NVL(t1.field2,'UID_INSTEAD_OF_NULL')=NVL(t2.field2,'UID_INSTEAD_OF_NULL') 

SQLFiddle demo

+1

このソリューションは、関数ベースのインデックスが定義されていないかぎり、フィールド1および/またはフィールド2のインデックスの利点を失います。 – Sentinel

0

を結果は、それが簡単に区別することはありません。結合に失敗したことを表すNULLのデータのNULL結合されるデータにNULL値が存在する場合は、通常の結合を使用して結果からそれらの値を除外することをお薦めします。 NVLを使用するとスカラー値にNULLを変換するhttps://technet.microsoft.com/en-us/library/ms190409(v=sql.105).aspx

select * 
from t1, t2 
where t1.id = t2.id and t1.field1 = t2.field1 and t1.field2 = t2.field2; 
0

一つの解決策は次のとおりです。 このリンクを参照してください。

select * 
from t1 
full outer join t2 
    ON NVL(t1.id, 0) = NVL(t2.id, 0) 
    AND NVL(t1.field1, 0) = NVL(t2.field1, 0) 
    AND NVL(t1.field2, 0) = NVL(t2.field2, 0) 
; 
+1

ファンクションベースのインデックスが作成されない限り、すべてのインデックスが失われます – Sentinel

+1

@Sentinelはい、正しいです。 –

0

内部的にはOracle独自のコードは、(さわやかなため、たとえば、マテリアライズド・ビューを)(Sys_Op_Map_NonNullを使用しています)これはあなたの参加になるでしょう:

select * 
from t1 
full outer join t2 on (t1.id       = t2.id and 
         t1.field1      = t2.field2 and 
         Sys_Op_Map_NonNull(t1.field2) = Sys_Op_Map_NonNull(t2.field2)); 

私は、その使用が正式にサポートされているかどうか、あるいは公に文書化し始めているかどうかはわかりません。

+0

非常に興味深いソリューションです。 – bviale

2

NVLはそう何の機能が結合に必要とされない条件

select 
    nvl(t1.id, t2.id) id, 
    nvl(t1.field1, t2.field1) field1, 
    nvl(t1.field2, t2.field2) field2, 
    extra_field 
from t1 
full outer join t2 on t1.id = t2.id AND t1.field1 = t2.field1 AND (t1.field2 = t2.field2 OR (t1.field2 IS NULL AND t2.field2 IS NULL)); 
+1

これは良い解決策です。 – Sentinel

+0

Husqvikの回答がある場所(VALEXが提供する答えに優先)に自分のクエリを更新する必要がありました。しかし、Sentinelsはインデックスの利点を失うことについてコメントしています。私は300行しか持っていなかった。しかしそれは知っていることは良いことです。皆さん、ありがとうございました! – ionescu77

0

この溶液を使用して句の使用を維持するが、ヌル(FIELD2を含むUSING句での列を排除した結果に適用することができます)。代わりに、選択リストでfield2が統合されます。

select id 
    , field1 
    , coalesce(t1.field2,t2.field2) field2 
    , extra_field 
from t1 
full outer join t2 using (id, field1); --field2 removed from using clause. 
関連する問題