MSSQL 2016查询问题:按工单号取最早日期(子查询不能用Order By)
嘿,我懂你这种卡在子查询不能用ORDER BY的郁闷!在MSSQL 2016里要按工单号提取最早的日期,其实有好几种靠谱的解决方案,我给你详细说说:
方案1:GROUP BY + MIN()函数(最简洁的基础方案)
如果你的需求只是获取每个工单号对应的最早日期,不需要其他关联字段,这个方法绝对是首选,简单直接还高效:
SELECT 工单号, MIN(日期字段) AS 最早日期 FROM 你的表名 GROUP BY 工单号;
原理很简单:GROUP BY 工单号把数据按工单号分组,MIN(日期字段)直接计算每个组里的最小(最早)日期。MSSQL对聚合函数的优化很好,小到大表都能轻松应对。
方案2:ROW_NUMBER()窗口函数(适合需要额外字段的场景)
要是你还需要同时获取该最早日期对应的其他字段(比如操作人、备注信息),窗口函数就派上用场了:
WITH 工单日期排序 AS ( SELECT 工单号, 日期字段, 操作人, 备注, -- 按工单号分组,每组内按日期升序排,给最早的行标序号1 ROW_NUMBER() OVER (PARTITION BY 工单号 ORDER BY 日期字段 ASC) AS 排序序号 FROM 你的表名 ) SELECT 工单号, 日期字段 AS 最早日期, 操作人, 备注 FROM 工单日期排序 WHERE 排序序号 = 1;
PARTITION BY 工单号:把数据按工单号拆分成独立的分组ORDER BY 日期字段 ASC:每个分组内按日期从早到晚排序ROW_NUMBER():给每个分组里的行按顺序标序号,最早的日期行就是序号1
如果同一个工单号有多条记录是相同的最早日期,这个方法只会取其中一行;要是想保留所有同最早日期的记录,可以把ROW_NUMBER()换成RANK()或者DENSE_RANK()。
方案3:TOP 1 WITH TIES(简洁的多字段查询写法)
这是另一种适合多字段查询的写法,语法更紧凑:
SELECT TOP 1 WITH TIES 工单号, 日期字段, 操作人, 备注 FROM 你的表名 ORDER BY ROW_NUMBER() OVER (PARTITION BY 工单号 ORDER BY 日期字段 ASC);
TOP 1 WITH TIES的作用是:返回所有和“第一行”排序值相同的记录,配合窗口函数的排序规则,就能一次性把每个工单号的最早日期行都捞出来。
补充说明
你之前遇到的子查询不能用ORDER BY的问题,是因为MSSQL里如果子查询是用来返回单个值(比如嵌套在SELECT子句里),ORDER BY是无效的,甚至可能因为返回多行报错。上面这些方法都是MSSQL官方推荐的、更规范的分组取极值的方案,完全可以替代子查询的思路。
内容的提问来源于stack exchange,提问作者simon_s
相关产品推荐
相关产品推荐

