SQL中HAVING 1语法的含义是什么?分组取最新记录SQL疑问
HAVING 1的含义与实际作用 基础语义
HAVING子句原生作用是在GROUP BY分组操作后,对聚合结果做条件过滤,只有满足HAVING后条件的分组才会被保留。HAVING 1里的1在SQL的布尔判断里等价于恒真,单看这一句的效果是不会过滤任何数据,相当于没写过滤条件。
这段SQL中HAVING 1的真实作用
网上流传的这段SQL是针对5.7及更早版本、未开启ONLY_FULL_GROUP_BY模式的MySQL的特殊写法,HAVING 1在这里没有任何业务过滤价值,纯粹是用来绕过MySQL优化器的默认行为:
- 按照SQL标准,子查询如果没有搭配
LIMIT子句,内层写的ORDER BY会被优化器判定为无意义,会在执行时被忽略。如果去掉这个HAVING,内层写的ORDER BY r.time DESC大概率会被优化掉,外层GROUP BY a.id就不会按预期返回每个id分组下最新的记录。 - 老版本MySQL的优化器逻辑存在特殊判定:只要子查询里写了HAVING子句,就不会主动消除内层的ORDER BY排序逻辑,会保留按时间倒序排好的结果集,外层GROUP BY时就会默认取每个分组排序后的第一行,刚好得到「每个分组最新一条记录」的效果。
注意事项
- 这个写法是利用数据库优化器特性的非标准奇技淫巧,兼容性极差:换到8.0及以上版本MySQL、开启
ONLY_FULL_GROUP_BY配置、或者换到Oracle/PostgreSQL等其他数据库,这段SQL要么直接报错,要么返回结果不符合预期。 - 正规的「按字段分组取每组最新记录」的实现不要用这种写法,推荐用窗口函数实现,逻辑清晰且兼容所有主流数据库新版本:
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY time DESC) AS row_rank FROM record WHERE id IN (xx,xx,xx) ) t WHERE row_rank = 1
如果是不支持窗口函数的老版本数据库,也可以用关联查询实现:
SELECT r.* FROM record r WHERE r.id IN (xx,xx,xx) AND r.time = ( SELECT MAX(r2.time) FROM record r2 WHERE r2.id = r.id )
内容的提问来源于stack exchange,提问作者bronson
相关产品推荐
相关产品推荐

