一文教你如何删除重复记录
# 一文教你如何删除重复记录
# 写法一:根据行号和排序
场景分析:
- 现以用户表(
t_user
)为例,uid
和id
为表中的某个字段。 uid
是表中的唯一字段,但是因为之前没有加唯一索引,导致内部出现uid
重复的数据。- 现在需要加唯一索引,但是需要先删除表中多余的重复的脏数据。
SQL 示例:
以下是一个删除重复记录的示例 SQL 语句,它将为每个 uid
保留具有最小 id
值的记录
DELETE
FROM t_user
WHERE id IN (SELECT id
FROM (SELECT id, uid,
ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id) AS row_num
FROM t_user) AS ranked
WHERE row_num > 1);
1
2
3
4
5
6
7
2
3
4
5
6
7
示例解析:
在这个例子中,内部查询首先为每个 uid
分组内的记录分配了一个行号(row_num
),根据 id
字段排序,其中最小的 id
值对应行号1。然后,外层的 IN
子句用来选择那些行号大于 1 的记录,即重复的记录。最后,DELETE
语句根据 id
删除这些记录。
语法解析:
ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id) AS row_num
是 SQL 中的一个窗口函数(window function)的语法。窗口函数用于在不失去分组的情况下,对分组内的数据进行计算。
这里是 ROW_NUMBER()
函数的具体用法:
ROW_NUMBER()
: 这是一个窗口函数,它会为结果集中的每一行分配一个唯一的序号,序号的分配是连续的,从1开始,不管中间是否有空缺。OVER
: 这个关键字用来指定窗口函数的参数,即定义窗口函数的作用域和排序的顺序。PARTITION BY uid
: 这个子句定义了窗口函数的分区依据。在这里,PARTITION BY
将结果集按照uid
字段的值进行分组。对于每个uid
分区,ROW_NUMBER()
都会重新从1开始计数。ORDER BY id
: 这个子句定义了窗口函数内部的排序规则。在这里,它指定了在每个uid
分区内部,行应该根据id
字段的值进行升序排序。如果有多条记录具有相同的id
,它们的行号可能会是相同的。AS row_num
: 这是给窗口函数的结果指定一个别名,方便在查询的其他部分引用。在这里,行号被命名为row_num
。
整个表达式的作用是:对于表 t_user
中的每条记录,根据 uid
进行分组,并在每个分组内根据 id
的升序排列,为每条记录分配一个唯一的行号。
这种语法在处理如去重、分组排序等复杂查询时非常有用。例如,你可以使用这个行号来删除每个 uid
分组内的重复记录,只保留具有最小 id
的记录。
# 写法二:min(id)
场景分析:
- 唯一键(
date, alert_level, enterprise_id
) '2024-12-13'
统计的数据出现重复行,需要删除多余的重复数据
SQL 示例:
-- 先查
select DISTINCT date
from t_alarm_stat
GROUP BY date, alert_level, enterprise_id
having count(*) > 1;
-- 后删(这里不能直接用子查询去查同一张表)
WITH Duplicates AS (SELECT min(id) AS min_id
FROM t_alarm_stat
WHERE date = '2024-12-13'
GROUP BY date, alert_level, enterprise_id
HAVING COUNT(*) > 1)
DELETE
FROM t_alarm_stat
WHERE id IN (SELECT min_id FROM Duplicates);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上次更新: 2024/12/16 17:54:54