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

Sql server 如何在SQL Server上创建唯一的MD5哈希索引?,sql-server,md5,sql-server-2016,Sql Server,Md5,Sql Server 2016,我想创建一个唯一的索引,用于检查表中的文本组合是否已经存在。在PostgreSQL中,我通过一个简单的创建索引来实现这一点: CREATE UNIQUE INDEX table_unique ON cd.hdealerproductdata USING btree (md5((((svId::text || manufacturer::text) || manufacturerreference::text) || path::text) || treetype::text) C

我想创建一个唯一的索引,用于检查表中的文本组合是否已经存在。在
PostgreSQL
中,我通过一个简单的
创建索引来实现这一点:

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,table designer->Properties->computed column Specification):

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

但我有一个错误,说它不能被验证

编辑:我甚至可以将SHA-2与HashBytes一起使用:

Edit2.
HashBytes
返回
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.:我最终为此创建了一个标量函数,并在插入和创建计算列时调用它(我在该列上持久化并创建了唯一索引)

并调用计算列:
([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
替换值让您绊倒

运行:

你得到了错误

Msg 257,第16级,第3状态,第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

它运行时没有错误

这不太可能是偶然发生的,但既然已经证明了MD5碰撞,我怀疑它是否是评估唯一性的好候选。为什么您排除了对列本身应用唯一约束?@Damien\u不相信列是长varchar(
nvarchar(512)
)。此外,我并不真的害怕md5碰撞意外发生(如果是故意的,那是另一个话题)。我可以使用sha1或更好,这并不重要。请求唯一散列没有意义。散列不是完全唯一的;它们是用于快速比较和扣扣的摘要。它们是故意的有损减少。如果你想要一个唯一的索引,你应该编写一些其他的东西,尽管基于你的用例,我会放弃唯一索引的想法。(也就是说,我很想听听你还能得到什么答案!)@CodeConfident有时候你只需要知道某些字符串在数据库中是否唯一。我认为使用散列(甚至是md5)效果很好。发生碰撞的可能性很小。绝对地做专栏。质疑它。但这不是唯一的限制。您试图告诉数据库强制执行一个不正确的数据不变量。
declare @t table (Manufacturer varchar(512), ManufacturerReference varchar(512))

select ISNULL(HashBytes('MD5',CONVERT(VARCHAR(512),
       CONCAT(Manufacturer,ManufacturerReference))), 'null')
from @t
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