SQL Server - 选择最近的记录以生成更改列表

Posted

技术标签:

【中文标题】SQL Server - 选择最近的记录以生成更改列表【英文标题】:SQL Server - Selecting Most Recent Record to generate a list of changes 【发布时间】:2009-08-06 15:32:13 【问题描述】:

情况如下:

我有一个“票证”数据库,每次保存票证时,我们都会跟踪票证的更改。我特别关注状态变化,其跟踪格式如下:

状态:FROM:TO

FROM 和 TO 更改为各自的状态。我需要做的是在任何给定的一周结束时,比如过去 12 周,按周生成“开放”(意味着处于草稿状态)的票数。但是,您不限于“关闭”工单然后重新打开它,或者在一周内进行多项更改。

所以,我需要做的是修改下面的 SQL,只考虑任何给定条目的最新“操作”。通过这种方式,我们避免了“关闭”的条目出现在打开计数中的问题,因为它们之前被打开过。

SELECT track.historyID
      FROM RS_HistoryTracker track 
     WHERE (track.action = 'STATUS:INITIAL:DRAFT'
            OR track.action = 'STATUS:DELETED:DRAFT'
            OR track.action = 'STATUS:DRAFT:DRAFT')
       AND track.trackDateTime <= @endOfWeek

但是,此语句包含在另一个 select 语句中,用于生成历史项目的完整列表:

    SELECT COUNT(DISTINCT his.historyID) AS theCount
  FROM RS_History his
 WHERE his.historyID IN 
       (SELECT track.historyID
          FROM RS_HistoryTracker track 
         WHERE (track.action = 'STATUS:INITIAL:DRAFT'
                OR track.action = 'STATUS:DELETED:DRAFT'
                OR track.action = 'STATUS:DRAFT:DRAFT')
           AND track.trackDateTime <= @endOfWeek) 

那么,如何让内部选择仅考虑在 endOfWeek 日期之前或当天发生的最近跟踪的“操作”? HistoryTracker 包含一个日期时间戳列。

【问题讨论】:

我认为您在表格轨道中有一个工单 ID 字段。所以本质上你想加入一个包含每个票证 ID 的最大历史记录 ID 的结果集。 是的,我们确实在跟踪表中跟踪票证 ID 至于最大历史ID,可能不是这样。如果我在 3 个月前运行一周的查询,我需要最新的历史记录项,直到并包括该周的结束日期,同时忽略该周之后发生的所有历史记录项。 问题是最近的历史ID,即使受日期限制,也可能不指示状态更改。如果他们更改多个字段,它将生成多个跟踪操作行。 【参考方案1】:

适用于 SQL Server 2005+:

WITH history AS (
  SELECT rh.historyID,
         MAX(rh.action) 'action'
    FROM RS_HISTORYTRACKER rh 
   WHERE rh.action IN ('STATUS:INITIAL:DRAFT', 'STATUS:DELETED:DRAFT', 'STATUS:DRAFT:DRAFT')
     AND rh.trackDateTime <= @endOfWeek)
SELECT COUNT(DISTINCT t.historyID) AS theCount
  FROM RS_HISTORY t
  JOIN history h ON h.historyi = t.historyid

使用查询的替代、非 CTE:

SELECT COUNT(DISTINCT t.historyID) AS theCount
  FROM RS_HISTORY t
  JOIN (SELECT rh.historyID,
               MAX(rh.action) 'action'
          FROM RS_HISTORYTRACKER rh 
         WHERE rh.action IN ('STATUS:INITIAL:DRAFT', 'STATUS:DELETED:DRAFT', 'STATUS:DRAFT:DRAFT')
          AND rh.trackDateTime <= @endOfWeek) h ON h.historyi = t.historyid

【讨论】:

我仍然有一个问题,如果最近的状态更改是 STATUS:%:FINAL,这似乎没有出现,这不会包括它。不过,这是一个好的开始,让我思考。 如果 IN 子句仅获得 INITIAL:DRAFT、DELETED:DRAFT 或 DRAFT:DRAFT,它怎么能包括 FINAL?或者 final 是 RS_HISTORY 表上的列/属性? 对不起,你是对的。我在窗口中查看了错误的代码。【参考方案2】:

作为初学者,您可以通过执行以下操作找到每张票的最后一个历史记录项

select * from
(
    --find max history id for each ticket
    select 
        T1.ticketId, 
        max(T1.historyId) As LastHistoryId
    from #Ticket T1
    --add WHERE clause to filter out dates
    group by 
       T1.ticketId
) MaxTicket

inner join 
#Ticket T2 --find the ticket so you can get the status
on MaxTicket.ticketId = T2.ticketId 
and MaxTicket.LastHistoryId=T2.Historyid

您可能希望更改根据日期而不是历史 ID 查找最新票证的方式。

【讨论】:

添加了一个“LIKE”子句来过滤掉不处理状态的更新。工作日期。感谢您的建议 historid 是一个外键——在它上面做聚合函数没有任何价值,它们总是一样的。【参考方案3】:

这个问题在 *** 上有很多变体,这是我发现的第一个 :)

sql-query-to-get-most-recent-row-for-each-instance-of-a-given-key

基本上您确实需要分两部分进行。 - 使用一个查询来查找每个项目的最新时间戳 - 使用另一个查询来完成您打算做的工作

查找在给定日期之前仍处于打开状态的所有项目:

SELECT
  [data].*
FROM
  track AS [data]
WHERE
  [data].trackDateTime =
    (
       SELECT
          MAX(trackDateTime)
       FROM
          track
       WHERE
          track.ticketID = [data].ticketID
          AND track.DateTime < @endOfWeek
    )
  AND track.action IN ('STATUS:INITIAL:DRAFT','STATUS:DELETED:DRAFT','STATUS:DRAFT:DRAFT'))

这假定 ticketID 是每张票的唯一标识符。 (基于你的一个 cmets)

【讨论】:

【参考方案4】:

看起来这样可行:

  SELECT query.historyID
    FROM
    (SELECT MAX(track.trackID) AS maxTrackID, track.historyID
    FROM RS_HistoryTracker track
    WHERE track.trackDateTime <= '2009-08-06 23:59:59'
      AND track.action LIKE 'STATUS:%'
    GROUP BY historyID) AS query, RS_HistoryTracker track
    WHERE track.historyID = query.historyID
      AND track.trackID = query.maxTrackID
      AND track.action LIKE 'STATUS:%:DRAFT'

【讨论】:

感谢您的所有建议 - 我将每个建议的一部分和一部分整合到其中。 虽然 LIKE 操作符可以给你一个捷径来缩短代码;严重的是,如果可以避免,请不要使用它。原因是它阻止优化器使用索引,通常会降低性能。 另外,在使用日期范围时只是一个一般性注释,最好使用 ">= @start" 和 " 感谢 cmets。我们使用后天作为生产的结束日期。 LIKE 是一种不幸的需求,因为每组票据集合使用不同的状态,但始终使用草稿。 (数据库严重地没有标准化,但我不是它的开发人员)。

以上是关于SQL Server - 选择最近的记录以生成更改列表的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 中为默认值或绑定生成脚本

SQL Server 选择最近的记录(稍加改动)

SQL Server - 如何显示最近的记录

SQL Server:根据应用程序用户记录数据库更改

如何更改实体框架项目以使用 Microsoft SQL Server

如何使用 SQL Server 更新触发器中的原始值更改第二条记录