Вычислить хэш или контрольную сумму для таблицы в SQL Server
Я пытаюсь вычислить контрольную сумму или хэш для всей таблицы в SQL Server 2008. Проблема, с которой я сталкиваюсь, заключается в том, что таблица содержит тип данных столбца XML, который не может использоваться контрольной суммой и должен быть сначала преобразован в nvarchar. Поэтому мне нужно разбить его на две проблемы:
- вычислить контрольную сумму для строки, схема неизвестна до выполнения.
- вычислить контрольную сумму для всех строк, чтобы получить полную контрольную сумму таблицы.
Ответы
Ответ 1
Вы можете использовать CHECKSUM_AGG. Для этого требуется только один аргумент, поэтому вы можете сделать CHECKSUM_AGG(CHECKSUM(*))
- но это не работает для вашего типа данных XML, поэтому вам придется прибегнуть к динамическому SQL.
Вы можете динамически генерировать список столбцов из INFORMATION_SCHEMA.COLUMNS
, а затем вставить int в шаблон:
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(@template
'{@column_list}', @column_list),
'{@schema_name}', @schema_name),
'{@table_name}', @table_name)
EXEC ( @sql )
Ответ 2
Я изменил script, чтобы создать запрос для всех соответствующих таблиц в базе данных.
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
Ответ 3
//Быстрая хэш-сумма SQL и С# mirror Украина //HASH _ZKCRC64 /// ----------------------------------------------- -------------------------------------------------- ------------- частный Int64 HASH_ZKCRC64 (байт [] Данные) { Int64 Result = 0x5555555555555555; if (Data == null || Data.Length <= 0) return 0; int SizeGlobalBufer = 8000; int Ost = Data.Length% SizeGlobalBufer; int LeftLimit = (Data.Length/SizeGlobalBufer) * РазмерGlobalBufer;
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
}