SQL 服务器游标与交叉应用

SQL SERVER CURSOR VS CROSS APPLY

我有 BatchDetail table 作为

对于每一行,我都想检查总值是否为负并更新一个标志,以便在进一步处理时不会考虑这些行。我采取了以下方法

  • 获取总值为正的所有行,即 pid 为 1、3、5、6 的行。

  • 使用游标并使用 BatchDetail 逐一检查以找到相应的负总数并更新这些行。

  • 由于 batch_detail table 有上万行,因此这种方法花费了太多时间。因此,在谷歌搜索之后,我决定使用 CROSS APPLY,其中我采用了与 batchDetail table 相同的列的 temp table 加上作为 newPid 的新列,插入的行具有正总数并交叉应用批次详细信息 table 如:
  • UPDATE TEMP_TABLE  
    SET TEMP_TABLE.NEWPID=TEMP.PID,TEMP_TABLE.FLAG=1 
    FROM TEMP_TABLE T CROSS APPLY 
    (SELECT * FROM BATCH_DETL_TBL 
     WHERE LOAN_NUMBER=T.LAON_NUMBER AND TOTAL=-T.TOTAL)) TEMP
    

    问题是,一旦 pid 3(总计 50)的行与 pid 4(总计 -50)匹配,pid 4 行不应再次与 pid 5 行匹配。因此,一旦更新了具有正数和负数的行,就不应考虑下一组行。

    你可以只使用join,但是你需要一个序列号来匹配total

    UPDATE TEMP_TABLE
        SET TEMP_TABLE.NEWPID = TEMP.PID,
            TEMP_TABLE.FLAG = 1
        FROM (SELECT t.*,
                    row_number() over (partition by total order by (select null)) as seqnum
              FROM TEMP_TABLE T
             ) t JOIN
             (SELECT dt.*,
                     row_number() over (partition by total order by (select null)) as seqnum
              FROM BATCH_DETL_TBL dt
             ) dt
             on dt.LOAN_NUMBER = T.LOAN_NUMBER AND
                dt.TOTAL = -T.TOTAL AND
                dt.seqnum = T.seqnum;
    

    这应该比游标快得多(建议:避免使用游标,除非你真的别无选择)。 cross applyjoin 的性能应该相似。为了性能,您还可以在 batch_detl_tbl(load_number, total).

    上添加索引

    这是一个棘手的问题。对于每个唯一的正总数,您必须按照该总数对所有记录进行排序,并独立地对具有该总数的 负数 的所有记录进行排序,以便您可以将它们匹配起来。这确保每条记录只匹配一次。

    以下是使用您的测试数据完成的方法:

    create table t1 (loan_number int, pid int, total int, newPid int, flag int );
    insert into t1 (loan_number, pid, total ) values (411001,1,100), (411001,2,-100), (411001,3,50), (411001,4,-50), (411001,5,50), (411001,6,25);
    update pos set newPid=neg.pid, flag=1 from
        ( select loan_number, pid, total, 
                 row_number() over (partition by total order by pid) rn 
          from t1 
          where total>0) pos
        inner join 
        (select loan_number, pid, total, 
                row_number() over (partition by total order by pid) rn 
                from t1 
                where total<0) neg 
        on  neg.loan_number = pos.loan_number 
        and neg.total =- pos.total 
        and neg.rn = pos.rn
    ;