0Pricing
Coding Interview Prep · 课时

安全地去除重复行

删除完全重复和近似重复的行,同时保留一条规范记录

安全地去除重复行 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。

去重问题

“这张表中有重复行。请删除重复行,但每行只保留一份。”几乎每场数据工程面试都会以某种形式考查这个问题。挑战在于要安全地完成操作:恰好保留一行规范记录,同时不能误删那些只是看起来相似、实际却不同的记录。

我们将讲解如何检测重复行、选择要保留的副本、在 SELECT 中进行去重,以及从表中实际删除重复行。

先定义重复行

首先要问面试官的问题是:“什么情况下两行算作重复行?”常见定义包括:

  • 完全重复:每一列都相同。
  • 键重复:业务键相同(例如 email 相同),但其他列可能不同。

针对不同定义,所用技术也不同。请不要自行假设;澄清重复行的定义是最重要的一步,面试官也希望您主动询问。

检测重复行

要查找重复键,请按定义重复关系的列进行分组,并保留计数大于一的分组。这样可以在进行任何修改前,了解哪些键受到影响以及每个键存在多少个副本。

先运行检测查询是一项值得明确说出的最佳实践:在删除之前,您可以先确认问题的规模。

SELECT email, COUNT(*) AS copies
FROM users
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY copies DESC;

完全重复:DISTINCT

如果重复行确实在每一列上都完全相同,那么只读的去重视图可以简单地写成 SELECT DISTINCT *。不带 ALL 的 UNION 也会删除重复行。

但只有在您希望对整行去重、且不需要选择要保留的副本时,DISTINCT 才有帮助。对于列值不同的基于键的重复行,您需要使用排名。

-- Read-only dedup of exact-duplicate rows
SELECT DISTINCT customer_id, name, signup_date
FROM customers;

键重复:ROW_NUMBER

当多行共享同一个键、但其他列不同时,请按键进行分区,并为每个副本编号。rn = 1 标记要保留的行;rn > 1 标记要丢弃的多余行。

窗口中的 ORDER BY 决定要保留哪个副本作为规范副本。请有意识地进行选择,例如保留最近更新的行。

SELECT *,
  ROW_NUMBER() OVER (
    PARTITION BY email
    ORDER BY updated_at DESC
  ) AS rn
FROM users;

选择规范副本

请将编号逻辑封装在 CTE 中,只保留 rn = 1。这样每个键会返回一行,具体就是您的 ORDER BY 排名第一的那一行。

这种 SELECT 写法不会破坏数据:它非常适合构建干净的视图,或者通过 INSERT ... SELECT 将数据写入去重后的目标表,而不会修改源表。

WITH ranked AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY email ORDER BY updated_at DESC
    ) AS rn
  FROM users
)
SELECT user_id, email, name, updated_at
FROM ranked
WHERE rn = 1;

排序选择很重要

分区中的 ORDER BY 是业务决策,而不是形式要求:

  • ORDER BY updated_at DESC 会保留最新的记录。
  • ORDER BY created_at ASC 会保留最初创建的记录。
  • ORDER BY id ASC 会保留数值最小的代理键,适合用作稳定的任意选择。

请加入唯一的并列决胜字段,以便在主要排序列也出现并列时,仍能确定地选出目标行。

ROW_NUMBER() OVER (
  PARTITION BY email
  ORDER BY updated_at DESC, id ASC
) AS rn

实际删除重复行

要真正从表中删除重复行,请先识别多余行(rn > 1),然后将其删除。在 PostgreSQL 和 SQL Server 中,您可以使用 CTE 进行删除;在 MySQL 中,自连接或子查询很常见。

请始终先运行匹配的 SELECT,预览究竟哪些行将被删除。盲目删除正是候选人在这道题上失分的原因。

WITH ranked AS (
  SELECT ctid,
    ROW_NUMBER() OVER (
      PARTITION BY email ORDER BY updated_at DESC, id ASC
    ) AS rn
  FROM users
)
DELETE FROM users
WHERE ctid IN (SELECT ctid FROM ranked WHERE rn > 1);

自连接删除模式

一种经典且通用的方法是保留每个重复键下 id 最小的行,并使用自连接删除其余行。它不需要窗口函数,这在较旧的数据库引擎上很有价值。

连接条件会将每一行与另一行配对,后者拥有相同的键但更小的 id;任何存在这样一个较小 id 对应行的行,都是需要删除的重复行。

DELETE u1
FROM users u1
JOIN users u2
  ON u1.email = u2.email
 AND u1.id > u2.id;

安全检查清单

删除之前,请采取以下保护措施:

  • 将删除操作放在事务中,这样如果数量看起来不对,就可以执行 ROLLBACK。
  • 先运行要删除行的 SELECT COUNT(*),并检查结果是否合理。
  • 请考虑创建备份表:CREATE TABLE users_bak AS SELECT * FROM users。
  • 确认您的 PARTITION BY 列确实定义了重复关系,否则可能会误删不同的记录。
BEGIN;
-- run the DELETE, inspect row count
-- COMMIT; if correct, otherwise ROLLBACK;

近似重复与规范化

有时多行并不完全相同,但在逻辑上却表示同一项:'Ann@X.com' 与 'ann@x.com',或者存在尾随空格。请基于规范化后的表达式进行分区,而不是直接使用原始列。

提到规范化能够体现您的实践经验:现实中的重复项经常隐藏在大小写、空白字符或格式差异之后,简单的键比较会漏掉它们。

ROW_NUMBER() OVER (
  PARTITION BY LOWER(TRIM(email))
  ORDER BY updated_at DESC, id ASC
) AS rn

快速检查

请选择安全的去重方法。

回顾:安全去重

请按步骤进行去重:

  • 首先定义什么是重复行,然后使用 GROUP BY / HAVING COUNT(*) > 1 进行检测。
  • 完全重复 → DISTINCT。键重复 → 按键进行分区的 ROW_NUMBER,保留 rn = 1。
  • 窗口中的 ORDER BY 决定规范副本;请加入唯一的并列决胜字段。
  • 预览计数后,在事务中删除 rn > 1 的行。
  • 请规范化键,以捕获近似重复项。

常见问题解答

「安全地去除重复行」课时是免费的吗?

是的 — 「安全地去除重复行」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。

「安全地去除重复行」这节课中我会学到什么?

删除完全重复和近似重复的行,同时保留一条规范记录 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Coding Interview Prep 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「安全地去除重复行」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Coding Interview Prep 课中编写并运行代码吗?

能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 ROW_NUMBER 获取各组前 N 行
  2. 处理前 N 名中的并列值
  3. 安全地去除重复行
  4. 保留每个键对应的最新行
← 返回 Coding Interview Prep