如何使用SQL查询从表中删除重复项

4

我有一个表格,如下所示:

emp_name   emp_address  sex  matial_status  
uuuu       eee          m    s
iiii       iii          f    s
uuuu       eee          m    s

我希望根据员工姓名、地址和性别这三个字段删除重复的条目。删除后,我的结果表应该如下所示 -

emp_name    emp_address   sex   marital_status
uuuu        eee           m     s
iiii        iii           f     s

我不记得如何为此编写SQL查询。有人可以帮忙吗?


3
如果您不打算以行的所有列为基础进行复制,那么当找到重复项时,您将如何决定保留哪一行? - Ralph Shillington
8个回答

5

我会创建一个新表,对你想要保持唯一的列创建一个唯一性索引。然后从旧表中插入到新表中,忽略有关重复行的警告。最后,我会删除(或重命名)旧表并用新表替换它。在MySQL中,操作如下:

CREATE TABLE tmp LIKE mytable;
ALTER TABLE tmp ADD UNIQUE INDEX myindex (emp_name, emp_address, sex, marital_status);
INSERT IGNORE INTO tmp SELECT * FROM mytable;
DROP TABLE mytable;
RENAME TABLE tmp TO mytable;

或者类似的东西(这完全没有经过测试)。

4

这不是一个查询语句,而是一个删除语句。它将从您的表中删除/移除重复行。

;with C as
(
  select row_number() over(partition by DUPLICATE_VAARS_DECISION 
                           order by NODE_EQ_NO) as rn
  from yourtable
)
delete C
where rn > 1

如果您只对查询表并获取非重复项感兴趣,应改用以下方法。
;with C as
(
  select *,
         row_number() over(partition by DUPLICATE_VAARS_DECISION 
                           order by NODE_EQ_NO) as rn
  from yourtable
)
select *
from C
where rn = 1

1
谢谢,这个可以用!对于第一条删除重复项的语句,更易理解的写法是:;with C as ( select row_number() over(partition by Description order by Description) as rn from [YourTable] ) delete C where rn > 1 - 6dev6il6

2

一种方法

select emp_name,   emp_address,  sex,  max(marital_status) as marital_status
from Yourtable
group by emp_name,   emp_address,  sex

由于我不知道您想要什么,所以我将婚姻状况使用最高值(max)

更多示例请参见包含聚合列的相关值


你为什么使用了max函数? - user7
请查看@ Ralph在您的问题上的评论。 您决定保留哪个重复婚姻状况的逻辑是什么? - mellamokb

2
看起来所有四个列的值都是重复的,所以您可以这样做 -
select distinct emp_name, emp_address, sex, marital_status
from YourTable

然而,如果婚姻状况不同,且您有其他基于某一列进行选择的列(例如,您想根据创建日期列选择最新记录),则可以这样做。
select emp_name, emp_address, sex, marital_status
from YourTable a
where not exists (select 1 
                   from YourTable b
                  where b.emp_name = a.emp_name and
                        b.emp_address = a.emp_address and
                        b.sex = a.sex and
                        b.create_date >= a.create_date)

1
在我看来,这并没有回答他的问题。他想要一个UPDATE或DELETE FROM语句,而不是一个单独的SELECT语句,它不是永久性的,并且不会以任何方式改变表格。 - Mack

0

如果您可以为了性能和简单性而牺牲空间,那么可以通过引入使用 CHECKSUM() TSQL 方法和 DISTINCT 关键字的计算/派生列来消除 emp_name | emp_address | sex 组合中的重复项。

以下是 CHECKSUM 的示例:

SELECT CHECKSUM(*) FROM HumanResources.Employee WHERE EmployeeID = 2

在Google上搜索并创建一个依赖列,其中包含3个列的校验和。 然后,您可以通过查看此问题来选择不同的行。


我也邀请一些对这个答案的批评 - 我需要知道这是否足够好(即使是一个有800k行的表)。 - Zasz

0

如果您对distinct不满意,请尝试以下方法

SELECT MAX(ID) AS MaxRecordID, max(FirstName) AS fname
    FROM [SampleDB].[dbo].[Employee]
    GROUP BY [FirstName], 
             [LastName], 
             [Country]

使用 groupBy 和 Max 关键字。你可以在任何类型的列上使用max,包括 Integer、Varchar 等等。

0

我知道这是一个旧帖子,但最近我测试了一个解决方案,并希望分享给任何人,如果有人觉得我的解决方案有用的话 -

创建表 tmpTable 类似于 yourTable; 插入到 tmpTable (col1, col2 ... colN) 从 yourTable 中选择不同的 col1, col2 ... colN WHERE 1; 删除表 yourTable; 将表 tmpTable 重命名为 yourTable;

请注意,插入语句可能在没有主键的情况下执行。

谢谢。


0

这里有最佳解答:
使用以下SQL语句识别额外的重复行:

 select * from Employee a 
where %%physloc%% >
(select min(%%physloc%%) from Employee b
where a.emp_name=b.emp_name and a.emp_address=b.emp_address and a.sex=b.sex);

你将会得到额外的行:

uuuu   eee m   s 


使用以下SQL语句删除多余的重复行:

 delete from Employee a 
where %%physloc%% >
(select min(%%physloc%%) from Employee b
where a.emp_name=b.emp_name and a.emp_address=b.emp_address and a.sex=b.sex);


对于所有重复的记录,只保留具有最低物理位置的记录。该方法可用于删除各种重复行。

我假设您正在使用MS SQL Server。如果您使用的是Oracle DB,则可以将“ %% physloc%%”替换为“ rowid

享受这段代码吧!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接