首页/数据/SQL 速查/窗口函数的使用限制
聚合与窗口函数54 条

窗口函数的使用限制

窗口函数只能出现在 SELECT 列表与 ORDER BY 中:WHERE、GROUP BY、HAVING 里不能用;要筛选计算结果必须套子查询。

SQL 速查数据更新于 2026-10-13

窗口函数的使用限制

窗口函数只能出现在 SELECT 列表与 ORDER BY 里,不能写进 WHERE、GROUP BY 或 HAVING——它们的执行时机都在窗口计算之前。要按窗口结果过滤,必须把查询包成派生表或 CTE,再在外层写条件。此外还有几条硬性限制:窗口函数不能互相嵌套;MySQL 8 的窗口函数不支持 DISTINCT 聚合;两个库都不允许在 UPDATE / DELETE 里直接使用窗口函数,需要先用 CTE 算出目标值再更新。

基本信息

允许的位置SELECT 列表、ORDER BY
不允许的位置WHERE、GROUP BY、HAVING、UPDATE / DELETE 的直接使用
嵌套限制窗口函数不能嵌套在另一个窗口函数内部
MySQL 限制窗口函数里不支持 DISTINCT 聚合(如 COUNT(DISTINCT x) OVER (…))
过滤窗口结果包一层派生表或 CTE,再在外层写 WHERE

典型使用场景

  • 按行号筛选每组前 N 行,需要包一层派生表
  • 按排名或占比结果过滤(取占比超过 10% 的项)
  • 排查「窗口函数写在 WHERE 报错」这类语法问题
  • 用 CTE 先算出窗口结果,再据此执行更新
  • 把窗口结果与其他聚合函数分层组合使用

过滤窗口结果的标准写法

过滤窗口结果的标准写法
# 正确:窗口结果在派生表里算好,外层再过滤
SELECT id, user_id, amount
FROM (
  SELECT id, user_id, amount,
         ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC, id DESC) AS rn
  FROM orders
) t
WHERE t.rn = 1;

# 错误写法(语法报错):窗口函数不能直接写在 WHERE
-- SELECT * FROM orders WHERE ROW_NUMBER() OVER (PARTITION BY user_id) = 1;

PostgreSQL 里用 CTE 配合更新

PostgreSQL 里用 CTE 配合更新
-- 两个库都不允许在 UPDATE 里直接使用窗口函数:先用 CTE 算出结果
WITH ranked AS (
  SELECT id,
         ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC, id DESC) AS rn
  FROM orders
)
UPDATE orders o
   SET is_latest = (ranked.rn = 1)
  FROM ranked
 WHERE ranked.id = o.id;

-- MySQL 里改写成 UPDATE … JOIN:
-- UPDATE orders o JOIN (SELECT id, ROW_NUMBER() OVER (...) AS rn FROM orders) t
--   ON t.id = o.id SET o.is_latest = (t.rn = 1);

限制清单

位置或用法是否允许替代方案
SELECT 列表允许—
ORDER BY允许—
WHERE / HAVING不允许包派生表或 CTE 后在外层过滤
GROUP BY不允许改用语义等价的聚合写法,或分层实现
UPDATE / DELETE两库都不允许直接使用用 CTE 先算出目标值再更新
窗口函数嵌套不允许拆成多层派生表或 CTE
窗口函数与聚合函数的执行时机不同:GROUP BY 会先把行折叠,窗口函数则在保留行的前提下计算;同一层里既要分组又想让窗口基于明细行,只能分层实现(先聚合出派生表,再在外层开窗)。
MySQL 8 的窗口函数不支持 DISTINCT 聚合,写 COUNT(DISTINCT x) OVER (…) 会直接报错;需要组内去重计数时,先用派生表去重,再用窗口计数。

易错点

  • 把窗口函数直接写进 WHERE 或 HAVING,语法报错,需包一层派生表
  • 想在 UPDATE / DELETE 中直接使用窗口函数,语句不被支持,必须拆成两步
  • 尝试嵌套窗口函数被拒绝后没有改用多层 CTE 实现
  • 在 MySQL 8 里写 COUNT(DISTINCT …) OVER (…),该组合不被支持

数据来源与参考

  • MySQL 8.0 Reference Manual · Window Function Restrictions
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌