如何删除 MYSQL table 上的重复数据以便能够应用唯一值约束
How to delete repeated data on MYSQL table to be able to apply an unique value constraint
我有一个包含一些字段的数据库,我想将唯一值约束应用于 table:
ALTER TABLE assessment_submissions
ADD CONSTRAINT UC_Question UNIQUE (evaluated_user, evaluator_user, question_id);
但是 table 中有些数据不允许我设置此约束。
我在尝试应用约束时遇到错误:
SQL error 1062: Duplicate entry 154-154-45 for key UC_Question
看看下图:
以 id 131271 和 id 131413 开头的行的结果在字段 evaluated_user
、evaluator_user
和 question_id
.
上具有相同的值
这样就无法应用约束。
我删除了重复的行,但仍然无法应用约束。
我想里面有更多重复数据table。如何找到 table 中所有重复的数据?我可以使用哪个查询来做到这一点?
我不知道从哪里开始。
此查询将 return 所有重复行,以及属于同一“组”的几个 ID。
select evaluated_user, evaluator_user, question_id, count(*), min(id), max(id)
from assessment_submissions
group by evaluated_user, evaluator_user, question_id
having count(*) > 1
这在一定程度上取决于您是否要在决定删除哪些行之前检查这些行(分别参见下面的 1. 2.)。
假设您有以下示例数据:
id evaluated_user evaluator_user question_id answer_id
1 262 275 157 573
2 262 275 162 593
3 262 275 332 1260
4 262 275 161 589
5 262 275 157 573
6 262 275 157 1425
7 262 275 167 726
8 262 275 167 4593
如果您想查看行以获取需要删除哪些行的信息,仅按分组不会获得 ID。
如果您有 MySQL 8.0,您可以使用 window 函数计算每个唯一 (evaluated_user, evaluator_user, question_id)
组合的重复数,如下所示(顺序是可选的):
select *, count(*) over (partition by evaluated_user, evaluator_user, question_id) as cnt
from example e
order by cnt desc, evaluated_user, evaluator_user, question_id
这会给你
id evaluated_user evaluator_user question_id answer_id cnt
1 262 275 157 573 3
5 262 275 157 573 3
6 262 275 157 1425 3
7 262 275 167 726 2
8 262 275 167 4593 2
4 262 275 161 589 1
2 262 275 162 593 1
3 262 275 332 1260 1
在此 table 中,所有 cnt
> 1 的条目都是您感兴趣的行。如果您只需要它们,请将其包装到 select * from ... where cnt > 1
.
对于 MySQL 的早期版本(不支持 window 函数),您可以使用类似@DNNX 答案中的查询并将结果与原始结果相结合来实现相同的目的table:
select e.*
from example e
join (select evaluated_user, evaluator_user, question_id
from example
group by evaluated_user, evaluator_user, question_id
having count(*) > 1) f
on e.evaluated_user = f.evaluated_user and
e.evaluator_user = f.evaluator_user and
e.question_id = f.question_id
其中任何一个都会为您提供您可能想要检查以决定要删除哪些行的行:
id evaluated_user evaluator_user question_id answer_id
1 262 275 157 573
5 262 275 157 573
6 262 275 157 1425
7 262 275 167 726
8 262 275 167 4593
如果您不需要先检查数据来决定删除哪些记录,只要保留一行,您就可以使用 RANK()
函数(同样,MySQL 8.0):
with subtab as (select id, rank() over (partition by evaluated_user, evaluator_user, question_id order by id) as rnk
from example)
delete from example e
where e.id in (select id
from subtab
where rnk > 1)
此示例将针对每个唯一组合批量删除所有重复行,但具有最小 id
的行除外。您可以修改 order by
语句来影响要删除的记录。例如,要保留具有最高 ID 的记录,您可以 order by id desc
。或者,如果您想保留 answer_id
最小的那个,您 order by answer_id
。注意:如果您在排序时所依据的列中有重复的条目,您最终可能会剩下不止一行。为避免这种情况,请使用 row_number()
而不是 rank()
。
要在没有 window 功能的情况下获得相同的效果,您可以使用
delete e from example e
join example f
on e.evaluated_user = f.evaluated_user
and e.evaluator_user = f.evaluator_user
and e.question_id = f.question_id
and e.id > f.id ;
同样,可以根据要保留的行修改语句。例如,要保留最高 answer_id
的条件,您将最后一个条件更改为 and e.answer_id < f.answer_id
.
请参阅 this db<>fiddle 以了解上述所有操作。
请根据手头的需要使用这两个中的任何一个。本质上,您需要决定是保留最先到达数据库的副本集还是最后到达的副本集。
DELETE t1 FROM assessment_submissions t1 INNER JOIN assessment_submissions t2
WHERE t1.id < t2.id
AND t1.evaluated_user=t2.evaluated_user AND t1.evaluator_user = t2.evaluator_user
AND t1.question_id=t2.question_id;
DELETE t1 FROM assessment_submissions t1 INNER JOIN assessment_submissions t2
WHERE t1.id > t2.id
AND t1.evaluated_user=t2.evaluated_user AND t1.evaluator_user = t2.evaluator_user
AND t1.question_id=t2.question_id;
对于 MySQL 版本早于 8.X
的用户环境,我更喜欢上述方法
我有一个包含一些字段的数据库,我想将唯一值约束应用于 table:
ALTER TABLE assessment_submissions
ADD CONSTRAINT UC_Question UNIQUE (evaluated_user, evaluator_user, question_id);
但是 table 中有些数据不允许我设置此约束。
我在尝试应用约束时遇到错误:
SQL error 1062: Duplicate entry 154-154-45 for key UC_Question
看看下图:
以 id 131271 和 id 131413 开头的行的结果在字段 evaluated_user
、evaluator_user
和 question_id
.
这样就无法应用约束。
我删除了重复的行,但仍然无法应用约束。
我想里面有更多重复数据table。如何找到 table 中所有重复的数据?我可以使用哪个查询来做到这一点?
我不知道从哪里开始。
此查询将 return 所有重复行,以及属于同一“组”的几个 ID。
select evaluated_user, evaluator_user, question_id, count(*), min(id), max(id)
from assessment_submissions
group by evaluated_user, evaluator_user, question_id
having count(*) > 1
这在一定程度上取决于您是否要在决定删除哪些行之前检查这些行(分别参见下面的 1. 2.)。
假设您有以下示例数据:
id evaluated_user evaluator_user question_id answer_id
1 262 275 157 573
2 262 275 162 593
3 262 275 332 1260
4 262 275 161 589
5 262 275 157 573
6 262 275 157 1425
7 262 275 167 726
8 262 275 167 4593
如果您想查看行以获取需要删除哪些行的信息,仅按分组不会获得 ID。
如果您有 MySQL 8.0,您可以使用 window 函数计算每个唯一
(evaluated_user, evaluator_user, question_id)
组合的重复数,如下所示(顺序是可选的):select *, count(*) over (partition by evaluated_user, evaluator_user, question_id) as cnt from example e order by cnt desc, evaluated_user, evaluator_user, question_id
这会给你
id evaluated_user evaluator_user question_id answer_id cnt 1 262 275 157 573 3 5 262 275 157 573 3 6 262 275 157 1425 3 7 262 275 167 726 2 8 262 275 167 4593 2 4 262 275 161 589 1 2 262 275 162 593 1 3 262 275 332 1260 1
在此 table 中,所有
cnt
> 1 的条目都是您感兴趣的行。如果您只需要它们,请将其包装到select * from ... where cnt > 1
.对于 MySQL 的早期版本(不支持 window 函数),您可以使用类似@DNNX 答案中的查询并将结果与原始结果相结合来实现相同的目的table:
select e.* from example e join (select evaluated_user, evaluator_user, question_id from example group by evaluated_user, evaluator_user, question_id having count(*) > 1) f on e.evaluated_user = f.evaluated_user and e.evaluator_user = f.evaluator_user and e.question_id = f.question_id
其中任何一个都会为您提供您可能想要检查以决定要删除哪些行的行:
id evaluated_user evaluator_user question_id answer_id 1 262 275 157 573 5 262 275 157 573 6 262 275 157 1425 7 262 275 167 726 8 262 275 167 4593
如果您不需要先检查数据来决定删除哪些记录,只要保留一行,您就可以使用
RANK()
函数(同样,MySQL 8.0):with subtab as (select id, rank() over (partition by evaluated_user, evaluator_user, question_id order by id) as rnk from example) delete from example e where e.id in (select id from subtab where rnk > 1)
此示例将针对每个唯一组合批量删除所有重复行,但具有最小
id
的行除外。您可以修改order by
语句来影响要删除的记录。例如,要保留具有最高 ID 的记录,您可以order by id desc
。或者,如果您想保留answer_id
最小的那个,您order by answer_id
。注意:如果您在排序时所依据的列中有重复的条目,您最终可能会剩下不止一行。为避免这种情况,请使用row_number()
而不是rank()
。要在没有 window 功能的情况下获得相同的效果,您可以使用
delete e from example e join example f on e.evaluated_user = f.evaluated_user and e.evaluator_user = f.evaluator_user and e.question_id = f.question_id and e.id > f.id ;
同样,可以根据要保留的行修改语句。例如,要保留最高
answer_id
的条件,您将最后一个条件更改为and e.answer_id < f.answer_id
.
请参阅 this db<>fiddle 以了解上述所有操作。
请根据手头的需要使用这两个中的任何一个。本质上,您需要决定是保留最先到达数据库的副本集还是最后到达的副本集。
DELETE t1 FROM assessment_submissions t1 INNER JOIN assessment_submissions t2
WHERE t1.id < t2.id
AND t1.evaluated_user=t2.evaluated_user AND t1.evaluator_user = t2.evaluator_user
AND t1.question_id=t2.question_id;
DELETE t1 FROM assessment_submissions t1 INNER JOIN assessment_submissions t2
WHERE t1.id > t2.id
AND t1.evaluated_user=t2.evaluated_user AND t1.evaluator_user = t2.evaluator_user
AND t1.question_id=t2.question_id;
对于 MySQL 版本早于 8.X
的用户环境,我更喜欢上述方法