SQL Server查询优化:添加字段后如何保留200行并获取最新日期
解决思路与方案
这个问题我碰到过不少次——核心原因是你加入时间字段后,分组粒度被拆细了:原来每个(ReportID, Name, UserName)组合是一个独立分组,现在因为同一个组合下存在多条不同时间的执行记录,分组后行数直接膨胀。要解决这个问题,我们需要把统计点击次数和获取最新时间字段这两个逻辑分开处理,再合并结果,这样就能保持原来的200行结构。
方案一:用窗口函数精准获取最新记录
这个方案通过CTE拆分逻辑,先统计总点击数,再给每个分组的执行记录按时间排序,取最新的那一条的时间字段:
WITH ReportHitStats AS ( -- 保留原逻辑,统计每个分组的总点击次数,确保行数还是200行 SELECT els.ReportID, COUNT(*) AS HitCount, c.Name, els.UserName FROM [SP_RPT_SVC].[dbo].ExecutionLogStorage els INNER JOIN Catalog c ON els.ReportID = c.ItemID WHERE c.[Type] = 2 GROUP BY els.ReportID, c.Name, els.UserName ), LatestReportExecutions AS ( -- 给每个分组的执行记录按时间降序排序,最新的记录标记为rn=1 SELECT els.ReportID, els.UserName, els.TimeStart, els.TimeDataRetrieval, ROW_NUMBER() OVER (PARTITION BY els.ReportID, els.UserName ORDER BY els.TimeStart DESC) AS rn FROM [SP_RPT_SVC].[dbo].ExecutionLogStorage els INNER JOIN Catalog c ON els.ReportID = c.ItemID WHERE c.[Type] = 2 ) -- 合并统计结果与最新时间字段 SELECT rhs.ReportID, rhs.HitCount, rhs.Name, rhs.UserName, lre.TimeStart, lre.TimeDataRetrieval, y.DirName, y.LeafName, z.PreferredName FROM ReportHitStats rhs LEFT JOIN LatestReportExecutions lre ON rhs.ReportID = lre.ReportID AND rhs.UserName = lre.UserName AND lre.rn = 1 -- 只取每个分组的最新记录 LEFT JOIN [SP_BI].[dbo].[AllDocs] y ON y.ID = rhs.ReportID LEFT JOIN [SP_ProfileDB].[dbo].[UserProfile_Full] z ON rhs.UserName = z.NTName;
方案二:先找最大时间再关联
如果你的场景中TimeStart的唯一性有保障,也可以先找到每个分组的最大时间,再关联回原表获取对应字段:
WITH ReportHitStats AS ( -- 原统计逻辑不变 SELECT els.ReportID, COUNT(*) AS HitCount, c.Name, els.UserName FROM [SP_RPT_SVC].[dbo].ExecutionLogStorage els INNER JOIN Catalog c ON els.ReportID = c.ItemID WHERE c.[Type] = 2 GROUP BY els.ReportID, c.Name, els.UserName ), MaxTimePerGroup AS ( -- 找到每个分组的最新TimeStart SELECT els.ReportID, els.UserName, MAX(els.TimeStart) AS MaxTimeStart FROM [SP_RPT_SVC].[dbo].ExecutionLogStorage els INNER JOIN Catalog c ON els.ReportID = c.ItemID WHERE c.[Type] = 2 GROUP BY els.ReportID, els.UserName ) SELECT rhs.ReportID, rhs.HitCount, rhs.Name, rhs.UserName, els.TimeStart, els.TimeDataRetrieval, y.DirName, y.LeafName, z.PreferredName FROM ReportHitStats rhs LEFT JOIN MaxTimePerGroup mtpg ON rhs.ReportID = mtpg.ReportID AND rhs.UserName = mtpg.UserName -- 关联回原表获取对应时间字段 LEFT JOIN [SP_RPT_SVC].[dbo].ExecutionLogStorage els ON mtpg.ReportID = els.ReportID AND mtpg.UserName = els.UserName AND mtpg.MaxTimeStart = els.TimeStart LEFT JOIN [SP_BI].[dbo].[AllDocs] y ON y.ID = rhs.ReportID LEFT JOIN [SP_ProfileDB].[dbo].[UserProfile_Full] z ON rhs.UserName = z.NTName;
注意事项
如果同一个分组下存在多条记录共享最大TimeStart的情况,方案二可能会导致行数增加,这时候可以在最后关联原表时嵌套一个窗口函数(参考方案一的ROW_NUMBER()逻辑),确保每个分组只取一条记录。
内容的提问来源于stack exchange,提问作者Green Code




