【问题标题】:Filtering Join in Oracle DB在 Oracle DB 中过滤联接
【发布时间】:2021-03-10 22:17:59
【问题描述】:

问题: 表 A 中的每个KEY 都应该有一个 RF 记录和一个 SJ 记录,但是我有一些重复的 SJ 记录。

目标: 我希望使用表 B 中的 SJ 记录来确定要保留表 A 中的哪个 SJ 记录。

信息: 表 A 和表 B 共享一个 KEY 和 SEQ_NBR 字段。

输入: 表A如下所示

KEY    ID_TYPE   SEQ_NBR   BUS_NAME
1234      RF        1       COMP_A
1234      SJ        2       COMP_B
1234      SJ        4       COMP_C
5678      RF        1       COMP_L
5678      SJ        2       COMP_M
5678      SJ        3       COMP_N

表 B 如下所示

KEY    SEQ_NBR   BUS_NAME
1234      2       COMP_B
5678      3       COMP_N

期望的结果: 我的输出如下所示

KEY    ID_TYPE   SEQ_NBR   BUS_NAME
1234      RF        1       COMP_A
1234      SJ        2       COMP_B
5678      RF        1       COMP_L
5678      SJ        3       COMP_N

【问题讨论】:

  • 请用一般的语言描述这个结果背后的逻辑。有很多方法可以从 this 示例生成 this 结果,但我希望您想了解如何解决一些 type 问题,而不是以未知方式将 A 转换为 B 的黑盒代码。
  • 如果您有在b 中不匹配的重复项怎么办?还是多场比赛?

标签: sql oracle join


【解决方案1】:

这是一种方法:

select key, id_type, seq_nbr, bus_name
from   (
         select a.*,
                row_number() over (partition by a.key, a.id_type
                                   order by b.key) as rn
         from   a left outer join b on a.key = b.key and a.seq_nbr = b.seq_nbr
       )
where  rn = 1
;

左外连接将表b 的列添加到表a 的列。我们需要它来达到一个目的:当我们按keyid_type 分区时,我们有单行或(两或更多)行的分区。在后一种情况下,b.key 中只有一行具有非空值。如果我们按b.key 排序,b.key 为非空的行将得到行号 = 1(我们不关心其余的)。

然后外部查询只是保留所有行号 = 1 的行并忽略其余行。

另一种解决方案,使用两个表的union all(根据需要稍作修改)和使用last聚合函数的基本聚合:

select key, id_type, 
       min(seq_nbr)  keep (dense_rank last order by source) as seq_nbr,
       min(bus_name) keep (dense_rank last order by source) as bus_name
from   (
         select 'A' as source, a.* from a
         union all
         select 'B', key, 'SJ', seq_nbr, bus_name from b
       )
group  by key, id_type
;

您可以同时测试两者,看看哪个对您的数据更有效(如果性能很重要)。

【讨论】:

    【解决方案2】:

    这是你的代码:

    select * from tablea a 
    where   exists 
      (select 1 from tableb b where b.key=a.key and b.seq_nbr=a.seq_nbr)
    or not exists (select tablea.id_type from tablea inner join tableb  on tablea.key=tableb.key and tablea.SEQ_NBR=tableb.SEQ_NBR and tablea.id_type=a.id_type)
    

    【讨论】:

      【解决方案3】:

      如果我理解正确,您可以计算重复的数量。然后使用left join 并根据计数和匹配进行过滤:

      select a.*
      from (select a.*,
                   count(*) over (partition by key, id_type) as cnt
            from a
           ) a left join
           b
           on b.key = a.key and
              b.seq_nbr = a.seq_nbr and
              b.bus_name = a.bus_name
      where cnt = 1 or b.key is not null;
      

      【讨论】:

      • 感谢您的快速回复。表 A 和 B 仅共享 'KEY' 和 'SEQ_NBR' 但第一个 where 子句引用了 id_type,这是故意的吗?再次感谢。
      猜你喜欢
      • 2018-01-01
      • 1970-01-01
      • 2021-07-15
      • 2020-04-08
      • 2015-12-24
      • 2018-08-20
      • 2014-11-07
      • 1970-01-01
      • 2016-11-25
      相关资源
      最近更新 更多