如何避免SQL中SELECT、GROUP BY、ORDER BY的函数重复书写
你可以通过以下几种主流方案消除重复的计算逻辑,提升查询可维护性:
方案1:使用CROSS APPLY定义复用计算值(适配SQL Server、PostgreSQL 12+、Oracle 12C+等支持APPLY语法的数据库)
这是代码量最少、可读性最高的方案,只需要定义一次计算逻辑即可在所有子句中引用:
SELECT v.BodyLengthGroup * 100 AS BodyLengthStart, (v.BodyLengthGroup + 1) * 100 - 1 AS BodyLengthEnd, COUNT(*) AS MessageCount FROM [Message] CROSS APPLY ( SELECT FLOOR(COALESCE(LEN(Body), 0) / 100) AS BodyLengthGroup ) v GROUP BY v.BodyLengthGroup ORDER BY v.BodyLengthGroup
方案2:使用公用表表达式(CTE),适配所有主流SQL数据库
通过CTE提前预计算分组字段,所有后续逻辑直接引用预计算的结果即可:
WITH MessageWithGroup AS ( SELECT FLOOR(COALESCE(LEN(Body), 0) / 100) AS BodyLengthGroup FROM [Message] ) SELECT BodyLengthGroup * 100 AS BodyLengthStart, (BodyLengthGroup + 1) * 100 - 1 AS BodyLengthEnd, COUNT(*) AS MessageCount FROM MessageWithGroup GROUP BY BodyLengthGroup ORDER BY BodyLengthGroup
方案3:复用SELECT别名(适配MySQL、PostgreSQL等支持GROUP BY/ORDER BY引用SELECT别名的数据库)
这类数据库支持直接在GROUP BY、ORDER BY子句中引用SELECT中定义的别名,由于BodyLengthStart是分组字段乘以固定系数,分组和排序效果与原始逻辑完全一致:
SELECT FLOOR(COALESCE(LEN(Body), 0) / 100) * 100 AS BodyLengthStart, (FLOOR(COALESCE(LEN(Body), 0) / 100) + 1) * 100 - 1 AS BodyLengthEnd, COUNT(*) AS MessageCount FROM [Message] GROUP BY BodyLengthStart ORDER BY BodyLengthStart
以上所有方案的输出结果与原始查询完全一致,样例输出如下:
| BodyLengthStart | BodyLengthEnd | MessageCount |
|---|---|---|
| 0 | 99 | 130 |
| 100 | 199 | 76 |
| 200 | 299 | 36 |
内容的提问来源于stack exchange,提问作者Redline
相关产品推荐
相关产品推荐

