PostgreSQL的FILTER子句是MySQL完全不支持的关键特性,允许对同一分组数据进行条件性聚合,如COUNT(*) FILTER (WHERE status='active'),而MySQL只能用SUM(CASE...)模拟,且无法用于JSONB_AGG等高级聚合。

PostgreSQL 的 FILTER 子句在聚合中不可替代
MySQL 完全不支持 FILTER,这是 PostgreSQL 聚合能力的关键分水岭。它允许你在不拆分查询、不嵌套子查询的前提下,对同一组数据做条件性聚合。
常见错误是试图用 CASE WHEN 模拟,但容易忽略 NULL 处理或误用 WHERE 导致整体分组被过滤掉:
-
SELECT COUNT(*) FILTER (WHERE status = 'active') AS active_cnt, COUNT(*) FILTER (WHERE status = 'inactive') AS inactive_cnt FROM users;—— 一行出两组统计 - 等价的 MySQL 写法只能靠
SUM(CASE WHEN ... THEN 1 ELSE 0 END),语义弱、易出错、无法用于ARRAY_AGG或JSONB_AGG等高级聚合 - 注意:FILTER 必须紧跟在聚合函数后、括号外,
COUNT(*) FILTER WHERE ...是语法错误
MySQL 的 JSON_OBJECTAGG 和 PostgreSQL 的 JSONB_AGG 行为差异极大
两者都支持键值对聚合,但底层逻辑和容错性完全不同:
- MySQL 的
JSON_OBJECTAGG(key, value)要求key必须唯一,重复 key 会报错ER_DUP_ENTRY;PostgreSQL 的JSONB_AGG(JSONB_BUILD_OBJECT(...))不校验 key 唯一性,直接拼接,结果里可能含重复键(解析时以最后出现为准) - MySQL 对 NULL 值敏感:
JSON_OBJECTAGG(name, email)遇到任一字段为 NULL,整条键值对被跳过;PostgreSQL 默认保留NULL字段,需显式用FILTER (WHERE email IS NOT NULL)控制 - 性能上,PostgreSQL 的
JSONB_AGG可与FILTER、ORDER BY组合使用,例如:JSONB_AGG(JSONB_BUILD_OBJECT('id', id, 'name', name) ORDER BY id DESC) FILTER (WHERE active)—— MySQL 无法在一个聚合中同时完成排序、过滤、结构化
GROUP BY 场景下 JSON 聚合的 NULL 处理陷阱
当聚合字段来自 LEFT JOIN 或可空列时,MySQL 和 PostgreSQL 对空值的默认行为会悄悄改变结果结构:
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- MySQL 的
JSON_OBJECTAGG在任意输入为 NULL 时,整个键值对消失,可能导致某组返回空 JSON 对象{},而非预期的{"name": null} - PostgreSQL 的
JSONB_BUILD_OBJECT显式保留 NULL:JSONB_BUILD_OBJECT('name', NULL)→{"name": null},更符合 JSON 标准,但也更容易暴露业务逻辑漏洞(比如前端未处理 null 字段) - 若需兼容 MySQL 行为,在 PostgreSQL 中应加
FILTER (WHERE name IS NOT NULL AND email IS NOT NULL),而不是依赖外层 COALESCE
别直接用 JSON_AGG 替代 JSONB_AGG —— 类型决定能否索引
PostgreSQL 提供两个函数,但用途截然不同:
-
JSON_AGG返回文本型 JSON,不能直接在字段上建 GIN 索引,也无法用@>、#>等操作符高效查询 -
JSONB_AGG返回二进制 JSONB,支持 GIN 索引、路径查询、去重合并(||操作符),且排序稳定(自动按 key 字典序) - MySQL 没有对应区分,
JSON_OBJECTAGG输出就是 JSON 类型,但无法建立真正意义上的 JSON 索引(仅支持虚拟列 + B-tree) - 迁移时最容易忽略的一点:应用层若假设聚合结果是字符串并做正则匹配,换成
JSONB_AGG后需改用TO_JSONB()或显式::TEXT转换,否则类型不匹配报错
真正麻烦的不是语法差异,而是当业务开始依赖 FILTER 做多维统计、或用 JSONB_AGG 构建动态配置结构时,再想切回 MySQL 就得重写整个聚合层——连 GROUP BY 的粒度都可能被迫调整。










