2009-10-13 6 views
25

Ich versuche, eine Prüfsumme oder einen Hash für eine gesamte Tabelle in SQL Server 2008 zu berechnen. Das Problem, das ich renne ist, dass die Tabelle einen XML-Spalte Datentyp enthält, Das kann nicht von Prüfsumme verwendet werden und muss zuerst in nvarchar konvertiert werden. Also muss ich es in zwei Probleme unterteilen:Berechnen Hash oder Prüfsumme für eine Tabelle in SQL Server

  1. berechnen Sie eine Prüfsumme für eine Zeile, Schema ist unbekannt vor der Laufzeit.
  2. berechnen Sie die Prüfsumme für alle Zeilen, um die vollständige Tabelle Prüfsumme zu erhalten.

Antwort

23

Sie können CHECKSUM_AGG verwenden. Es braucht nur ein einziges Argument, also könnten Sie CHECKSUM_AGG(CHECKSUM(*)) tun - aber das funktioniert nicht für Ihren XML-Datentyp, also müssen Sie auf dynamisches SQL zurückgreifen.

Sie können dynamisch die Spaltenliste von INFORMATION_SCHEMA.COLUMNS erzeugen und dann int in eine Vorlage einfügen:

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

Vielen Dank! Ich musste es ein wenig auf die Datentypen anpassen, aber ich konnte etwas entwickeln, das schnell war und auf dieser Lösung basierte. Ausgezeichnet! –

+0

Seien Sie vorsichtig mit Identity-Spalten, auch würde ich BINARY_CHECKSUM verwenden, da dies die Groß-/Kleinschreibung betrifft. –

2

ich das Skript modifiziert, um eine Abfrage für alle relevanten Tabellen in einer Datenbank zu generieren.

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

// Schnell Hash-Summe von SQL und C# Spiegel Ukraine // HASH_ZKCRC64 /// ----------------------- -------------------------------------------------- ------------------------------------- private Int64 HASH_ZKCRC64 (Byte [] Daten) { Int64 Ergebnis = 0x5555555555555555; if (Daten == null || Daten.Länge < = 0) return 0; int GrößeGlobalBufer = 8000; int Ost = Daten.Länge% SizeGlobalBufer; int LeftLimit = (Data.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

Bitte formatieren Sie Ihren Code und aktualisieren Sie Ihre Antwort mit einer Erklärung. –