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

时间:2017-09-05 08:02:20

标签: sql-server md5 sql-server-2016

我想创建一个唯一的索引,检查我的表中的文本组合是否已经存在。在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 Server(2016)中执行此操作?我尝试创建一个计算列(并为其添加一个唯一索引),如下所示(使用SSMS,表设计器 - >属性 - >计算列规范):

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

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

编辑:我甚至可以在HashBytes使用SHA-2:https://docs.microsoft.com/en-us/sql/t-sql/functions/hashbytes-transact-sql

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

enter image description here

后:

'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。:我最终为此创建了一个Scalar函数,并在插入和创建计算列时调用它(我坚持并创建了一个唯一索引)。

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

并调用了Compute列:([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

1 个答案:

答案 0 :(得分:1)

这是你选择的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

     

不允许从数据类型varchar到varbinary的隐式转换。使用CONVERT函数运行此查询。

但运行此查询:

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

它运行没有错误