从没有主键的SQL表中删除重复记录

Shy*_*yju 50 sql t-sql sql-server-2005 duplicate-removal

我在下面的表格中有以下记录

create table employee
(
 EmpId number,
 EmpName varchar2(10),
 EmpSSN varchar2(11)
);

insert into employee values(1, 'Jack', '555-55-5555');
insert into employee values (2, 'Joe', '555-56-5555');
insert into employee values (3, 'Fred', '555-57-5555');
insert into employee values (4, 'Mike', '555-58-5555');
insert into employee values (5, 'Cathy', '555-59-5555');
insert into employee values (6, 'Lisa', '555-70-5555');
insert into employee values (1, 'Jack', '555-55-5555');
insert into employee values (4, 'Mike', '555-58-5555');
insert into employee values (5, 'Cathy', '555-59-5555');
insert into employee values (6 ,'Lisa', '555-70-5555');
insert into employee values (5, 'Cathy', '555-59-5555');
insert into employee values (6, 'Lisa', '555-70-5555');
Run Code Online (Sandbox Code Playgroud)

我没有在这张桌子上的任何主键.但我已经在我的表中有上述记录.我想删除EmpId和EmpSSN字段中具有相同值的重复记录.

例如:Emp id 5

任何人都可以帮我构建一个查询来删除那些重复的记录

提前致谢

小智 71

这很简单.我在SQL Server 2008中尝试过

DELETE SUB FROM
(SELECT ROW_NUMBER() OVER (PARTITION BY EmpId, EmpName, EmpSSN ORDER BY EmpId) cnt
 FROM Employee) SUB
WHERE SUB.cnt > 1
Run Code Online (Sandbox Code Playgroud)

  • 这个答案实际上解决了这个问题,没有结构上的变化.完美的工作. (4认同)
  • 当你有很多列要分组时,这很有效,并且它在比较两列时整齐地处理NULL!= NULL.您不必像其他一些答案那样列出每一列("a.col = b.col"类型的东西),更重要的是,您不必检查"((a.col = b) .col)OR(a.col IS NULL和b.col IS NULL))"在NULL列上. (2认同)

cjk*_*cjk 54

添加主键(下面的代码)

运行正确的删除(下面的代码)

考虑为什么你不想保留那个主键.


假设MSSQL或兼容:

ALTER TABLE Employee ADD EmployeeID int identity(1,1) PRIMARY KEY;

WHILE EXISTS (SELECT COUNT(*) FROM Employee GROUP BY EmpID, EmpSSN HAVING COUNT(*) > 1)
BEGIN
    DELETE FROM Employee WHERE EmployeeID IN 
    (
        SELECT MIN(EmployeeID) as [DeleteID]
        FROM Employee
        GROUP BY EmpID, EmpSSN
        HAVING COUNT(*) > 1
    )
END
Run Code Online (Sandbox Code Playgroud)

  • +1:引用一些SQL神:"如果它没有主键,它就不是表" (7认同)
  • +1主键标识一行.没有PK =没有意义.@marc_s:聚簇索引将表与堆区分开来.没有PK只是意味着没有数据完整性 (2认同)

Pau*_*gan 22

使用行号区分重复记录.保留EmpID/EmpSSN的第一行编号并删除其余部分:

    DELETE FROM Employee a
     WHERE ROW_NUMBER() <> ( SELECT MIN( ROW_NUMBER() )
                               FROM Employee b
                              WHERE a.EmpID  = b.EmpID
                                AND a.EmpSSN = b.EmpSSN )
Run Code Online (Sandbox Code Playgroud)

  • +1一个很好的解决方案,以避免必须进行结构更改 (3认同)

小智 9

With duplicates

As
(Select *, ROW_NUMBER() Over (PARTITION by EmpID,EmpSSN Order by EmpID,EmpSSN) as Duplicate From Employee)

delete From duplicates

Where Duplicate > 1 ;
Run Code Online (Sandbox Code Playgroud)

这将更新表并删除表中的所有重复项!


小智 8

select distinct * into newtablename from oldtablename
Run Code Online (Sandbox Code Playgroud)

现在,newtablename将没有重复的记录.

只需newtablename在sql server中的对象资源管理器中按F2 即可更改表名().


Dar*_*mas 6

您可以创建一个临时表#tempemployee包含select distinct您的employee表.然后delete from employee.然后insert into employee select from #tempemployee.

就像Josh所说 - 即使你知道重复项,删除它们也是不可能的,因为如果它与另一条记录完全相同,你实际上不能引用特定的记录.

  • 如果名称不同但ID/SSN匹配,则只有技巧.你必须以某种方式选择一个,因为明显不会有帮助. (2认同)

小智 6

代码

DELETE DUP 
FROM 
( 
    SELECT ROW_NUMBER() OVER (PARTITION BY Clientid ORDER BY Clientid ) AS Val 
    FROM ClientMaster 
) DUP 
WHERE DUP.Val > 1
Run Code Online (Sandbox Code Playgroud)

解释

使用内部查询来构建表的视图,该视图包含一个基于 的字段Row_Number(),由您希望唯一的那些列分区。

从这个内部查询的结果中删除,选择行号不为 1 的任何内容;即重复;不是原版。

order by有效语法需要 row_number 窗口函数的子句;您可以在此处输入任何列名称。如果您希望更改将哪些结果视为重复结果(例如保留最早的或最近的等),那么此处使用的列很重要;即您要指定顺序,以便您希望保留的记录在结果中排​​在第一位。