11

使用 SQL Server 2014,我有一个表,其中有一个nvarchar(max)名为的列,该列[ASCII File]可以包含许多 K 的 ASCII 文本文件。然后我想对该文件执行 MD5 哈希字节,生成的哈希值应始终为 20 个字节。

好吧,当我进行选择时,hashbytes('MD5', [ASCII File])我会完成查询并出现错误

消息 8152、级别 16、状态 10、第 4 行
字符串或二进制数据将被截断。

我尝试时收到相同的消息

left(hashbytes('MD5', [ASCII File]), 50)

我尝试时收到相同的消息

convert(varchar(50), hashbytes('MD5', [ASCII File]))

似乎因为我正在做 hashbytes 的列是nvarchar(max),所以 hashbytes 函数的结果也是nvarchar(max)

您能告诉我如何使结果达到预期的 20 长,而不是必须截断的那么长吗?

4

4 回答 4

15

似乎因为我正在做 hashbytes 的字段是 nvarchar(max),所以 hashbytes 的结果是 nvarchar(max)。

不,这是不可能的,特别是因为HASHBYTES的返回值是 a VARBINARY。此外,由于您的测试只是 SELECT 语句而不是 INSERT 语句,因此返回值无法获得截断错误。截断错误来自输入值。如链接的 MSDN 页面中所述HASHBYTES(对于 SQL Server 2012 和 2014):

允许的输入值限制为 8000 字节。输出符合算法标准:MD2、MD4、MD5为128位(16字节);SHA 和 SHA1 为 160 位(20 字节);SHA2_256 为 256 位(32 字节),SHA2_512 为 512 位(64 字节)。

这确实说明了一切:输入限制为 8000 字节,输出是基于指定算法的固定字节数。

SQL Server 2016(已删除 8000 字节限制)的更新文档指出:

对于 SQL Server 2014 及更早版本,允许的输入值限制为 8000 个字节。

您可以运行一个简单的测试:

DECLARE @Test NVARCHAR(MAX) = REPLICATE(CONVERT(NVARCHAR(MAX), N't'), 50000);
SELECT LEN(@Test);
SELECT HASHBYTES('MD5', @Test);

回报:

50000

Msg 8152, Level 16, State 10, Line 3
String or binary data would be truncated.

如果要在 2016 之前的 SQL Server 版本中将超过 8000 个字节传递给哈希函数,则需要使用 SQLCLR。您可以编写自己的函数,也可以下载并安装免费版的SQL# SQLCLR 库(我创建的),并使用Util_HashUtil_HashBinary函数:

DECLARE @Test NVARCHAR(MAX) = REPLICATE(CONVERT(NVARCHAR(MAX), N't'), 50000);
SELECT LEN(@Test);
SELECT SQL#.Util_Hash('MD5', CONVERT(VARBINARY(MAX), @Test));
SELECT SQL#.Util_HashBinary('MD5', CONVERT(VARBINARY(MAX), @Test));

回报:

50000
40752EB301B41EEAEB309348CE9711D6
0x40752EB301B41EEAEB309348CE9711D6

更新

如果使用VARCHAR(MAX)包含 8000 个或更少字符的NVARCHAR(MAX)列或变量(或包含 4000 个或更少字符的列或变量),则不会出现问题,一切都会按预期工作:

DECLARE @Test VARCHAR(MAX) = REPLICATE('t', 5000);
SELECT LEN(@Test) AS [Characters], 
       HASHBYTES('MD5', @Test) AS [MD5];

回报:

5000    0x6ABFBA10B49157F2EF8C85862B6E6313
于 2016-07-30T05:43:35.127 回答
4

如果您正在尝试转换 sql 中已经存在的大型 varbinary 或图像文件,那么有一些内置函数可以执行此操作(可能从 2014 年开始),这个简单的函数将适用于 varbinary(max) 和较旧的 Image 字段。

/****** Object:  UserDefinedFunction [dbo].[MD5Bin]    Script Date: 16/07/2018 11:04:26 ******/

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- ==================================================
-- Author:    Darren Steven
-- Create date: 16/07/2018
-- Description: Hashes a binary or image field with MD5
-- ==================================================
CREATE FUNCTION [dbo].[MD5Bin](@value varbinary(max))
RETURNS varchar(32)
AS
BEGIN
  RETURN SUBSTRING(master.sys.fn_sqlvarbasetostr(master.sys.fn_repl_hash_binary(@value)),3,32);
END
GO

然后只需使用您的选择调用该函数:

SELECT dbo.MD5Bin(imageFieldName) from dbo.yourTable 
于 2018-07-16T10:18:57.607 回答
4

在 SQL Server 2016 中,我们不再有 HASHBYTES 函数的输入参数长度问题。

DECLARE @Test NVARCHAR(MAX); 
SET @Test = REPLICATE(CONVERT(NVARCHAR(MAX), N't'), 50000000);
SELECT LEN(@Test);
SELECT HASHBYTES('SHA2_512', @Test);

哈希字节 (Transact-SQL)

于 2017-05-15T14:44:37.673 回答
1

在 sql 2016 中删除了 HASHBYTES (Transact-SQL) 函数的输入长度限制为 8,000 字节

基于以下算法的是 MD2、MD4 和 MD5 的输出数据大小为 128 位(16 字节);SHA 和 SHA1 为 160 位(20 字节);SHA2_256 为 256 位(32 字节) SHA2_512 为 512 位(64 字节)。

于 2017-04-19T17:47:07.830 回答