Oracle 10g中的条件重复删除

时间:2015-01-16 06:52:50

标签: sql oracle

CREATE TABLE testdup
(seq_no NUMBER,
ID NUMBER,
attrib1 NUMBER,
attrib2 NUMBER);

INSERT INTO testdup
     VALUES (2, 15, 1211, 1250);
INSERT INTO testdup
     VALUES (1, 15, -999, -999);
INSERT INTO testdup
     VALUES (3, 16, 1234, 1234);
INSERT INTO testdup
     VALUES (4, 16, 1234, -1234);
INSERT INTO testdup
     VALUES (5, 17, -999, -999);
INSERT INTO testdup
     VALUES (6, 17, -999, -999);
INSERT INTO testdup
     VALUES (7, 18, -999, -999);
INSERT INTO testdup
     VALUES (8, 19, 741, -715);

COMMIT ;

我需要做的是删除重复的ID -

  • 如果重复的ID记录具有值(attrib1 =除 -999 之外的任何值),则删除较低的seq_no(在上面的示例中id = 16)
  • 如果-999与非-99一起出现(在上面的示例中为id = 15),则删除值为-999的记录
  • 如果对于所有记录存在重复记录值'attrib1 = -999',则删除较低的seq_no(在上面的示例中为id = 17)
  • 跳过非重复的ID(在上面的示例中为id = 18和19)

在上面的示例中,seq_no应该删除1,3和5

数据库 - Oracle 10g

下面的查询给出了部分输出,但是当attrib1对于给定的id是相同的时候,删除min(seq_id)就不行了

SELECT seq_no, ID, attrib1,
       ROW_NUMBER () OVER (PARTITION BY ID, ID ORDER BY CASE
           WHEN attrib1 = -999
              THEN 999999999
           ELSE TO_NUMBER (attrib1)
        END) rn
  FROM testdup order by 1

我正在玩解析功能并为此找到解决方案,将其附加到其他人参考

SELECT seq_no, ID, attrib1,
       ROW_NUMBER () OVER (PARTITION BY ID ORDER BY CASE
           WHEN attrib1 = -999
              THEN 999999999
           ELSE TO_NUMBER (attrib1)
        END ASC,
        seq_no DESC) rn
  FROM testdup

2 个答案:

答案 0 :(得分:1)

我相信你想要

delete from testdup where rowid in (
  select
    coalesce(
      case when rowid_999_min is not null and 
                rowid_999_max is not null and
                rowid_999_min != rowid_999_max 
           then null
           else rowid_999_max
      end,
      rowid_min_seq
  )
  from (
      select
        min(case when attrib1 = -999 then rowid end)        rowid_999_min,
        max(case when attrib1 = -999 then rowid end)        rowid_999_max,
        min(rowid) keep (dense_rank first order by seq_no)  rowid_min_seq
      from
        testdup
      group by
        id
      having
        count(*) > 1
  )
);

答案 1 :(得分:1)

这是一个尝试:

with w as
(
  select t.id,
         case when sum(case when t.attrib1 = -999 then 1 else 0 end) > 0 then 1 else 0 end exists999,
         case when min(t.attrib1) = -999 and max(t.attrib1) = -999 then 1 else 0 end only999
  from testdup t
  group by t.id
  having count(*) > 1
)
select 'Only -999 values, removed min seq_no' reason, min(t.seq_no) removed
from testdup t, w
where w.id = t.id
  and w.only999 = 1
group by t.id

union all

select 'No -999 values, removed min seq_no' reason, min(t.seq_no) removed
from testdup t, w
where w.id = t.id
  and w.exists999 = 0
group by t.id

union all

select 'Some -999 values, removed seq_no with this value' reason, t.seq_no removed
from testdup t, w
where w.id = t.id
  and w.exists999 = 1
  and w.only999 = 0
  and t.attrib1 = -999
;

with子句允许我知道一组相似的ID,如果它们只包含-999值。然后我根据你的标准有一个查询。

结果:

    REASON                                 REMOVED
1   Only -999 values, removed min seq_no                5
2   No -999 values, removed min seq_no                  3
3   Some -999 values, removed seq_no with this value    1
相关问题