2009-10-13 16 views
25

Tôi đang cố gắng tính toán tổng kiểm tra hoặc băm cho toàn bộ bảng trong SQL Server 2008. Vấn đề tôi đang gặp phải là bảng chứa một kiểu dữ liệu cột XML, mà không thể được sử dụng bởi tổng kiểm tra và phải được chuyển đổi thành nvarchar trước tiên. Vì vậy, tôi cần phải chia nhỏ thành hai vấn đề:Tính toán Hash hoặc Checksum cho một bảng trong SQL Server

  1. tính toán tổng kiểm cho một hàng, giản đồ không xác định trước khi chạy.
  2. tính tổng kiểm tra cho tất cả các hàng để nhận toàn bộ bảng tổng kiểm tra.

Trả lời

23

Bạn có thể sử dụng CHECKSUM_AGG. Nó chỉ mất một đối số duy nhất, vì vậy bạn có thể làm CHECKSUM_AGG(CHECKSUM(*)) - nhưng điều này không làm việc cho kiểu dữ liệu XML của bạn, do đó bạn sẽ phải sử dụng SQL động.

Bạn có thể tạo ra động danh sách cột từ INFORMATION_SCHEMA.COLUMNS và sau đó chèn int vào một khuôn mẫu:

SELECT @column_list = COALESCE(@column_list + ', ', '') 
     + /* Put your casting here from XML, text, etc columns */ QUOTENAME(COLUMN_NAME) 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = @table_name 
    AND TABLE_SCHEMA = @schema_name 

DECLARE @template AS varchar(MAX) 
SET @template = 'SELECT CHECKSUM_AGG(CHECKSUM({@column_list})) FROM {@schema_name}.{@table_name}' 

DECLARE @sql AS varchar(MAX) 
SET @sql = REPLACE(REPLACE(REPLACE(
    '{@column_list}', @column_list), 
    '{@schema_name}', @schema_name), 
    '{@table_name}', @table_name) 

EXEC (@sql) 
+0

Cảm ơn! Tôi đã phải tinh chỉnh nó một chút để trường hợp đặc biệt các kiểu dữ liệu, nhưng tôi đã có thể đến với một cái gì đó đã được nhanh chóng và dựa trên giải pháp này. Xuất sắc! –

+0

Chỉ cần cẩn thận với cột nhận dạng, tôi cũng sẽ sử dụng BINARY_CHECKSUM vì đây là trường hợp nhạy cảm. –

2

tôi sửa đổi kịch bản để tạo ra một truy vấn cho tất cả các bảng có liên quan trong một cơ sở dữ liệu.

USE myDatabase 
GO 
DECLARE @table_name sysname 
DECLARE @schema_name sysname 
SET @schema_name = 'dbo' 

DECLARE myCursor cursor 
FOR SELECT TABLE_NAME 
     FROM INFORMATION_SCHEMA.TABLES T 
    WHERE T.TABLE_SCHEMA = @schema_name 
     AND T.TABLE_TYPE = 'BASE TABLE' 
     AND T.TABLE_NAME NOT LIKE 'MSmerge%' 
     AND T.TABLE_NAME NOT LIKE 'sysmerge%' 
     AND T.TABLE_NAME NOT LIKE 'tmp%' 
    ORDER BY T.TABLE_NAME 

OPEN myCursor 

FETCH NEXT 
FROM myCursor 
INTO @table_name 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    DECLARE @column_list nvarchar(MAX) 
    SET @column_list='' 
SELECT @column_list = @column_list + CASE WHEN DATA_TYPE IN ('xml','text','ntext','image sql_variant') THEN 'CONVERT(nvarchar(MAX),' 
              ELSE '' 
            END 
            + QUOTENAME(COLUMN_NAME) 
            + CASE WHEN DATA_TYPE IN ('xml','text','ntext','image sql_variant') THEN ' /* ' + DATA_TYPE + ' */)' 
              ELSE '' 
            END + ', ' 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = @Table_name 
    ORDER BY ORDINAL_POSITION 

    SET @column_list = LEFT(@column_list, LEN(@column_list)-1) -- remove trailing comma 

    DECLARE @sql AS nvarchar(MAX) 
    SET @sql = 'SELECT ''' + QUOTENAME(@schema_name) + '.' + QUOTENAME(@table_name) + ''' table_name, 
     CHECKSUM_AGG(CHECKSUM(' + @column_list + ')) CHECKSUM 
    FROM ' + QUOTENAME(@schema_name) + '.' + QUOTENAME(@Table_name) + ' WITH (NOLOCK)' 


    PRINT @sql 

    FETCH NEXT 
    FROM myCursor 
    INTO @table_name 

    IF @@FETCH_STATUS = 0 
     PRINT 'UNION ALL' 

END 

CLOSE myCursor 
DEALLOCATE myCursor 
GO 
0

// nhanh băm tổng của SQL và C# gương Ukraina // HASH_ZKCRC64 /// ----------------------- -------------------------------------------------- ------------------------------------- riêng Int64 HASH_ZKCRC64 (byte [] Dữ liệu) { Kết quả Int64 = 0x5555555555555555; nếu (Dữ liệu == null || Dữ liệu.Length < = 0) trả lại 0; int SizeGlobalBufer = 8000; int Ost = Dữ liệu.Length% SizeGlobalBufer; int LeftLimit = (Dữ liệu.Length/SizeGlobalBufer) * SizeGlobalBufer;

 for (int i = 0; i < LeftLimit; i += 64) 
     { 
      Result = Result 
      ^BitConverter.ToInt64(Data, i) 
      ^BitConverter.ToInt64(Data, i + 8) 
      ^BitConverter.ToInt64(Data, i + 16) 
      ^BitConverter.ToInt64(Data, i + 24) 
      ^BitConverter.ToInt64(Data, i + 32) 
      ^BitConverter.ToInt64(Data, i + 40) 
      ^BitConverter.ToInt64(Data, i + 48) 
      ^BitConverter.ToInt64(Data, i + 56); 
      if ((Result & 0x0000000000000080) != 0) 
      Result = Result^BitConverter.ToInt64(Data, i + 28); 
     } 

     if (Ost > 0) 
     { 
      byte[] Bufer = new byte[SizeGlobalBufer]; 
      Array.Copy(Data, LeftLimit, Bufer, 0, Ost); 
      for (int i = 0; i < SizeGlobalBufer; i += 64) 
      { 
       Result = Result 
      ^BitConverter.ToInt64(Bufer, i) 
      ^BitConverter.ToInt64(Bufer, i + 8) 
      ^BitConverter.ToInt64(Bufer, i + 16) 
      ^BitConverter.ToInt64(Bufer, i + 24) 
      ^BitConverter.ToInt64(Bufer, i + 32) 
      ^BitConverter.ToInt64(Bufer, i + 40) 
      ^BitConverter.ToInt64(Bufer, i + 48) 
      ^BitConverter.ToInt64(Bufer, i + 56); 
       if ((Result & 0x0000000000000080)!=0) 
       Result = Result^BitConverter.ToInt64(Bufer, i + 28); 
      } 
     } 

     byte[] MiniBufer = BitConverter.GetBytes(Result); 
     Array.Reverse(MiniBufer); 
     return BitConverter.ToInt64(MiniBufer, 0); 

     #region SQL_FUNCTION 
     /* CREATE FUNCTION [dbo].[HASH_ZKCRC64] (@data as varbinary(MAX)) Returns bigint 
      AS 
      BEGIN 
      Declare @I64 as bigint Set @I64=0x5555555555555555 
      Declare @Bufer as binary(8000) 
      Declare @i as int Set @i=1 
      Declare @j as int 
      Declare @Len as int Set @Len=Len(@data)  

      if ((@data is null) Or (@Len<=0)) Return 0 

       While @i<[email protected] 
       Begin 
       Set @Bufer=Substring(@data,@i,8000) 
       Set @j=1 
        While @j<=8000 
        Begin 
        Set @[email protected] 
        ^CAST(Substring(@Bufer,@j, 8) as bigint) 
        ^CAST(Substring(@Bufer,@j+8, 8) as bigint) 
        ^CAST(Substring(@Bufer,@j+16,8) as bigint) 
        ^CAST(Substring(@Bufer,@j+24,8) as bigint) 
        ^CAST(Substring(@Bufer,@j+32,8) as bigint) 
        ^CAST(Substring(@Bufer,@j+40,8) as bigint) 
        ^CAST(Substring(@Bufer,@j+48,8) as bigint) 
        ^CAST(Substring(@Bufer,@j+56,8) as bigint) 
        if @I64<0 Set @[email protected]^CAST(Substring(@Bufer,@j+28,8) as bigint)  
        Set @[email protected]+64  
        End; 
       Set @[email protected]+8000 
       End 
      Return @I64 
      END 
     */ 
     #endregion 

    } 
+1

Vui lòng định dạng mã của bạn và cập nhật câu trả lời của bạn với giải thích. –

Các vấn đề liên quan