在SQL Server中使用CURSOR计数下降尝试

Abu*_*iaz 1 sql t-sql sql-server

嗨,我陷入了这个问题,我在SQL SERVER中通过CURSOR工作了一个解决方案,但是我的行大约是40万,并且输出要花费数小时,有人可以更快地做到这一点吗?也许通过CROSS APPLY或其他方式。谢谢

问题:仅需要对事务状态“已拒绝”进行计数,如果TransactionStatus为“已批准”,则计数器将重置为零。

交易记录

帐号卡号交易状态输入日期
10845522-XYZ 5471XXXXXXXX1111已批准10/09/2013
10845522-XYZ 5471XXXXXXXX1111拒绝10/09/2014
10845522-XYZ 5471XXXXXXXX1111拒绝10/09/2015
10845522-XYZ 5471XXXXXXXX9999已批准10/09/2016
10845522-ABC 5471XXXXXXXX6666拒绝10/09/2012
10845522-ABC 5471XXXXXXXX6666拒绝10/09/2019
10845522-DEF 5471XXXXXXXX7777拒绝10/09/2016
10845522-DEF 5471XXXXXXXX7777已批准10/09/2019

需要的输出

帐号卡号拒绝计数器修改日期
10845522-XYZ 5471XXXXXXXX1111 2 10/09/2015
10845522-XYZ 5471XXXXXXXX9999 0 2016年10月9日
10845522-ABC 5471XXXXXXXX6666 2 10/09/2019
10845522-DEF 5471XXXXXXXX7777 0 10/09/2019

我的带有游标和合并语句的代码/方法,可以正常工作,但是由于CURSOR而需要花费数小时才能完成

-- Main Transaction Table
Select row_number() Over(Order by EntryDate) RowNumber
,Account, CARD_NUMBER, TransactionStatus, EntryDate
into dbo.TransactionLog_Temp
from dbo.TransactionLog


-- Cursor
DECLARE @RowNumber AS INT
DECLARE C CURSOR FOR
        Select Rownumber from dbo.TransactionLog_Temp order by Rownumber ASC

OPEN C

FETCH NEXT FROM C INTO @RowNumber;

    WHILE @@FETCH_STATUS = 0
    BEGIN

    -- Decide Update or Insert
    MERGE INTO dbo.Declined_Counter_Table AS T
    USING (Select Account,TransactionStatus,CARD_NUMBER,EntryDate 
    from TransactionLog_Temp where Rownumber=@RowNumber) S ON T.Account=S.Account AND T.CARD_NUMBER=S.CARD_NUMBER
        WHEN MATCHED AND T.ModifiedDate<>S.EntryDate
            THEN UPDATE SET T.[Counter] = CASE WHEN S.TransactionStatus ='Declined' THEN ISNULL(T.[Counter],0) + 1
                                                WHEN S.TransactionStatus ='Approved' THEN 0 END
                    ,T.ModifiedDate = S.EntryDate                             
        WHEN NOT MATCHED BY TARGET AND S.TransactionStatus ='Declined'
            THEN INSERT VALUES (S.Account, S.CARD_NUMBER,1, S.EntryDate);

    -- remove from main table, to resume the query anyother time since its taking too long
        Delete from dbo.TransactionLog_Temp where Rownumber=@RowNumber

    print @RowNumber
        FETCH NEXT FROM C INTO @RowNumber;
    END;

CLOSE C;
DEALLOCATE C; 
Run Code Online (Sandbox Code Playgroud)

Gor*_*off 5

您似乎想要一个聚合:

Select Account, CARD_NUMBER,
       sum(case when TransactionStatus = 'Declined' then 1 else 0 end) as num_all_declines,
       sum(case when TransactionStatus = 'Declined' and
                     (EntryDate > last_approved_ed or last_approved_ed is null
                     )
                then 1 else 0 
           end) as num_recent_declines,           
       max(EntryDate)
from (select tl.*,
             max(case when TransactionStatus = 'Approved' then EntryDate end) over (partition by Account, CARD_NUMBER) as last_approved_ed
      from dbo.TransactionLog tl) query
group by Account, CARD_NUMBER;
Run Code Online (Sandbox Code Playgroud)

这比尝试使用游标要快得多。