如何在SQL中保持滚动校验和?

时间:2010-07-16 15:43:14

标签: sql tsql

我正在尝试保持滚动校验和以考虑订单,因此请使用之前的“校验和”并将其与当前的校验和进行xor并生成新的校验和。

Name      Checksum     Rolling Checksum
------    -----------  -----------------
foo       11829231     11829231
bar       27380135     checksum(27380135 ^ 11829231) = 93291803
baz       96326587     checksum(96326587 ^ 93291803) = 67361090

我将如何完成这样的事情?

(请注意,计算完全弥补,仅供参考)

3 个答案:

答案 0 :(得分:2)

这基本上是running total问题。

修改

我最初声称这是基于光标的解决方案实际上表现最佳的少数几个地方之一。三角形自连接解决方​​案的问题在于它将重复地重新计算与下一步的子计算相同的累积校验和,因此随着所需工作随行数呈指数增长而不能很大程度地扩展。

Corina的回答使用了“古怪的更新”方法。我调整它来做校验和,在我的测试中发现光标解决方案需要3秒而不是26秒。两者都产生了相同的结果。不幸的是,它依赖于Update行为的无证方面。在决定是否在生产代码中依赖于此之前,我肯定会阅读讨论here

第三种可能性描述here(使用CLR)我没有时间测试。但是从the discussion here开始计算运行总类型事物似乎是一种很好的可能性,但是当计算结果必须保存回来时,光标会执行输出。

CREATE TABLE TestTable
(
PK int identity(1,1) primary key clustered,
[Name] varchar(50),
[CheckSum] AS CHECKSUM([Name]),
RollingCheckSum1 int NULL,
RollingCheckSum2 int NULL
)


/*Insert some random records (753,571 on my machine)*/
INSERT INTO TestTable ([Name])
SELECT newid() FROM sys.objects s1, sys.objects s2, sys.objects s3

方法一:基于Jeff Moden文章

DECLARE @RCS int

 UPDATE TestTable
    SET @RCS = RollingCheckSum1 = 
                                 CASE WHEN @RCS IS NULL THEN 
                                                        [CheckSum] 
                                 ELSE 
                                             CHECKSUM([CheckSum] ^ @RCS) 
                                 END
   FROM TestTable WITH (TABLOCKX)
 OPTION (MAXDOP 1)

方法二 - 使用与Hugo Kornelis相同的游标选项来讨论该文章。

SET NOCOUNT ON
BEGIN TRAN

DECLARE @RCS2 INT
DECLARE @PK INT, @CheckSum INT

DECLARE curRollingCheckSum CURSOR LOCAL STATIC READ_ONLY
    FOR
    SELECT PK, [CheckSum]
    FROM         TestTable
    ORDER BY PK

   OPEN curRollingCheckSum

  FETCH NEXT FROM curRollingCheckSum
   INTO @PK, @CheckSum

  WHILE @@FETCH_STATUS = 0
  BEGIN

  SET @RCS2 = CASE WHEN @RCS2 IS NULL THEN @CheckSum ELSE CHECKSUM(@CheckSum ^ @RCS2) END


 UPDATE dbo.TestTable 
    SET RollingCheckSum2 = @RCS2
  WHERE @PK = PK

  FETCH NEXT FROM curRollingCheckSum
   INTO @PK, @CheckSum

    END

COMMIT

测试它们是相同的

SELECT * FROM TestTable
WHERE RollingCheckSum1<> RollingCheckSum2

答案 1 :(得分:1)

Select Name, Checksum
    , (Select T1.Checksum_Agg(Checksum)
        From Table As T1
        Where T1.Name < T.Name) As RollingChecksum
From Table As T
Order By T.Name

要进行滚动操作,您需要对行的顺序有一些相似之处。这可以是名字,整数键,日期或其他。在我的示例中,我使用了名称(即使示例数据中的顺序不是按字母顺序排列的)。另外,我在SQL中使用Checksum_Agg函数。

此外,理想情况下,您可以使用唯一值来比较内部和外部查询。例如,Where T1.PK < T.PK对于整数键或甚至字符串键都可以正常工作。在我的解决方案中,如果Name具有唯一约束,那么它也可以运行得很好。

答案 2 :(得分:1)

我不确定滚动校验和,但是对于滚动总和,您可以使用UPDATE命令执行此操作:

declare @a table (name varchar(2), value int, rollingvalue int)
insert into @a
    select 'a', 1, 0 union all select 'b', 2, 0 union all select 'c', 3, 0 

select * from @a

declare @sum int
set @sum = 0

update @a
set @sum =  rollingvalue = value + @sum 

select * from @a