我已经看到了几个解决方案,但我想知道什么是最好和最有效的方法来重塑桌子。您可以使用代码(SQL等)来说明您的观点,但我只是在寻找基本算法。我以为在SO上已经有一个关于这个的问题,但我找不到一个,所以如果它已经存在,那就给我一个抬头。
(只是为了澄清 - 我指的是在具有增量自动PK的表中删除重复项,并且在除PK字段之外的所有内容中都有一些重复的行。)
答案 0 :(得分:12)
SELECT DISTINCT <insert all columns but the PK here> FROM foo
。使用该查询创建临时表(语法因RDBMS而异,但通常有SELECT … INTO
或CREATE TABLE AS
模式可用),然后吹掉旧表并将临时表中的数据泵回到其中。
答案 1 :(得分:8)
使用分析函数row_number:
WITH CTE (col1, col2, dupcnt)
AS
(
SELECT col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col1) AS dupcnt
FROM Youtable
)
DELETE
FROM CTE
WHERE dupcnt > 1
GO
答案 2 :(得分:7)
重复数据删除很少很简单。这是因为要进行重复数据删除的记录通常会有一些字段略有不同。因此,选择要保留的记录可能会有问题。此外,重复通常是人员记录,并且很难确定两个约翰史密斯是两个人还是一个人是重复的。因此,花费大量时间(整个项目的50%或更多)来定义构成dup的内容以及如何处理差异和子记录。
你怎么知道哪个是正确值?进一步的重复数据删除要求您处理所有不是孤立的子记录。当您发现通过更改子记录中的id突然违反其中一个唯一索引或约束时会发生什么 - 这最终会发生,您的进程需要处理它。如果您愚蠢地选择仅通过应用程序应用所有约束,您可能甚至不知道违反了约束。当您有10,000条记录要进行重复数据删除时,您不会通过该应用程序一次重复删除一个记录。如果约束不在数据库中,那么在重复数据删除时保持数据完整性的运气很大。
更复杂的是,副本并不总是与名称或地址完全匹配。例如,名为Joan Martin的销售代表可能是销售代表Joan Martin-Jones的副本,特别是如果他们有相同的地址和电子邮件。或者你可以在名字中加入约翰或约翰尼。或者相同的街道地址,除了一个记录abbreveiated ST。一个拼写出街道。在SQL Server中,您可以使用SSIS和模糊分组来识别近匹配。这些通常是最常见的重复,因为不完全匹配的事实是它们首先被放入重复的原因。
对于某些类型的重复数据删除,您可能需要一个用户界面,以便执行重复数据删除的人可以选择用于特定字段的两个值中的哪一个。如果被重复数据删除的人有两个或更多角色,则尤其如此。可能是特定角色的数据通常比另一个角色的数据更好。或者可能只有用户才能确定哪个是正确的值,或者他们可能需要联系人们以确定他们是真正的重复还是仅仅是两个具有相同名称的人。
答案 3 :(得分:6)
在此处添加实际代码以供将来参考
因此,有3个步骤,因此有3个SQL语句:
步骤1:将非重复项(唯一元组)移动到临时表
中CREATE TABLE new_table as
SELECT * FROM old_table WHERE 1 GROUP BY [column to remove duplicates by];
第2步:删除旧表(或重命名) 我们不再需要包含所有重复条目的表格,所以请删除它!
DROP TABLE old_table;
步骤3:将new_table重命名为old_table的名称
RENAME TABLE new_table TO old_table;
当然,不要忘记修复您的错误代码以停止插入重复项!
答案 4 :(得分:3)
如果您可以将dupe标准放入group by语句并且您的表具有唯一性的id标识列,则使用以下方法:
delete t
from tablename t
inner join
(
select date_time, min(id) as min_id
from tablename
group by date_time
having count(*) > 1
) t2 on t.date_time = t2.date_time
where t.id > t2.min_id
在此示例中,date_time是分组条件,如果您有多个列,请确保加入所有列。
答案 5 :(得分:2)
我从DShook获取一个并提供重复数据删除示例,您只保留具有最高日期的记录。
在这个例子中说我有3条记录都具有相同的app_id,我只想保留具有最高日期的记录:
DELETE t
FROM @USER_OUTBOX_APPS t
INNER JOIN
(
SELECT
app_id
,max(processed_date) as max_processed_date
FROM @USER_OUTBOX_APPS
GROUP BY app_id
HAVING count(*) > 1
) t2 on
t.app_id = t2.app_id
WHERE
t.processed_date < t2.max_processed_date
答案 6 :(得分:1)
对于那些喜欢快速而肮脏的方法的人,只需列出共同定义唯一记录的所有列,并使用这些列创建唯一索引,如下所示:
ALTER IGNORE TABLE TABLE_NAME
添加独特(column1
,column2
,column3
)
您可以删除后面的唯一索引。
答案 7 :(得分:0)
您可以为每一行(不包括PK)生成哈希值,将其存储在新列中(或者如果您不能添加新列,是否可以将表移动到临时暂存区域?),然后查看对于具有相同散列的所有其他行。当然,您必须能够确保您的哈希函数不会为不同的行生成相同的代码。
如果两行是重复的,那么你摆脱了哪些问题?是否有可能其他数据依赖于两个重复项?如果是这样,您将需要完成几个步骤:
dupeA
以消除dupeA
dupeB
dupeA
。这可能很简单,也可能很复杂,具体取决于您现有的数据模型。
这整个场景听起来像是一个维护和重新设计项目。如果是这样,祝你好运!
答案 8 :(得分:0)
对于SQL,您可以使用INSERT IGNORE INTO表SELECT xy FROM unkeyed_table;
对于算法,如果您可以假设可以重复成为主要密钥,但是要成为主要密钥唯一地标识行的内容,而不是仅对要成为主要密钥和检查重复。
答案 9 :(得分:0)
我认为这应该只需要除了id以外的所有列进行分组并从每个组中选择一行 - 为简单起见只是第一行,但除了你对id有额外的限制之外,这实际上并不重要。 / p>
或者反过来摆脱行...只需删除所有行,接受所有组中的一行。
答案 10 :(得分:0)
这可以重复使用c1
中的重复值:
select * from foo
minus
select f1.* from foo f1, foo f2
where f1.c1 = f2.c1 and f1.c2 > f2.c2
答案 11 :(得分:0)
这是我在现实生活中遇到过的一个。
假设您有一个用户外部/第三方登录表,您将合并两个用户,并希望对提供者/提供者密钥值进行重复数据删除。
;WITH Logins AS
(
SELECT [LoginId],[UserId],[Provider],[ProviderKey]
FROM [dbo].[UserLogin]
WHERE [UserId]=@FromUserID -- is the user we're deleting
OR [UserId]=@ToUserID -- is the user we're moving data to
), Ranked AS
(
SELECT Logins.*
, [Picker]=ROW_NUMBER() OVER (
PARTITION BY [Provider],[ProviderKey]
ORDER BY CASE WHEN [UserId]=@FromUserID THEN 1 ELSE 0 END)
FROM Logins
)
MERGE Logins AS T
USING Ranked AS S
ON S.[LoginId]=T.[LoginID]
WHEN MATCHED AND S.[Picker]>1 -- duplicate Provider/ProviderKey
AND T.[UserID]=@FromUserID -- safety check
THEN DELETE
WHEN MATCHED AND S.[Picker]=1 -- the only or best one
AND T.[UserID]=@FromUserID
THEN UPDATE SET T.[UserID]=@ToUserID
OUTPUT $action, DELETED.*, INSERTED.*;
答案 12 :(得分:0)
这些方法可行,但没有明确的id作为PK,那么确定要删除哪些行可能是个问题。反弹到临时表中删除原始表并重新插入而没有欺骗似乎是最简单的。
答案 13 :(得分:0)
对于重复数据删除/重复数据删除/删除重复数据/删除重复的行/数据库除重/数据库删除重复记录,有多种方法。
如果重复的行完全相同,请使用分组依据
创建表TABLE_NAME_DEDUP
作为选择column1,column2,...(所有列名称)
在TABLE_NAME中按列1,列2分组-所有列名称
然后TABLE_NAME_DEDUP是已重复数据删除的表。
例如,
create table test (t1 varchar(5), t2 varchar(5));
insert into test values ('12345', 'ssdlh');
insert into test values ('12345', 'ssdlh');
create table test_dedup as
select * from test
group by t1, t2;
-----optional
--remove original table and rename dedup table to previous table
--this is not recommend in dev or qa. DROP table test; Alter table test_dedup rename to test;
您有一个rowid,该rowid具有重复项,但其他列不同 记录部分相同,这可能在事务系统中更新一行时发生,并且更新失败的行将为空。 您要删除重复项
创建表test_dedup为 选择column1,column2,...(所有列名称) 来自( 选择 * ,row_number()超过cn(按row1,column2,...(除rowid之外的所有列名)按行ID顺序分区) 从测试 ),其中cn = 1
此功能使用的功能是,当您使用order by时,空值将在非空值之后排序。
create table test (rowid_ varchar(5), t1 varchar(5), t2 varchar(5));
insert into test values ('12345', 'ssdlh', null);
insert into test values ('12345', 'ssdlh', 'lhbzj');
create table test_dedup as
select rowid_, t1, t2 from
(select *
, row_number() over (partition by rowid_ order by t1, t2) as cn
from test)
where cn =1
;
-----optional
--remove original table and rename dedup table to previous table
--this is not recommend in dev or qa. DROP table test; Alter table test_dedup rename to test;
答案 14 :(得分:0)
今天遇到了这个问题,现有的答案都没有帮助我。假设您想对名为your_table
的表进行重复数据删除。
步骤1:使用重复数据删除的值创建新表
如果从StackOverflow上的其他地方借来了此代码,但似乎无法再次找到它。它对PostgreSQL很好用。它创建一个表your_table_deduped
,其中(col1, col2)
是唯一的。
CREATE TABLE your_table_deduped AS
SELECT * FROM your_table WHERE ctid NOT IN
(SELECT ctid FROM
(SELECT ctid, ROW_NUMBER() OVER
(PARTITION BY col1, col2 ORDER BY ctid) AS rnum
FROM your_table) t
WHERE t.rnum > 1);
第2步:将第一个表格替换为重复数据删除的副本
我们仅在此步骤中删除值,因为它允许我们将索引,约束等保留在表中。
DELETE FROM your_table;
INSERT INTO your_table
SELECT * FROM your_table_deduped;
第3步:删除重复数据删除的副本
DROP TABLE site_daily_kpis_dedup;
瞧,您已经对表格进行了重复数据删除!
答案 15 :(得分:0)
delete from yourTable
where Id not in (
select min(id)
from yourTable
group by <Unique Columns>
)
其中id是表中唯一的ID。 (可以是customerNumber或其他任何值)
如果您没有唯一ID,则可以添加一个(每个SQL表应该已经将ID作为第一列,但是
ALTER TABLE yourTable
ADD Id int identity(1,1)
(在上方)进行删除,然后删除该列。
比创建一个全新的表或我见过的任何其他神秘的东西更好。请注意,与此处的评论几乎相同,但这是我多年来所做的。