SQL:在一列中丢弃具有冲突记录的行

时间:2016-07-27 18:42:27

标签: sql oracle

为了更好地说明我的问题,我想出了一个示例场景,如下所示:

以下是客户A和B的银行帐户历史记录列表。部分帐户的Open_Year丢失或与其他记录冲突。

例如,帐户 A-3-UB 表示列表中有两个记录的单个帐户,但是,它有两个冲突的Open_Year 1990& 2012;帐户 A-1-BA 有两条记录,其中一条记录缺少Open_Year。

Customer Account_id Bank_id Open_Year Gender
       A          1      BA      2000      F
       A          1      BA         .      F

       A          2      UB         .      F

       A          3      UB      1990      F
       A          3      UB      2012      F

       A          4      UB      2013      F
       A          4      UB      2013      .

       A          5      UB         .      F

       B          1      WF      2014      M
       B          1      WF      2014      .

       B          6      WF         .      .

我希望通过单个 SELECT 查询,具有丢失/冲突的Open_Year的帐户将被丢弃完成,即返回结果将是:

 Customer Account_id Bank_id Open_Year Gender
        A          4      UB      2013      F
        A          4      UB      2013      .
        B          1      WF      2014      M
        B          1      WF      2014      .

其他问题:

现在我们在最后添加了另一条记录,当性别与至少一个值冲突或缺失时,我们还想丢弃一行,与Open_Year相同:

Customer Account_id Bank_id Open_Year Gender
       A          1      BA      2000      F
       A          1      BA         .      F

       A          2      UB         .      F

       A          3      UB      1990      F
       A          3      UB      2012      F

       A          4      UB      2013      F
       A          4      UB      2013      .

       A          5      UB         .      F

       B          1      WF      2014      M
       B          1      WF      2014      .

       B          6      WF         .      .

       C          7      WB      2015      F

预期输出为:

Customer Account_id Bank_id Open_Year Gender
       C          7      WB      2015      F

2 个答案:

答案 0 :(得分:1)

您可以使用窗口功能执行此操作。这是一种方法:

select t.*
from (select t.*,
             count(distinct open_year) over (partition by account_id, bank_id) as cntd_oy,
             count(*) over (partition by account_id, bank_id) as cnt,
             count(open_year) over (partition by account_id, bank_id) as cnt_oy
      from t
     ) t
where cntd_oy = 1 and cnt = cnt_oy

答案 1 :(得分:1)

你也可以使用group by和这样:

with a(Customer,Account_id,Bank_id,Open_Year,Gender) as (
select       'A'      ,    '1'   ,   'BA'  ,    2000,     'F' from dual union all
select       'A'      ,    '1'   ,   'BA'  ,    null ,    'F' from dual union all
select       'A'      ,    '2'   ,   'UB'  ,    null ,    'F' from dual union all
select       'A'      ,    '3'   ,   'UB'  ,    1990 ,    'F' from dual union all
select       'A'      ,    '3'   ,   'UB'  ,    2012 ,    'F' from dual union all
select       'A'      ,    '4'   ,   'UB'  ,    2013 ,    'F' from dual union all
select       'A'      ,    '4'   ,   'UB'  ,    2013 ,     null from dual union all
select       'A'      ,    '5'   ,   'UB'  ,    null ,    'F'   from dual union all
select       'B'      ,    '1'   ,   'WF'  ,    2014 ,    'M'   from dual union all
select       'B'      ,    '1'   ,   'WF'  ,    2014 ,     null from dual union all
select       'B'      ,    '6'   ,   'WF'  ,    null ,     null from dual union all
select       'C'      ,    '7'   ,   'AC'  ,    2016,      'F' from dual)
select a.*
  from a
 where (account_id, bank_id, Open_Year) in 
       ( select account_id, bank_id , Open_Year 
           from a 
          group by account_id, bank_id , Open_Year
         having count(*) > 1 )

    or customer in (select customer from a group by customer having count(*) = 1)