SQL 高级查询与分析实战案例

1次阅读

where 先执行,having 后执行;where 在 group by 前过滤行,只能用原始字段;having 在分组后过滤组,必须配合 group by,且只能用聚合函数或 group by 列。

SQL 高级查询与分析实战案例

WHERE 和 HAVING 混用时到底谁先执行?

WHERE 过滤行,HAVING 过滤分组结果,顺序不能颠倒。写反了会报错或逻辑出错,比如 HAVING 里用了未聚合的列,数据库直接拒绝执行。

  • WHEREGROUP BY 前执行,只能引用原始表字段;HAVING 在分组后执行,必须配合 GROUP BY,且只能用聚合函数或 GROUP BY
  • 想筛“订单金额大于 100 的用户”,用 WHERE order_amount > 100;想筛“平均订单额超 500 的用户”,必须用 HAVING AVG(order_amount) > 500
  • mysql 5.7+ 默认开启 sql_mode=only_full_group_by,如果 select 列没在 GROUP BY 中又没被聚合,会报错:Expression #1 of SELECT list is not in GROUP BY clause

窗口函数 ROW_NUMBER() vs RANK() vs DENSE_RANK()

三者都生成排序编号,但对并列值的处理完全不同,选错会导致业务指标偏差——比如排行榜去重、Top N 统计、分页跳过重复排名等场景极易踩坑。

  • ROW_NUMBER() 严格按顺序编号,相同值也不同号:1,2,2,4
  • RANK() 并列则同号,跳过后续编号:1,2,2,4
  • DENSE_RANK() 并列同号,不跳号:1,2,2,3
  • 分页取“前 10 名”用 ROW_NUMBER() 最稳妥;做“进入前 3 名的用户列表”得用 DENSE_RANK(),否则第 4 名可能实际是并列第 3

JOIN 多表时 NULL 值怎么安全处理?

LEFT JOIN 后字段为 NULL 是常态,但直接参与计算或比较会静默失败——比如 WHERE status = 'active' 会自动过滤掉所有 NULL 行,而你可能想保留左表记录。

  • 判断是否为 NULL 必须用 IS NULLIS NOT NULL,不能用 = NULL(永远返回 UNKNOWN
  • 聚合前补 COALESCE(status, 'unknown') 避免 GROUP BY 分裂;数值计算前用 COALESCE(amount, 0) 防止整个表达式变 NULL
  • postgresql 支持 IS DISTINCT FROM 安全比较,MySQL 和 SQL Server 得靠 COALESCE(a, '') = COALESCE(b, '')

EXPLAIN 看不出性能问题?重点盯这三列

EXPLAIN 输出里真正决定慢不慢的不是 typerows,而是 keyExtrafiltered —— 尤其当 keyNULLExtra 出现 using filesortUsing temporary 时,基本等于没走索引。

  • keyNULL:没命中任何索引,强制全表扫描
  • ExtraUsing index condition 是好信号(ICP 优化启用);含 Using where; Using index 表示覆盖索引,最快
  • filtered 值太低(比如 10.00)说明 WHERE 条件过滤性差,即使走了索引也要读大量无效行

实际写复杂分析查询时,最容易被忽略的是字段别名在 GROUP BYHAVING 中的可用性——标准 SQL 不允许,MySQL 旧版本纵容但新版本默认报错,别依赖它。

text=ZqhQzanResources