在 SQL 中提取唯一记录已经成为随着组织向多维数据存储的集中转变而变得至关重要的任务。有时需要根据多个列的组合输出不重复的行,有时只需依赖单一的关键字段。
问题的背景:
早期版本的 SQL 仅提供 DISTINCT 来过滤重复项。随后出现了结构性方法,包括用于对唯一值集进行聚合的 GROUP BY 以及用于处理重复项的更灵活的场景的窗口函数,例如:基于“最后”或“第一个”记录的提取。
问题:
DISTINCT 仅在 SELECT 字段集的层面上工作,而 GROUP BY 需要聚合。窗口函数允许更先进的逻辑,但如果不仔细考虑行的选择顺序,使用它们往往会导致错误。开发人员常常混淆这些方法,错误可能导致不正确的结果。
解决方案:
代码示例:
获取每位客户的最新订单记录:
WITH OrdersRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) as rn FROM Orders ) SELECT * FROM OrdersRank WHERE rn = 1;
关键点:
是否可以在没有 GROUP BY 的情况下将 DISTINCT 与聚合函数一起使用?
不可以,聚合函数需要分组,否则会出现语法错误。
SELECT COUNT(DISTINCT CustomerID) -- 正确 SELECT SUM(Amount), DISTINCT CustomerID -- 错误!
如果在 GROUP BY 中未列出所有未聚合的 SELECT 字段,会发生什么?
这会在大多数数据库管理系统中引发错误:除聚合外的所有 SELECT 字段都必须在 GROUP BY 中列出。
是否可以在没有子查询的情况下使用窗口函数“删除”重复项?
不可以:在单个 SELECT 中使用 ROW_NUMBER() 不会自动过滤“重复项”,需要外部查询选择所需的行。
对 2000 万行的表选择了所有列的 DISTINCT:查询运行了几个小时,结果是超时或数据库性能下降。
优点:
缺点:
使用窗口函数:在毫秒内仅获取每位客户的最新记录;以前的记录和重复项没有加载。
优点:
缺点: