You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动