SQL SERVER CURSOR VS CROSS APPLY

时间:2015-03-20 11:13:46

标签: sql sql-server tsql join cursor

我有BatchDetail表作为

Batch Detail table

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

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

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

  • 这种方法花费了太多时间,因为batch_detail表有十万行。因此在谷歌搜索之后我决定使用CROSS APPLY,其中我将临时表与batchDetail表相同的列加上新列作为newPid,插入的行为正总数,交叉应用批处理详细信息表为:
  • 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
    

    Result

    问题是,一旦pid 3(总共50)与pid 4(总共-50)匹配,pid 4行不应再与pid 5行匹配。因此,一旦更新了positve和negative amount的行,就不应该考虑下一组行。

    2 个答案:

    答案 0 :(得分:1)

    这是一个棘手的问题。对于每个唯一的正数,您必须订购具有该总数的所有记录,并使用该总计的否定独立订购所有记录,以便您可以匹配它们。这样可以确保每条记录仅匹配一次。

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

    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
    ;
    

    答案 1 :(得分:0)

    您可以使用join,但需要一个序列号来匹配total s:

    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)上添加索引。

    相关问题