我正在进行数据迁移(SQL Server 2012),在脚本中的某一点上,我的所有行都是这样的(只是显示一个客户ID的数据集,并截短日期):
CustTxnID CustomerID TransDate PmtActID
1964237 385120 10/2/2016 12820
1964529 385120 10/3/2016 NULL
2003082 385120 11/2/2016 NULL
2041647 385120 12/2/2016 NULL
2060535 385120 12/16/2016 10890
2060926 385120 12/17/2016 NULL
2081969 385120 1/2/2017 NULL
2128232 385120 2/2/2017 NULL
2173356 385120 3/2/2017 NULL
我要对每一个具有NULL PmtActID的行进行更新,更新PmtActID以匹配存储在具有PmtActID值的第一行之前存储的值。因此,例如,将使用PmtActID 12820更新CustTxnID 1964529、2003082和2041647,并将其他具有空PmtActID的行更新为10890。
一些说明可能会有所帮助...我们知道,到目前为止,该客户的最早交易具有PmtActID值。我们还知道交易是按时间顺序插入的。
我尝试了几种方法来生成正确的数据,但不仅它们表现不佳(事务表有大约400万行),而且还感到“错误”。我觉得这里有一个简单的解决方案,我忽略了。
一种方法是连接到txn表,然后是一个子查询,该子查询收集了所有可能的匹配项(具有PmtActID的行,其TransDate <当前行的TransDate,由Max(CustTxnID)排序以找到最接近的行)...另一种方法是排序具有一个pmtactid的行,然后为空行选择一个计数,该计数包含一个在它们之前的pmtactid的行数(这将与序列匹配)...等等等等。但是非常简单地,我强烈怀疑我是缺少一些简单的东西,肯定会比我一直在做的更好。
有什么想法吗?
更新我是根据戈登的回复尝试的:
SELECT
T.CustomerID
,T.CustomerTransactionID
,T.TransDate
,T.PaymentAccountID
,first_value(T.PaymentAccountID) over (
partition by CustomerID
order by
(case when PaymentAccountID is null then 1 else 2 end) desc,
transdate desc ) AS new_pmtActId
FROM
CustomerTransaction T
WHERE
T.CustomerID=385120
ORDER BY
TransDate desc
(请注意,此处我使用完整的列名而不是缩写),但使用此列,每行收到10890。
答案 0 :(得分:0)
您可以使用first_value()
获取先前的值,然后使用可更新的CTE:
with toupdate as (
select t.*,
max(pmtActId) over (partition by CustomerID, transdate_notnull) as new_pmtActId
from (select t.*,
max(case when pmtActId is not null then transdate end) over (partition by customerid order by transdate) as transdate_notnull
from t
) t
)
update toupdate
set pmtActId = new_pmtActId
where pmtActId is null;
当然,在进行update
之前,请先测试CTE,以确保这些值符合您的预期。
标准SQL具有带有lag()
的构造ignore nulls
。但是,SQL Server无法实现它。
Here是一个学期。