简体   繁体   English

SQL:空列上的FULL OUTER JOIN

[英]SQL : FULL OUTER JOIN on null columns

I want to use a FULL OUTER JOIN between two tables on several columns, but when both columns are null, they are not considered as equal during the join, so I obtain two different rows. 我想在几个列的两个表之间使用FULL OUTER JOIN ,但是当两个列都为null时,它们在连接期间不被视为相等,因此我获得两个不同的行。 How can I write my join, so null columns are considered as equal ? 如何编写连接,所以null列被认为是相等的?

I have set up a simplified example : 我已经设置了一个简化的例子:

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);

Result obtained : 获得的结果: 在此输入图像描述

Result expected : 结果预期: 在此输入图像描述

SQLFiddle SQLFiddle

Use NVL() and a Unique String to substitute NULL: 使用NVL()和Unique String替换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 SQLFiddle演示

NVL can be applied on the result so no function is needed in the join condition 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));

The results do not make it easy to distinguish a NULL in the data from a NULL that represents a failure to join. 结果不容易区分数据中的NULL和表示连接失败的NULL。 When null values are present in data being joined, it is usually preferable to omit them from the results by using a regular join. 当要连接的数据中存在空值时,通常最好通过使用常规连接从结果中省略它们。 See this link: https://technet.microsoft.com/en-us/library/ms190409(v=sql.105).aspx 请看以下链接: 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;

One solution is to use NVL and convert NULL into a scalar value. 一种解决方案是使用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)
;

Internally Oracle's own code (for refreshing materialised views, for example) makes use of the Sys_Op_Map_NonNull() function for this, which would make your join: 内部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));

I'm not sure that its use is officially supported, or if they have started documenting it publically though. 我不确定它的使用是否得到官方支持,或者他们是否已经开始公开记录它。

This solution maintains the use of the using clause, but eliminates the one column in the using clause containing nulls (field2). 此解决方案维护using子句的使用,但消除了包含空值(field2)的using子句中的一列。 Instead field2 is coalesced in the select list. 而是在选择列表中合并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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM