SQL Server 2017:如何依据最后记录值替换所有历史值
解决SQL Server 2017中基于Person最后交易状态生成布尔列的问题
我来帮你搞定这个需求!你需要根据每个Person的最后一条交易记录的Status,生成is_Open和is_Closed两个布尔列,咱们一步一步来实现。
核心思路
要实现这个需求,我们需要先获取每个Person的最后一条交易记录的状态及对应日期,再将这个结果关联回原表,结合两条规则判断每条记录的布尔值:
is_Open:仅当Person的最后状态是Open,且当前记录是该Person的最后一条交易时,值为1,其余情况为0is_Closed:仅当Person的最后状态是Closed,且当前记录是该Person的最后一条交易时,值为1,其余情况为0
完整解决方案代码
declare @T1 table ( ClaimID int, Person varchar(20), TransactionDate date, Status varchar(20) ) insert into @T1 values (1, 'Person1', '2018-03-05','Open') ,(1, 'Person2', '2018-03-10','Open') ,(1, 'Person2', '2018-03-15','Closed') ,(2, 'Person3', '2018-03-15','Open') ,(2, 'Person3', '2018-03-23','Closed') ,(3, 'Person4', '2018-04-18','Closed') ,(4, 'Person5', '2018-04-23','Open') ,(4, 'Person5', '2018-04-25','Open') -- 使用CTE获取每个Person的最后交易状态和日期 WITH PersonLastTransaction AS ( SELECT Person, Status AS LastStatus, TransactionDate AS LastTransactionDate, -- 给每个Person的交易按日期倒序排号,第1条就是最后一条交易 ROW_NUMBER() OVER (PARTITION BY Person ORDER BY TransactionDate DESC) AS RowRank FROM @T1 WHERE TransactionDate <= '2018-12-31' ) SELECT t.*, -- 计算is_Open列 CASE WHEN plt.LastStatus = 'Open' AND t.TransactionDate = plt.LastTransactionDate THEN 1 ELSE 0 END AS is_Open, -- 计算is_Closed列 CASE WHEN plt.LastStatus = 'Closed' AND t.TransactionDate = plt.LastTransactionDate THEN 1 ELSE 0 END AS is_Closed FROM @T1 t -- 关联每个Person的最后交易信息 JOIN PersonLastTransaction plt ON t.Person = plt.Person AND plt.RowRank = 1 WHERE t.TransactionDate <= '2018-12-31' ORDER BY t.ClaimID, t.TransactionDate;
为什么你的尝试没生效?
你之前用LAST_VALUE的问题主要有两点:
- 窗口框架默认行为限制:
LAST_VALUE默认的窗口框架是RANGE BETWEEN CURRENT ROW AND CURRENT ROW,只会取当前行的值,而非整个Person分区的最后一条记录状态。如果要让它取到整个分区的最后状态,需要显式指定窗口框架:LAST_VALUE(Status) OVER (PARTITION BY Person ORDER BY TransactionDate DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) - 缺少最后记录判断:就算正确获取了最后状态,还需要判断当前记录是否是该Person的最后一条交易,否则会出现所有记录都根据最后状态赋值的情况,不符合“仅最后一条记录为1,其余为0”的规则。
测试结果
运行上述代码后,输出完全符合需求:
| ClaimID | Person | TransactionDate | Status | is_Open | is_Closed |
|---|---|---|---|---|---|
| 1 | Person1 | 2018-03-05 | Open | 1 | 0 |
| 1 | Person2 | 2018-03-10 | Open | 0 | 0 |
| 1 | Person2 | 2018-03-15 | Closed | 0 | 1 |
| 2 | Person3 | 2018-03-15 | Open | 0 | 0 |
| 2 | Person3 | 2018-03-23 | Closed | 0 | 1 |
| 3 | Person4 | 2018-04-18 | Closed | 0 | 1 |
| 4 | Person5 | 2018-04-23 | Open | 0 | 0 |
| 4 | Person5 | 2018-04-25 | Open | 1 | 0 |
内容的提问来源于stack exchange,提问作者Serdia




