【问题标题】:Update value based on value in previous row根据上一行中的值更新值
【发布时间】:2021-04-13 22:25:44
【问题描述】:

我有下表:

CREATE TABLE dbo.Persons 
(
     [Date] date null, 
     [PersonId] int null, 
     [Amount] int null, 
     [Value] int null
)

这里有一些示例数据:

INSERT INTO dbo.Persons ([Date], [PersonId], [Amount], [Value])
VALUES
('2020-01-01', 1, 200, NULL),
('2020-01-02', 1, 300, NULL),
('2020-01-03', 1, 400, NULL),
('2020-01-04', 1, 500, NULL),
('2020-01-01', 2, 200, NULL),
('2020-01-02', 2, 300, NULL),
('2020-01-03', 2, 400, NULL),
('2020-01-04', 2, 500, NULL),
('2020-01-01', 3, 0, NULL),
('2020-01-02', 3, 0, NULL),
('2020-01-03', 3, 0, NULL),
('2020-01-04', 3, 0, NULL)

我的目标:根据其他列中的值和 [Value] 列中的先前值更新 [Value] 列中的所有值。主键是date+personId

用伪代码解释,我的逻辑需要如下:

CASE 
    WHEN [Amount] > 200 AND previous row value IN [Value] = 1, then 2
    WHEN [Amount] > 500 AND previous row value in [Value] = 2, then 3
    WHEN [Date] > '2020-01-01' AND [Amount] = 500 AND previous row value in [Value] = 2, then 4

等等 - 这捕获了一般的 T-SQL 代码逻辑..

我只想更新 [Value] 列,其中 [Value] 也是 NULL。

这里有什么戏?我读过有关使用 LAG、While LOOP、递归 CTE 等的信息,但不确定该去哪里。

【问题讨论】:

    标签: sql-server tsql recursion sql-update


    【解决方案1】:

    您可以使用lag 来引用前一行的值。在您的示例数据中,value 将保持为 null,尽管您的 case 逻辑取决于前一行,即 null 开始。

    但是,您可以通过可更新的 CTE 来处理它

    with u as (
        select [Date], PersonId,
        case
            when Amount > 200 and Lag(Value) over(partition by PersonId order by [Date]) = 1 then 2
            when Amount > 500 and Lag(Value) over(partition by PersonId order by [Date]) = 2 then 3
            when [Date] > '20200101' and Amount = 500 and Lag(Value) over(partition by PersonId order by [Date])= 2 then 4
        end NewValue
        from Persons
    )
    update u set Value = NewValue;
    

    【讨论】:

      【解决方案2】:

      您可以添加行号,然后自行加入。您可以将此想法扩展到第 2 行、第 3 行等。

      With Qry1 (
          Select  -- Columns from Person table
                  , ROWNUMBER() OVER(PARTITION BY PersonId ORDER BY Date) As Seq
          FROM Persons
      )
      Select  -- Columns from ThisRow
              -- Columns from PrevRow (values will be null if there is
              -- no previous row for this PersonId and Date)
      FROM Qry1 ThisRow
      LEFT JOIN Qry1 PrevRow
      ON ThisRow.PersonId = PrevRow.PersonId
      AND ThisRow.Date = PrevRow.Date
      AND ThisRow.Seq - 1 = PrevRow.Seq 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多