SQL : 空列上的 FULL OUTER JOIN
SQL : FULL OUTER JOIN on null columns
我想在两个表的多个列之间使用 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);
获得的结果:
预期结果:
结果不容易区分数据中的 NULL 和表示加入失败的 NULL。当被连接的数据中存在空值时,通常最好使用常规连接从结果中省略它们。
看到这个link: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;
一种解决方案是使用 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)
;
使用 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')
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));
我不确定它的使用是否得到官方支持,或者他们是否已经开始公开记录它。
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));
此解决方案保留了using 子句的使用,但删除了using 子句中包含空值的一列(field2)。相反,field2 合并在 select 列表中。
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.
我想在两个表的多个列之间使用 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);
获得的结果:
预期结果:
结果不容易区分数据中的 NULL 和表示加入失败的 NULL。当被连接的数据中存在空值时,通常最好使用常规连接从结果中省略它们。 看到这个link: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;
一种解决方案是使用 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)
;
使用 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')
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));
我不确定它的使用是否得到官方支持,或者他们是否已经开始公开记录它。
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));
此解决方案保留了using 子句的使用,但删除了using 子句中包含空值的一列(field2)。相反,field2 合并在 select 列表中。
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.