oracle“not in”没有返回正确的结果?

u0njafvf  于 2021-07-26  发布在  Java
关注(0)|答案(5)|浏览(411)

我正在比较两个表,它们之间共享唯一的值,使用 NOT IN 中的函数 Oracle 但我现在

select count(distinct CHARGING_ID)   from BILLINGDB201908 where CDR_TYPE='GPRSO'

输出为: 521254 对于所有计费id--<这是billingdb201908中唯一的计费id的总数
现在我想在billingdb201908表中找到同样存在于cbs\u chrg\u id\u aug表中的id

select count(distinct CHARGING_ID)   from BILLINGDB201908 where CDR_TYPE='GPRSO'
AND charging_id IN (select CHARGINGID from CBS_CHRG_ID_AUG);

---结果回来了 315567 收费id存在于billingdb201908中,也存在于cbs\U chrg\U id\U aug中
现在我想找到在cbs\u chrg\u id\u aug中不存在但存在billingdb201908的收费id

select count(distinct CHARGING_ID)   from prmdb.CDR_TAPIN_201908@prmdb where CDR_TYPE='GPRSO'
AND charging_id NOT IN (select CHARGINGID from CBS_CHRG_ID_AUG);

--结果回来了 0 !? 我应该去 205687 完全是因为 521254-315567 = 205687 ?

zvms9eto

zvms9eto1#

缺少的记录具有空值chargingid。
请尝试选择chargingid为空vs不为空的位置

lztngnrs

lztngnrs2#

NOT IN 如果子查询中的任何值无效,则不返回任何行 NULL . 因此,我强烈建议 NOT EXISTS :

SELECT count(distinct CHARGING_ID)   
FROM prmdb.CDR_TAPIN_201908@prmdb  ct
WHERE CDR_TYPE = 'GPRSO' AND
      NOT EXISTS (SELECT 1
                  FROM CBS_CHRG_ID_AUG ccia
                  WHERE ccia.charging_id = ct.charging_id
                 );

我还建议将第一个查询改为 EXISTS . 事实上,只是不要使用 IN 以及 NOT IN 使用子查询,就不会有这个问题。

klr1opcd

klr1opcd3#

我建议你 not exists 而不是 not in ; 它是 null -安全,通常效率更高:

select count(distinct charging_id)   
from billingdb201908 b
where 
    b.cdr_type = 'gprso'
    and not exists (select 1 from cbs_chrg_id_aug a where a.chargingid = b.chargingid)
ql3eal8s

ql3eal8s4#

您可以使用 LEFT OUTER JOIN .
sql返回cbs\u chrg\u id\u aug中不存在但存在billingdb201908的计费id列表-

select count(distinct CHARGING_ID)   
from prmdb.CDR_TAPIN_201908@prmdb a 
left join CBS_CHRG_ID_AUG b on a.CHARGING_ID = b.CHARGINGID 
where a.CDR_TYPE='GPRSO' and b.CHARGINGID is null;
mcvgt66p

mcvgt66p5#

这有两种危险 not in 当子查询键可能包含空值时:
如果实际存在空值,则可能无法得到预期的结果(如您所发现的)。数据库实际上是正确的,尽管在sql历史上没有人预料到这个结果。
即使填充了所有键值,键列是否可能为null(如果未定义为 not null )然后数据库必须进行检查以防出现空值,因此查询仅限于低效的逐行筛选操作,这可能会对大型卷执行灾难性的操作(这在历史上是正确的,尽管现在有一个空感知的反连接,因此性能问题可能不会那么严重。)

create table demo (id) as select 1 from dual;

select * from demo;

        ID
----------
         1
create table table_with_nulls (id) as (
  select 2 from dual union all
  select null from dual
);

select * from table_with_nulls;

        ID
----------
         2
select d.id
from   demo d
where  d.id not in
       ( select id from table_with_nulls );

no rows selected
select d.id
from   demo d
where  d.id not in
       ( select id from table_with_nulls
         where  id is not null );

        ID
----------
         1

原因是 1 <> nullnull ,不是 false . 如果用固定列表代替 not in 子查询,它将是:

select d.id
from   demo d
where  d.id not in (2, null);

这和

select d.id
from   demo d
where  d.id <> 2 and d.id <> null;

很明显 d.id <> null 永远不会是真的。这就是为什么你 not in 查询未返回任何行。

相关问题