TSQL-使用值查找上一行并更新初始行

时间:2018-07-14 23:35:30

标签: sql sql-server tsql sql-server-2012

我正在进行数据迁移(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。

1 个答案:

答案 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是一个学期。