编程SQL 分析师

如何从具有多个列的复杂数据结构中提取唯一记录,并且 DISTINCT、GROUP BY 与 ROW_NUMBER() 的工作特性是什么?

用 Hintsage AI 助手通过面试

答案。

在 SQL 中提取唯一记录已经成为随着组织向多维数据存储的集中转变而变得至关重要的任务。有时需要根据多个列的组合输出不重复的行,有时只需依赖单一的关键字段。

问题的背景:

早期版本的 SQL 仅提供 DISTINCT 来过滤重复项。随后出现了结构性方法,包括用于对唯一值集进行聚合的 GROUP BY 以及用于处理重复项的更灵活的场景的窗口函数,例如:基于“最后”或“第一个”记录的提取。

问题:

DISTINCT 仅在 SELECT 字段集的层面上工作,而 GROUP BY 需要聚合。窗口函数允许更先进的逻辑,但如果不仔细考虑行的选择顺序,使用它们往往会导致错误。开发人员常常混淆这些方法,错误可能导致不正确的结果。

解决方案:

  • 使用 DISTINCT 获取所需字段的唯一行。
  • 当需要聚合时使用 GROUP BY(例如,基于唯一对的总和或日期)。
  • 窗口函数 (ROW_NUMBER()) 用于“从重复组中根据某个标准选择一行”等任务。

代码示例:

获取每位客户的最新订单记录:

WITH OrdersRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) as rn FROM Orders ) SELECT * FROM OrdersRank WHERE rn = 1;

关键点:

  • DISTINCT — 仅返回 SELECT 中指定的字段的唯一行。
  • GROUP BY — 如果需要聚合,这是必需的。
  • ROW_NUMBER() — 在选择具有所需优先级/日期/版本的行时具有最大灵活性。

难题。

是否可以在没有 GROUP BY 的情况下将 DISTINCT 与聚合函数一起使用?

不可以,聚合函数需要分组,否则会出现语法错误。

SELECT COUNT(DISTINCT CustomerID) -- 正确 SELECT SUM(Amount), DISTINCT CustomerID -- 错误!

如果在 GROUP BY 中未列出所有未聚合的 SELECT 字段,会发生什么?

这会在大多数数据库管理系统中引发错误:除聚合外的所有 SELECT 字段都必须在 GROUP BY 中列出。

是否可以在没有子查询的情况下使用窗口函数“删除”重复项?

不可以:在单个 SELECT 中使用 ROW_NUMBER() 不会自动过滤“重复项”,需要外部查询选择所需的行。

常见错误和反模式

  • 在列和行数较多时使用 DISTINCT — 性能骤降。
  • 没有必要聚合的 GROUP BY — 没有意义且消耗资源。
  • 没有后续过滤的窗口函数 — 返回的数据包含重复项。

现实案例

消极案例

对 2000 万行的表选择了所有列的 DISTINCT:查询运行了几个小时,结果是超时或数据库性能下降。

优点:

  • 很简单。

缺点:

  • 在大数据上非常低效。

积极案例

使用窗口函数:在毫秒内仅获取每位客户的最新记录;以前的记录和重复项没有加载。

优点:

  • 极高的性能。
  • 灵活性。

缺点:

  • 需要良好的查询架构和窗口函数的知识。