【问题标题】:How to Update a table using transaction logs row by row using dynamic SQL Server stored procedure如何使用动态 SQL Server 存储过程使用事务日志逐行更新表
【发布时间】:2021-07-29 03:48:46
【问题描述】:

我有一个表格,其中显示了Ticket ID 及其状态以及在 BI 数据库上分配给谁。这里没有重复和粒度是每张票。

Ticket_ID   Status  Assigned_To   Date
--------------------------------------------------
001         Open    Team A        01/01/2020 10:01
002         Working Team B        01/01/2020 10:01
003         Open    Team C        02/01/2020 18:50
004         ResolvedTeam B        02/01/2020 19:22

现在,有一个包含每个更改的每日交易日志。然而,列 更改显示为如下行。

每日交易记录

Ticket_id     Field_Name        New Value     Date
---------------------------------------------------------------
001           Assigned_to       Team B        02/01/2020 10:23
002           Assigned_to       Team A        02/01/2020 10:23
002           Status            Resolved      02/01/2020 10:24
003           status            Resolved      03/01/2020 10:24
004           Assigned_to       Team C        03/01/2020 13:50
004           Assigned_to       Team A        03/01/2020 13:51
004           Status            Resolved      03/01/2020 13:51

现在我想使用动态 SQL 脚本编写一个更新脚本,使用游标(我想这是最好的方法)根据日志上的新值更新 Ticket 表。我需要 SQL 脚本逐行处理事务日志表并使用新值更新 Ticket 表。

预期输出如下:

Ticket_ID     Status     Assigned_To  Date
------------------------------------------------------
001           Open       Team B       02/01/2020 10:23
002           Resolved   Team A       02/01/2020 10:24
003           Resolved   TeamC        03/01/2020 10:24
004           Resolved   Team A       03/01/2020 13:51

【问题讨论】:

  • 为什么你认为你需要动态 sql 或游标?这是一个简单的基于集合的查询。您是否真的使用了几乎不支持或根本不支持的两个版本的 sql server?
  • @Stu 我可能错了,我使用 OpenQuery 从 Oracle 获取每日日志。有9种不同的状态变化而不仅仅是2种。所以比这复杂一点。谢谢
  • 我也不明白您为什么要在此处使用光标,您可以在单个 update 中执行此操作。 Date 列是否也会更新?所有相关列的数据类型是否相同?
  • 固定数量的状态更改(列名)不需要动态。这是一个普通的 sql,虽然有点冗长。
  • @Serg 是的,日期列也会更新。所以,我可能错了,你能提出你的建议吗

标签: sql sql-server-2012 sql-server-2008-r2


【解决方案1】:

种类

update t
set
   Status = case log.Field_Name when 'Status' then log.NewValue else t.Status end,
   ...
   Assigned_To = case log.Field_Name when 'Assigned_To' then log.NewValue else t.Assigned_To end,
   Date = log.LastDate
from tickets t
join ( -- take only last row for Ticket_id + Field_Name
   select top(1) with ties Ticket_id, Field_Name, NewValue, 
         max(Date) over (partition by Ticket_id) LastDate
   from DailyLog
   order by row_number() over(partition by Ticket_id, Field_Name order by Date desc)
  ) log on t.Ticket_ID = log.Ticket_ID

【讨论】:

    【解决方案2】:

    所以这是一个可以用作模板的解决方案,只需修改您拥有的其他类型的日志操作。

    首先删除不必要的重复项,只保留每张票的最终状态,然后转入每个属性的列,最后加入 tickets 进行更新。

    好的,所以可能不是那么简单,但不需要光标:)

    with l as (
        select *, Row_Number() over(partition by Ticket_id, Field_Name order by [date] desc)rn
        from TransactionLogs
    ), u as (
    select l.ticket_id,
        Max(case when field_name='status' then newvalue end) [Status],
        Max(case when field_name='assigned_to' then newvalue end) Assigned_to,
        /* Add additionalfield name properties here */
        Max(l.[date]) [Date]
    from l 
    where l.rn=1 
    group by l.ticket_id
    )
    
    update t set
        t.[status]=IsNull(u.[status],t.[status]),
        t.Assigned_To=IsNull(u.Assigned_to,t.Assigned_To),
        /* Include additional columns here */
        t.[date]=isnull(u.[date],t.[date])
    from u join tickets t on t.Ticket_Id=u.Ticket_id;
    

    working fiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2017-01-26
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多