将增量值更新为一组行的SQL表中的列

时间:2019-01-23 12:25:06

标签: sql-server tsql

我遇到一种情况,我必须根据同一记录组的上一行中同一列上的值,将增量值更新为一列。

Initial Table

“ COUNT”列的更新规则为:

For the very 1st row of a particular REFNO, 
If Amount 1 = Amount 2 then 
   COUNT = 1 
Else 
   COUNT = 0

对于特定REFNO的所有其他行(第一行除外):

If Amount 1 = Amount 2 then
   COUNT = COUNT from previous row for the same REFNO + 1
Else  
   COUNT = COUNT from previous row for the same REFNO 

因此结果应如下所示:

After Update

尽管我显示的样本数据只有14条记录,但我要更新的实际表中将有几百万行。因此,我正在寻找一种解决方案,该解决方案将执行基于集合的更新,而不是逐行处理!!

3 个答案:

答案 0 :(得分:2)

您可以从使用window functions计算数字的CTE中进行更新。

下面的SQL首先计算相等数量的row_number。
然后,对于其他数量不相等的其他对象,采用前一个row_number的最大值。

WITH CTE AS
(
    SELECT *, 
    (CASE 
     WHEN [Amount 1] = [Amount 2] 
     THEN rn 
     ELSE MAX(rn) OVER (PARTITION BY [REFNO] ORDER BY [ROW ID] ASC ROWS UNBOUNDED PRECEDING) 
     END) as rnk
    FROM (
      SELECT 
       [ROW ID], [REFNO], [Amount 1], [Amount 2], [COUNT],
       (CASE 
        WHEN [Amount 1] = [Amount 2] 
        THEN ROW_NUMBER() OVER (PARTITION BY [REFNO], IIF([Amount 1] = [Amount 2],0,1) ORDER BY [ROW ID] ASC) 
        ELSE 0 
        END) AS rn
      FROM PAYMENT
    ) q
)
UPDATE CTE
SET [COUNT] = rnk;

db <>小提琴here

的测试

答案 1 :(得分:0)

尝试

declare @t table (
    rowid int identity,
    refno int,
    amount1 int,
    amount2 int

)
insert into @t(refno,amount1,amount2) values (1000000,100,200)
insert into @t(refno,amount1,amount2) values (1000000,250,250)
insert into @t(refno,amount1,amount2) values (1000000,300,300)
insert into @t(refno,amount1,amount2) values (1000000,400,400)
insert into @t(refno,amount1,amount2) values (1000010,400,100)
insert into @t(refno,amount1,amount2) values (1000010,200,100)
insert into @t(refno,amount1,amount2) values (1000010,100,300)
insert into @t(refno,amount1,amount2) values (1000021,400,400)
insert into @t(refno,amount1,amount2) values (1000021,200,100)
insert into @t(refno,amount1,amount2) values (1000032,200,200)
insert into @t(refno,amount1,amount2) values (1000032,300,300)
insert into @t(refno,amount1,amount2) values (1000033,200,100)
insert into @t(refno,amount1,amount2) values (1000033,200,100)

select rowid,refno,amount1,amount2,rw-1 as count
from (
select
    row_number() over(partition by amount1,amount2 order by rowid) rw,*
from @t) as src

答案 2 :(得分:0)

此代码适用于该特定集合,但不能保证在某些情况下它不起作用:

CREATE TABLE  #tmp(
    RowID INT IDENTITY(1,1), 
    RefNo INT,
    Amount1 INT,
    Amount2 INT
)

INSERT INTO #tmp(RefNo,Amount1,Amount2) 
SELECT * FROM (VALUES
(100000,100,200),
(100000,250,250),
(100000,300,300),
(100000,400,400),
(100000,400,100),
(100010,200,100),
(100010,100,300),
(100010,400,400),
(100021,200,100),
(100021,200,200),
(100032,300,300),
(100032,200,100),
(100033,200,100),
(100033,200,100)) AS x(a,b,c)

;WITH Try1 AS (SELECT t1.*, [Count] = 
            CASE WHEN t1.Amount1 != t1.Amount2 AND 
                (t2.RowId IS NULL OR t2.Amount1 != t2.Amount2) THEN 0 
                WHEN t1.Amount1 != t1.Amount2 AND t2.Amount1 = t2.Amount2 THEN t2.RowId
                WHEN t1.Amount1 = t1.Amount2 AND t2.RowId IS NULL THEN t1.RowId
                WHEN t1.Amount1 = t1.Amount2 AND t2.RowId IS NOT NULL THEN t1.RowId 
            END
            , NextRefNo = CASE WHEN t2.RowId IS NULL THEN 1 ELSE 0 END
    FROM #tmp AS t1
    OUTER APPLY ( SELECT * FROM #tmp AS t2 
        WHERE t2.RowId = t1.RowID - 1 AND t2.RefNo = t1.RefNo) AS t2)
, Try2 AS (SELECT RowID, RefNo, Amount1, Amount2, [Count]
                , NextRefNo = ISNULL(t2.NextRefNo,0)
            FROM Try1 AS t1
            OUTER APPLY ( SELECT NextRefNo FROM Try1 AS t2 
                WHERE t2.[Count] > 0 AND t2.NextRefNo = 1 
                    AND t2.RefNo = t1.RefNo ) AS t2)
SELECT RowID, RefNo, Amount1, Amount2
    , [Count] = DENSE_RANK() OVER(PARTITION BY RefNo ORDER BY [Count]) - 1 + NextRefNo
FROM Try2
ORDER BY RowID;