Oracle NOT IN 对可为空的字段不起作用

Oracle NOT IN does not work will nullable fields

我必须比较两个具有相同结构的表(int not null、int not null、varchar2)。在两个表中,field3 都可以为空。

我有下一个SQL:

Select 
   t1.field1, t1.field2, t1.field3)  
From
   table1 t1
Where  (field1,field2,field3)
   not in 
   (select field1,
    field2,field3
    from table2 t2)

当字段 3 在其中任何一个(t1 或 t2)中为 NULL 时,查询不会 return 任何行。例如,我想从该数据中 return 一行,但 return 什么都没有。

Table 1

field1    field2    field3
1         2         <NULL>

Table 2

field1    field2    field3
1         2         'some text data' 

使用 NVL 函数可以解决此类问题:NVL(field3, 'dummytextorwhatever') 但我不想在我的代码中包含这种可怕的东西。有解决此问题的想法吗?

谢谢!

尝试not exists

Select 
  t1.field1, 
  t1.field2, 
  t1.field3
From
  table1 t1
where not exists 
  (select 1
    from table2 t2
  where 
  t1.field1=t2.field1 
  and t1.field2=t2.field2 
  and t1.field3=t2.field3
  )

样本测试

with table1(field1,field2,field3) as
(select 1,2,null from dual),
        table2(field1,field2,field3) as
(select 1,2,'something' from dual)

Select 
  t1.field1, 
  t1.field2, 
  t1.field3
From
  table1 t1
where not exists 
  (select 1
    from table2 t2
  where 
  t1.field1=t2.field1 
  and t1.field2=t2.field2 
  and t1.field3=t2.field3
  )

输出

FIELD1 FIELD2 FIELD3
1      2      

当主 table 或子查询的结果集中存在空值时,这是 NOT IN 的已知行为。正如@DrCopyPaste 所说的那样

"when writing WHERE value NOT IN (x, y, z) this will be internally interpreted as WHERE value != x AND value != y AND value != z, and comparing against NULL (either for equality or unequality) always yields FALSE"

简单的答案是使用 NOT EXISTS:

Select 
   t1.field1, t1.field2, t1.field3)  
From
   table1 t1
Where  not exists   
   (select  null   from table2 t2
    where t2.field1 = t1.field1
    and t2.field2 = t1.field2
    and t2.field3 = t1.field3 )

反加入会产生相同的结果

Select 
   t1.field1, t1.field2, t1.field3)  
From
   table1 t1
     left join table2 t2
       on t2.field1 = t1.field1
       and t2.field2 = t1.field2
       and t2.field3 = t1.field3 
where t2.field1 is null

"why do you select a null at the beginning?"

因为对于 NOT EXISTS,子查询是什么并不重要 returns。重要的是它 returns 一个非空结果集。它可能是 1field1,但这真的无关紧要,所以为什么不是 null

尝试使用 NVLCoalesce 运算符,像这样

Select 
   t1.field1, t1.field2, t1.field3 
From
   table1 t1
Where  (nvl(field1,0),nvl(field2,0),nvl(field3,0))
   not in 
   (select nvl(field1,0),nvl(field2,0),nvl(field3,0)
    from table2 t2)

但是如果在表数据中有一些数据等于 0 select 将是 return 那一行,因为 nvl(field1,0)=nvl(field2,0)field1=0field2=null 时,所以你可以使用任何值(你应该有信心 ) 您的表格数据中不存在,例如 -99(nvl(field,-99))

或者您可以使用 exists/not exists

根据您的查询,您试图在表 1 中查找表 2 中不存在的所有时间。考虑使用 MINUS 而不是 NOT IN...

Select t1.field1, t1.field2, t1.field3
From   table1 t1
Minus
select t2.field1, t2.field2, t2.field3
from   table2 t2;