【问题标题】:SQL : FULL OUTER JOIN on null columnsSQL:空列上的完全外部连接
【发布时间】:2015-12-11 18:28:51
【问题描述】:

我想在多个列的两个表之间使用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);

获得的结果:

预期结果:

SQLFiddle

【问题讨论】:

  • 为什么不加入 ID 列,因为它们都是各自表的主键?

标签: sql oracle join outer-join


【解决方案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

【讨论】:

  • 除非定义了基于函数的索引,否则此解决方案将失去对 field1 和/或 field2 索引的任何好处
【解决方案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));

【讨论】:

  • 我必须将我的查询更新到带有 Husqvik 答案的地方(与 VALEX 提供的答案相反)。然而,我注意到哨兵评论说失去了索引优势。我只有 300 行。但很高兴知道。谢谢大家!
【解决方案3】:

结果不容易区分数据中的 NULL 和表示连接失败的 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;

【讨论】:

    【解决方案4】:

    一种解决方案是使用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)
    ;
    

    【讨论】:

    • 除非创建匹配的基于函数的索引,否则所有索引都会丢失
    【解决方案5】:

    在内部,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));
    

    我不确定它的使用是否得到官方支持,或者他们是否已经开始公开记录它。

    【讨论】:

      【解决方案6】:

      此解决方案保留了 using 子句的使用,但删除了 using 子句中包含空值的一列(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.
      

      【讨论】:

        猜你喜欢
        • 2017-07-05
        • 2012-01-06
        • 1970-01-01
        • 1970-01-01
        • 2022-01-01
        • 2018-07-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多