如何在现有SQL分组查询中筛选每组最大DueDate的记录?
解决方法:筛选每个客户对应最大DueDate的记录
哈哈,这个问题我刚入行的时候也踩过坑!直接写WHERE cs.DueDate = MAX(cs.DueDate)肯定不行——因为数据库在执行WHERE子句时,还没完成分组和聚合计算,根本不知道MAX(cs.DueDate)的具体值,会直接抛出语法错误。下面给你两种实用的解决方案:
方案一:子查询+关联筛选(适合大多数SQL数据库)
先通过子查询算出每个客户对应的最大DueDate,再用这个结果关联T_ClientStore表,只保留匹配最大DueDate的记录,最后再执行原有的关联和聚合逻辑:
SELECT cl.[Name] Client, bt.Name BottleType, SUM(csi.Amount) Amount FROM T_Clients cl -- 子查询获取每个客户的最大DueDate INNER JOIN ( SELECT FK_ClientId, MAX(DueDate) AS MaxDueDate FROM T_ClientStore GROUP BY FK_ClientId ) cs_max ON cs_max.FK_ClientId = cl.ClientID -- 筛选出该客户对应最大DueDate的门店记录 INNER JOIN T_ClientStore cs ON cs.FK_ClientId = cl.ClientID AND cs.DueDate = cs_max.MaxDueDate INNER JOIN T_ClientStoreItem csi ON csi.FK_ClientStoreId = cs.ClientStoreId INNER JOIN T_BottleType bt ON bt.BottleTypeId = csi.FK_BootleTypeID GROUP BY cl.[Name], bt.Name ORDER BY cl.[Name]
方案二:窗口函数标记法(适合支持窗口函数的数据库,如SQL Server、MySQL 8+、PostgreSQL等)
用RANK()或ROW_NUMBER()窗口函数给每个客户的门店记录按DueDate降序排名,只保留排名为1的记录(也就是最大DueDate的那些):
WITH ClientStoreWithRank AS ( SELECT cs.ClientStoreId, cs.FK_ClientId, -- 按客户分组,DueDate降序排名,最大的日期排名为1 RANK() OVER (PARTITION BY cs.FK_ClientId ORDER BY cs.DueDate DESC) AS DateRank FROM T_ClientStore cs ) SELECT cl.[Name] Client, bt.Name BottleType, SUM(csi.Amount) Amount FROM T_Clients cl -- 只保留每个客户排名第一的门店记录 INNER JOIN ClientStoreWithRank cs_r ON cs_r.FK_ClientId = cl.ClientID AND cs_r.DateRank = 1 INNER JOIN T_ClientStore cs ON cs.ClientStoreId = cs_r.ClientStoreId INNER JOIN T_ClientStoreItem csi ON csi.FK_ClientStoreId = cs.ClientStoreId INNER JOIN T_BottleType bt ON bt.BottleTypeId = csi.FK_BootleTypeID GROUP BY cl.[Name], bt.Name ORDER BY cl.[Name]
小提示:
- 如果一个客户可能有多个门店记录的DueDate都是最大值(比如同一天的多个门店),用
RANK()会保留所有这些记录;如果只想随机保留一条,换成ROW_NUMBER()即可。 - 不要用
HAVING子句来处理这个需求——HAVING是用来筛选分组后的聚合结果(比如筛选SUM(Amount) > 100的分组),而我们需要的是在分组前就筛选出符合条件的行,所以HAVING不适用。
内容的提问来源于stack exchange,提问作者Arie
相关产品推荐
相关产品推荐

