2010-07-16 3 views
3

저는 순서를 설명하기 위해 롤링 체크섬을 유지하려고합니다. 따라서 이전 '체크섬'을 가져와 현재 체크섬을 xor하여 새 체크섬을 생성하십시오.SQL에서 롤링 체크섬을 유지하는 방법은 무엇입니까?

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

어떻게하면 좋을까요?

당신은 행에 대한 주문의 일부 외관이 필요

+0

당신이 당신의 테이블에 클러스터 된 인덱스가 있는가하고 클러스터 된 인덱스 당신이 당신의 롤링 체크섬을 계산하기 위해 허용되는 순서의 순서가 있습니까? –

+0

예, 예. 시간 기반 시퀀스 (bigint, 타임 스탬프 생각)가 있고 클러스터 된 인덱스입니다. – esac

답변

2

이 기본적으로 running total 문제입니다.

편집 :

내 원래의 주장은 그 커서 기반의 솔루션이 실제로 가장 좋은 수행하는 몇 안되는 장소 중 하나입니다. 삼각형 자체 조인 솔루션의 문제점은 다음 단계의 하위 계산과 동일한 누적 체크섬을 반복적으로 다시 계산해야하므로 필요한 작업이 행 수와 함께 기하 급수적으로 늘어남에 따라 확장 성이 떨어집니다.

Corina의 대답은 "기발한 업데이트"접근 방식을 사용합니다. 체크섬을 적용하도록 조정했고 테스트에서 커서 솔루션에 대해 26 초가 아닌 3 초가 걸렸습니다. 둘 다 같은 결과를 냈다. 그러나 불행하게도 업데이트 동작의 문서화되지 않은 측면에 의존합니다. 프로덕션 코드에서 이것을 사용할지 결정하기 전에 반드시 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) 

접근 방식 두 가지를 바탕으로 - 그 기사에 대한 토론 휴고 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 
+0

@Martin Smith - 그렇지 않습니까? 내부 쿼리와 외부 쿼리를 일치시키기 위해 사용하는 것에 크게 의존합니까? 즉, 비교가'Where T1.PK Thomas

+0

@ 토마스 - 내가 말하는 것은 당신이 마지막 계산의 결과를 재사용 할 수 없다는 것입니다. 따라서 행 수가 100 만개가 될 때까지 이전 행의 값을 계산하기 위해 999,998 개를 통과했지만 이전 행의 999,999 행을 다시 검토해야합니다. 이것과 전혀 다른가요? http://www.sqlservercentral.com/articles/T-SQL/61539/ –

+0

@ Martin Smith- Ah. 네, 질문 없습니다. 무엇이든 롤링하는 것이 엔진 및 BI 툴 IMO를보고하는 것이 가장 좋습니다. – Thomas

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에 고유 한 제한 조건이있는 경우 충분히 잘 작동합니다.

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 
+0

+1 관찰해야 할 몇 가지주의 사항이 있지만 여기서는 기사의 매우 빠른 탈피에서 작동 할 수 있다고 생각합니다. http://www.sqlservercentral.com/articles/T-SQL/68467/ –

관련 문제