我有下表:
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 等的信息,但不确定该去哪里。
答案 0 :(得分:0)
您可以使用 lag
来引用前一行的值。在您的示例中,数据 value
将保留为 null
,因为您的 case
逻辑取决于从 null
开始的前一行。
但是,这就是你可能的处理方式
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 [Value]
from Persons
)
update p set
p.Value=u.Value
from u join Persons p on p.[Date]=u.[Date] and p.PersonId=u.PersonId
答案 1 :(得分:0)
您可以添加行号,然后自连接。您可以将此想法扩展到 Row-2、Row-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