消除数据库中的重复项 table
Eliminating duplicates in a database table
对于那些阅读了原始问题的人,很抱歉让您感到困惑。我正在重做这个问题,让它更清楚一点(尽我所能)
我在 DB2 中有一个 table,它是从源数据库和数据中填充的,使用的条件超出了我的控制范围。我的目标是创建预期查询以确保进入此目标 table 的数据与预期相符。前 5 列将具有主键约束。
源数据有时可能在本应作为主键的列中有重复项。所以我需要让我的查询说明这一点。以下是记录的一些示例。 (由于真实数据的隐私限制,我不得不使用通用数据来说明)
Apple Banana Carrot Dog Elephant A+
Apple Banana Carrot Dog Elephant B
Apple Bowl Carrot Dog Elephant 231
Apple Bowl Carrot Dog Elephant A-
AppleJack Bowl Carrot Dog Elephant 142
AppleJack Bowl Carrot Dog Elephant 204
因此,如果我们将前 5 条记录作为主键的条件,那么这里将有 3 条重复记录。前两个记录将相互重复,接下来的两个和最后两个。这是我选择保留哪些记录的标准。
1.) 如果出现重复,删除第 6 列值 = 'NR' 的记录
(我的问题中没有这方面的例子,但它确实出现在我的实际数据中。
2.) 去除NR后,如果仍然出现重复,则去除第6列值=数值的记录。如果两条记录都是数字,则保留
3.) 检查数值后,如果仍然重复,则将第6列按字母顺序排序,取第一条记录。
我需要我的查询在删除的同时检查这些条件。所以在我的查询执行后,唯一应该仍然存在的记录(根据我的理解如下):
Apple Banana Carrot Dog Elephant A+
Apple Bowl Carrot Dog Elephant A-
AppleJack Bowl Carrot Dog Elephant 142
AppleJack Bowl Carrot Dog Elephant 204
我希望这更清楚我需要什么。任何帮助将不胜感激!我永远感谢那些提供意见的人!这确实意义重大!我对 SQL 还是很陌生,但了解大部分基本概念。再次感谢您花时间阅读。
示例(仅用于数字的过滤器相当笨拙):
DELETE
-- SELECT * -- for testing
FROM rubbish d
WHERE EXISTS (
SELECT *
FROM rubbish x
WHERE x.a=d.a
AND x.b=d.b
AND x.c=d.c
AND x.d=d.d
AND x.e=d.e
AND ( 0=1
-- delete NR record only if a non-NR record exists
OR (d.val = 'NR' AND x.val <> 'NR')
-- d=numeric, x= non numeric
OR (length(translate(d.val, '0123456789' , '' )) = 0
AND length(translate(x.val, '0123456789' , '')) > 0
)
-- both numeric
-- OR (length(translate(d.val, '0123456789' , '' )) = 0
-- AND length(translate(x.val, '0123456789' , '' )) = 0
-- AND d.val::integer < x.val::integer
-- )
-- both non-numeric
OR (length(translate(d.val, '0123456789' , '' )) > 0
AND length(translate(x.val, '0123456789' , '' )) > 0
AND d.val > x.val AND x.val <> 'NR'
)
)
)
;
基本上你需要的是根据你的标准在前五列确定的组内对记录进行排序:首先是非数字,然后是数字,然后是 'NR',然后按字母顺序排序,并删除除每个组的第一个记录。所以对于一个简化的例子:
create table t (f1 varchar(10), f2 varchar(10), f3 varchar(10))
insert into t values ('foo', 'bar', 'A+'), ('foo', 'bar', 'B'),
('jack','jill','231'), ('jack','jill','A-'),
('apple', 'banana', '142'), ('apple', 'banana', '204'),
('yum','sum','NR'), ('yum','sum','42')
首先尝试选择:
select * from (
select
f1, f2, f3,
row_number()
over (partition by f1, f2
order by
case
when f3 = 'NR' then 3 -- check for 'NR' first otherwise it will match the non-numeric check
when length(trim(translate(f3,'','0123456789') )) > 0 then 1 -- non-numeric
when length(trim(translate(f3,'','0123456789') )) = 0 then 2 -- numeric
else 4 -- shouldn't happen anyway
end,
f3
) rn
from t
) where rn = 1
order by f1, f2, f3
并删除:
delete from (
select
row_number() -- don't need any other columns
over (partition by f1, f2
order by
case
when f3 = 'NR' then 3
when length(trim(translate(f3,'','0123456789') )) > 0 then 1
when length(trim(translate(f3,'','0123456789') )) = 0 then 2
else 4
end,
f3
) rn
from t
) where rn > 1
显然在你的情况下你会 partition by
五列,而不是两列。
对于那些阅读了原始问题的人,很抱歉让您感到困惑。我正在重做这个问题,让它更清楚一点(尽我所能)
我在 DB2 中有一个 table,它是从源数据库和数据中填充的,使用的条件超出了我的控制范围。我的目标是创建预期查询以确保进入此目标 table 的数据与预期相符。前 5 列将具有主键约束。
源数据有时可能在本应作为主键的列中有重复项。所以我需要让我的查询说明这一点。以下是记录的一些示例。 (由于真实数据的隐私限制,我不得不使用通用数据来说明)
Apple Banana Carrot Dog Elephant A+
Apple Banana Carrot Dog Elephant B
Apple Bowl Carrot Dog Elephant 231
Apple Bowl Carrot Dog Elephant A-
AppleJack Bowl Carrot Dog Elephant 142
AppleJack Bowl Carrot Dog Elephant 204
因此,如果我们将前 5 条记录作为主键的条件,那么这里将有 3 条重复记录。前两个记录将相互重复,接下来的两个和最后两个。这是我选择保留哪些记录的标准。
1.) 如果出现重复,删除第 6 列值 = 'NR' 的记录 (我的问题中没有这方面的例子,但它确实出现在我的实际数据中。
2.) 去除NR后,如果仍然出现重复,则去除第6列值=数值的记录。如果两条记录都是数字,则保留
3.) 检查数值后,如果仍然重复,则将第6列按字母顺序排序,取第一条记录。
我需要我的查询在删除的同时检查这些条件。所以在我的查询执行后,唯一应该仍然存在的记录(根据我的理解如下):
Apple Banana Carrot Dog Elephant A+
Apple Bowl Carrot Dog Elephant A-
AppleJack Bowl Carrot Dog Elephant 142
AppleJack Bowl Carrot Dog Elephant 204
我希望这更清楚我需要什么。任何帮助将不胜感激!我永远感谢那些提供意见的人!这确实意义重大!我对 SQL 还是很陌生,但了解大部分基本概念。再次感谢您花时间阅读。
示例(仅用于数字的过滤器相当笨拙):
DELETE
-- SELECT * -- for testing
FROM rubbish d
WHERE EXISTS (
SELECT *
FROM rubbish x
WHERE x.a=d.a
AND x.b=d.b
AND x.c=d.c
AND x.d=d.d
AND x.e=d.e
AND ( 0=1
-- delete NR record only if a non-NR record exists
OR (d.val = 'NR' AND x.val <> 'NR')
-- d=numeric, x= non numeric
OR (length(translate(d.val, '0123456789' , '' )) = 0
AND length(translate(x.val, '0123456789' , '')) > 0
)
-- both numeric
-- OR (length(translate(d.val, '0123456789' , '' )) = 0
-- AND length(translate(x.val, '0123456789' , '' )) = 0
-- AND d.val::integer < x.val::integer
-- )
-- both non-numeric
OR (length(translate(d.val, '0123456789' , '' )) > 0
AND length(translate(x.val, '0123456789' , '' )) > 0
AND d.val > x.val AND x.val <> 'NR'
)
)
)
;
基本上你需要的是根据你的标准在前五列确定的组内对记录进行排序:首先是非数字,然后是数字,然后是 'NR',然后按字母顺序排序,并删除除每个组的第一个记录。所以对于一个简化的例子:
create table t (f1 varchar(10), f2 varchar(10), f3 varchar(10))
insert into t values ('foo', 'bar', 'A+'), ('foo', 'bar', 'B'),
('jack','jill','231'), ('jack','jill','A-'),
('apple', 'banana', '142'), ('apple', 'banana', '204'),
('yum','sum','NR'), ('yum','sum','42')
首先尝试选择:
select * from (
select
f1, f2, f3,
row_number()
over (partition by f1, f2
order by
case
when f3 = 'NR' then 3 -- check for 'NR' first otherwise it will match the non-numeric check
when length(trim(translate(f3,'','0123456789') )) > 0 then 1 -- non-numeric
when length(trim(translate(f3,'','0123456789') )) = 0 then 2 -- numeric
else 4 -- shouldn't happen anyway
end,
f3
) rn
from t
) where rn = 1
order by f1, f2, f3
并删除:
delete from (
select
row_number() -- don't need any other columns
over (partition by f1, f2
order by
case
when f3 = 'NR' then 3
when length(trim(translate(f3,'','0123456789') )) > 0 then 1
when length(trim(translate(f3,'','0123456789') )) = 0 then 2
else 4
end,
f3
) rn
from t
) where rn > 1
显然在你的情况下你会 partition by
五列,而不是两列。