GROUP BY子句问题:按BookingID和Status分组的字段报错解决方法
搞定分组取最新行的问题,不用把Total/Duration加进GROUP BY!
我太懂你这个困扰了——SQL的聚合规则就是这么严格:SELECT里的非聚合字段要么进GROUP BY,要么被聚合函数包起来,但咱们要的是每个分组里最新那一行的原始Total、Duration,根本不想把它们当分组键对吧?
给你几个实用的解决方案,覆盖不同数据库场景:
方法1:用ROW_NUMBER()窗口函数(最推荐,大部分数据库都支持)
窗口函数可以给每个分组内的行按时间排序,标记出最新的那一行,之后筛选标记为1的就行,完美绕开GROUP BY的限制:
SELECT BookingID, Status, DateTimeCreatedRealTime, Total, Duration FROM ( SELECT *, -- 按BookingID和Status分组,每组内按时间倒序排,给最新行标1 ROW_NUMBER() OVER( PARTITION BY BookingID, Status ORDER BY DateTimeCreatedRealTime DESC ) AS row_rank FROM BookingTotalAuditTrail ) AS ranked_data WHERE row_rank = 1;
要是同一个分组里有好几行时间完全相同的最新记录,你想都保留的话,把ROW_NUMBER()换成RANK()就行。
方法2:子查询关联(兼容老版本数据库)
如果你的数据库还不支持窗口函数(比如MySQL 5.x),那就先找出每个分组的最新时间,再关联原表拿对应行的字段:
SELECT main.BookingID, main.Status, main.DateTimeCreatedRealTime, main.Total, main.Duration FROM BookingTotalAuditTrail main INNER JOIN ( -- 先拿到每个分组的最新时间 SELECT BookingID, Status, MAX(DateTimeCreatedRealTime) AS latest_time FROM BookingTotalAuditTrail GROUP BY BookingID, Status ) AS latest_times ON main.BookingID = latest_times.BookingID AND main.Status = latest_times.Status AND main.DateTimeCreatedRealTime = latest_times.latest_time;
注意哦,这个方法会返回同一分组里所有时间等于最新时间的行,要是你只想拿一行,就得再加个筛选条件。
方法3:TOP 1 WITH TIES(仅SQL Server可用)
要是你用的是SQL Server,还有个更简洁的写法:
SELECT TOP 1 WITH TIES BookingID, Status, DateTimeCreatedRealTime, Total, Duration FROM BookingTotalAuditTrail ORDER BY ROW_NUMBER() OVER(PARTITION BY BookingID, Status ORDER BY DateTimeCreatedRealTime DESC);
TOP 1 WITH TIES会自动把所有排序后序号为1的行都返回,省得写子查询啦。
内容的提问来源于stack exchange,提问作者ditto
相关产品推荐
相关产品推荐

