2015-09-15 45 views
5

我想在幾列上的兩個表之間使用FULL OUTER JOIN,但是當兩列都爲空時,在連接期間它們不會被視爲相等,因此我獲得了兩個不同的行。我如何編寫我的連接,所以空列被認爲是平等的?SQL:空列上的全外連接

我已經建立了一個簡單的例子:獲得

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

這個解決方案失去了field1和/或field2索引的好處,除非定義了基於索引的函數 – Sentinel

0

一種解決方案是使用NVL,並轉換成NULL標量值。

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的答案一樣)。不過,我注意到哨兵評論失去索引優勢。我只有300行。但很高興知道。謝謝你們! – ionescu77

0

此溶液中沒有功能被施加維持利用所使用的子句的,但含有空值所使用的子句中消除了一列(FIELD2 )。相反,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.