如何在 SQL 服务器上创建唯一的 MD5 哈希索引?

How to create unique MD5 hash index on SQL Server?

我想创建一个唯一索引,用于检查我的 table 中的文本组合是否已经存在。在 PostgreSQL 中,我用一个简单的 CREATE INDEX:

CREATE UNIQUE INDEX table_unique
    ON cd.hdealerproductdata USING btree
    (md5((((svId::text || manufacturer::text) || manufacturerreference::text) || path::text) || treetype::text) COLLATE pg_catalog."default")
    TABLESPACE pg_default;

如何在 SQL 服务器 (2016) 中执行此操作?我尝试像这样创建一个计算列(并向其添加唯一索引)(使用 SSMS,table designer->Properties->Computed Column Specification):

ISNULL(HashBytes('MD5',CONVERT(VARCHAR(512),CONCAT(Manufacturer,ManufacturerReference))), 'null')

但我收到一条错误消息,提示无法验证。

编辑:我什至可以将 SHA-2 与 HashBytes 一起使用:https://docs.microsoft.com/en-us/sql/t-sql/functions/hashbytes-transact-sql

Edit2.: HashBytes returns varbinary 类型,但我无法为计算列指定数据类型。

之后:

'Document' table
- Unable to modify table.  
Implicit conversion from data type varchar to varbinary is not allowed. Use the CONVERT function to run this query.

Edit3.: 我最终为此创建了一个标量函数,并在插入和创建计算列时调用它(我坚持并在其上创建了一个唯一索引)。

CREATE FUNCTION [dbo].[DocumentUniqueHash] 
(
    @DocumentTreeId bigint,
    @Manufacturer nvarchar(255),
    @ManufacturerReference nvarchar(255)
)
RETURNS varbinary(20)
WITH SCHEMABINDING
AS
BEGIN
    -- Declare the return variable here
    DECLARE @Result varbinary(20)

    SELECT @Result = (hashbytes('SHA1',(CONVERT([nvarchar](max),@DocumentTreeId)+@Manufacturer)+@ManufacturerReference))

    -- Return the result of the function
    RETURN @Result

END

并调用了计算列:([dbo].[DocumentUniqueHash]([DocumentTreeId],[Manufacturer],[ManufacturerReference]))

还有,插入存储过程是这样的:

CREATE PROCEDURE DocumentInsert
    @DocumentTreeId bigint,
    @Manufacturer nvarchar(255),
    @ManufacturerReference nvarchar(255),
    @NewId bigint OUTPUT
AS
BEGIN
    SELECT @NewId = Id FROM Document (NOLOCK) 
    WHERE UniqueHash = [dbo].[DocumentUniqueHash](@DocumentTreeId, @Manufacturer, @ManufacturerReference)

    IF @NewId IS NULL
    BEGIN
        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
        BEGIN TRANSACTION
            SELECT @NewId = Id FROM Document (NOLOCK) 
            WHERE UniqueHash = [dbo].[DocumentUniqueHash](@DocumentTreeId, @Manufacturer, @ManufacturerReference)
            IF @NewId IS NULL
            BEGIN
                INSERT INTO Document (DocumentTreeId, Manufacturer, ManufacturerReference) 
                VALUES (@DocumentTreeId, @Manufacturer, @ManufacturerReference)
                SELECT @NewId = SCOPE_IDENTITY()
            END
        COMMIT TRANSACTION
    END
    SELECT @NewId
END
GO

您选择的 ISNULL 替换值让您感到困惑。

运行:

declare @t table (Manufacturer varchar(512), ManufacturerReference varchar(512))

select ISNULL(HashBytes('MD5',CONVERT(VARCHAR(512),
       CONCAT(Manufacturer,ManufacturerReference))), 'null')
from @t

你得到了错误

Msg 257, Level 16, State 3, Line 4

Implicit conversion from data type varchar to varbinary is not allowed. Use the CONVERT function to run this query.

但是 运行 这个查询:

declare @t table (Manufacturer varchar(512), ManufacturerReference varchar(512))

select ISNULL(HashBytes('MD5',CONVERT(VARCHAR(512),
       CONCAT(Manufacturer,ManufacturerReference))), 0x) --not a string any more
from @t

它 运行 没有错误