FILTER子句必须与聚合函数配合使用,不能用于非聚合窗口函数;正确写法为SUM(sales) FILTER (WHERE status='completed') OVER (PARTITION BY region);不支持嵌套FILTER,且仅PostgreSQL 9.4+支持,MySQL和SQL Server不支持。

FILTER子句必须和聚合函数一起用,不能单独用于窗口函数
很多人看到 FILTER 就想直接写成 SUM(sales) OVER (PARTITION BY region) FILTER (WHERE status = 'completed'),这会报错:ERROR: syntax error at or near "FILTER"。因为 SQL 标准里 FILTER 是聚合函数的修饰子句(类似 DISTINCT),不是窗口定义的一部分。它只能出现在聚合函数内部,且必须配合 OVER 使用。
正确写法是把 FILTER 放在聚合函数括号里,再整体套上窗口语法:
SELECT region, sales, SUM(sales) FILTER (WHERE status = 'completed') OVER (PARTITION BY region) AS completed_sum FROM orders;
-
FILTER必须紧贴在聚合函数名后、括号内,不能放在OVER后面 - 不支持嵌套多个
FILTER,比如AVG(x) FILTER (...) FILTER (...)是非法的 - PostgreSQL 9.4+ 支持;MySQL 和 SQL Server 不支持该语法,别硬套
替代方案:CASE WHEN + 窗口函数更通用但语义稍弱
当数据库不支持 FILTER,或你想兼容更多环境时,CASE WHEN 是等效写法,但要注意 NULL 处理逻辑差异:
SUM(CASE WHEN status = 'completed' THEN sales ELSE 0 END) OVER (PARTITION BY region)
这和 FILTER 的行为不完全一致:前者把不满足条件的行转为 0,后者是彻底忽略(即不参与求和)。如果 sales 字段本身可能为 NULL,用 CASE 写成 ELSE NULL 才等价,否则会把 NULL 行也计入(因 SUM(NULL) 忽略,但 SUM(0) 会拉低均值)。
- 用
CASE WHEN ... THEN x ELSE NULL END才与FILTER语义一致 -
CASE方式在所有主流 SQL 引擎中都可用,包括 BigQuery、Snowflake、Redshift - 性能上,
FILTER在 PostgreSQL 中通常略快,因为避免了分支计算和额外的 NULL 转换
常见误用:在 ROW_NUMBER() 或 LAG() 上加 FILTER 报错
ROW_NUMBER() FILTER (WHERE flag = true) OVER (ORDER BY ts) 这类写法一定失败——FILTER 不适用于非聚合的窗口函数。这类需求得换思路:
- 先用
WHERE过滤源数据,再对子集编号:SELECT ..., ROW_NUMBER() OVER (ORDER BY ts) FROM orders WHERE flag - 或用
CASE构造标记列,再配合条件聚合:COUNT(*) FILTER (WHERE flag) OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING) -
LAG()、LEAD()、FIRST_VALUE()全都不接受FILTER,强行加会触发syntax error at or near "FILTER"
复杂场景下 FILTER 和窗口帧(ROWS/RANGE)的交互容易被忽略
FILTER 只控制“哪些行参与聚合”,但不改变窗口帧范围。例如:
SUM(sales) FILTER (WHERE status = 'completed') OVER (PARTITION BY region ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
它的意思是:在当前行及前两行构成的滑动窗口内,只对其中 status = 'completed' 的行求和。不是“先过滤全表再开窗”。这点常被误读,导致结果比预期小。
- 如果窗口帧很窄(如
1 PRECEDING),而符合条件的行又少,结果可能是 NULL 或 0 - 想实现“全局过滤后排序编号”,就不能依赖
FILTER+ 窗口,得用 CTE 预过滤 - PostgreSQL 中
FILTER对空组(即窗口内无匹配行)返回 NULL,不是 0,注意判空

















