TSQL按site、service分组先取最大yr再取对应最大mo的更优实现方法
解决方案
下面提供两种简洁高效的实现方式,均支持后续年-月-日层级的扩展需求:
方案1:数值拼接法(最适合层级扩展,代码极简)
核心逻辑是将年、月按权重拼接为整数,最大值天然对应「最大年+该年最大月」,后续扩展层级仅需调整权重即可,无需修改整体结构。
SELECT site, service, MAX(yr * 100 + mo) / 100 AS maxYr, MAX(yr * 100 + mo) % 100 AS maxMo FROM @t1 GROUP BY site, service
如果后续要扩展到年-月-日层级,仅需调整计算规则:
SELECT site, service, MAX(yr * 10000 + mo * 100 + [day]) / 10000 AS maxYr, (MAX(yr * 10000 + mo * 100 + [day]) % 10000) / 100 AS maxMo, MAX(yr * 10000 + mo * 100 + [day]) % 100 AS maxDay FROM @t1 GROUP BY site, service
优势:仅需一次表扫描,无嵌套子查询,性能最优,层级扩展成本极低。
方案2:排序取Top1法(逻辑直观,无需数值运算)
如果不想做数值计算,可以用开窗函数排序后取每组第一条,逻辑非常好理解,扩展也很方便:
SELECT site, service, yr AS maxYr, mo AS maxMo FROM ( SELECT site, service, yr, mo, ROW_NUMBER() OVER (PARTITION BY site, service ORDER BY yr DESC, mo DESC) AS rn FROM @t1 ) t WHERE rn = 1
扩展到年-月-日层级只需要在ORDER BY后面加[day] DESC即可。
原有写法问题说明
你尝试写的窗口函数写法逻辑存在缺陷:分组后每个site+service分组仅返回一行,此时max(mo) over (...)取的是该分组所有月份的最大值,而非最大年对应的月份最大值,比如分组内存在「2021年1月、2020年12月」时,会错误返回maxMo为12,而非正确的1。
你原来的EXISTS写法虽然逻辑正确,但需要多次扫描表,性能不如上述两种方案,且层级扩展时需要修改多层子查询,维护成本高。
内容的提问来源于stack exchange,提问作者smpa01
相关产品推荐
相关产品推荐

