filter子句仅修饰单个聚合函数,作用域限于该调用内部;必须紧贴聚合函数且带括号;支持多filter并列但不可嵌套或与over共存;条件为false或null时行被排除;空集聚合中count返回0,sum/avg等返回null。

FILTER子句不是WHERE的替代品,它只修饰单个聚合函数,作用域严格限定在那一行聚合调用内部。 你写 COUNT(*) FILTER (WHERE status = 'paid'),就只影响这个 COUNT,其他聚合(比如 SUM(amount))照常处理所有行——这点和把条件塞进 WHERE 或用 CASE WHEN 完全不同。
FILTER必须紧贴聚合函数,括号不能省
常见错误是漏掉括号或位置错乱。PostgreSQL 会直接报 syntax error at or near "WHERE"。
- ✅ 正确:
COUNT(*) FILTER (WHERE status = 'shipped') - ❌ 错误:
COUNT(*) FILTER WHERE status = 'shipped'(缺括号) - ❌ 错误:
FILTER (WHERE status = 'shipped') COUNT(*)(位置反了) - ❌ 错误:
COUNT(*) FILTER (WHERE status IN (?))(参数占位符不被接受)
多个FILTER可并列,但不能嵌套或混用窗口函数
你可以在同一 SELECT 中给不同聚合加各自独立的 FILTER,它们互不干扰,也共享一次扫描。但跨层级或跨上下文就会失败。
- ✅ 支持:
AVG(salary) FILTER (WHERE dept = 'eng'), SUM(bonus) FILTER (WHERE year = 2025) - ❌ 不支持:
AVG(salary) FILTER (WHERE dept = 'eng') FILTER (WHERE year > 2020)(嵌套非法) - ❌ 不支持:
AVG(salary) OVER (PARTITION BY dept) FILTER (WHERE active)(FILTER和OVER不能共存) - ❌ 不支持:
SUM(COUNT(*) FILTER (WHERE flag))(聚合函数里不能再套带 FILTER 的聚合)
NULL 值不会被自动跳过,条件里要显式处理
FILTER 的条件求值为 FALSE 或 NULL 时,该行都会被排除。这不是 bug,是设计行为。但容易忽略的是:如果你的过滤字段本身可能为 NULL,不加判断会导致结果偏低。
- ⚠️ 危险写法:
AVG(score) FILTER (WHERE score > 60)——score IS NULL的行也被滤掉,但你可能只想排除低分,而非空分 - ✅ 更安全:
AVG(score) FILTER (WHERE score IS NOT NULL AND score > 60) - ✅
COUNT(*) FILTER不受列是否为NULL影响,但若条件里用了该列(如WHERE name IS NOT NULL),仍需主动写出来
最常被忽略的一点是返回值类型:空集聚合结果不是 0,而是 NULL。COUNT(*) FILTER (WHERE false) 返回 0,但 SUM(amount) FILTER (WHERE false) 或 AVG() 都返回 NULL。报表里直接展示这个 NULL,前端常误判为“没数据”,其实只是“该条件下无匹配行”——得靠 COALESCE(SUM(), 0) 显式兜底。











