Oracle 10g 中的条件重复删除
Conditional duplicate removal in Oracle 10g
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 -
- 如果重复的 ids 记录有值(attrib1=除-999之外的任何值)然后删除较低的seq_no(在上面的例子中id=16)
- 如果 -999 与非 -999 一起出现(在上面的示例中 id=15),则删除值为 -999 的记录
- 如果所有记录都存在重复记录值 'attrib1=-999',则删除较低的 seq_no(在上面的示例中 id=17)
- 跳过非重复 ID(在上面的例子中 id=18 和 19)
在下面的例子中 seq_no 应该删除 1、3 和 5
数据库 - Oracle 10g
下面的查询给了我部分输出,但是当给定 id 的 attrib1 相同时,删除 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
我相信你想要
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
)
);
试一试:
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
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 -
- 如果重复的 ids 记录有值(attrib1=除-999之外的任何值)然后删除较低的seq_no(在上面的例子中id=16)
- 如果 -999 与非 -999 一起出现(在上面的示例中 id=15),则删除值为 -999 的记录
- 如果所有记录都存在重复记录值 'attrib1=-999',则删除较低的 seq_no(在上面的示例中 id=17)
- 跳过非重复 ID(在上面的例子中 id=18 和 19)
在下面的例子中 seq_no 应该删除 1、3 和 5
数据库 - Oracle 10g
下面的查询给了我部分输出,但是当给定 id 的 attrib1 相同时,删除 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
我相信你想要
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
)
);
试一试:
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