Sql server HASHBYTES的唯一约束挑战

Sql server HASHBYTES的唯一约束挑战,sql-server,sql-server-2016,Sql Server,Sql Server 2016,我有下表,根据4列,其中的记录应该是唯一的 我使用HASHBYTES添加了一个HashCol。现在是一条错误消息 表“RCM\u EM\u Benchmarks”中的列“HashCol”不能用于索引或统计信息,也不能用作分区键,因为它是不确定的。 如何在这种情况下保持一致性 CREATE TABLE [dbo].[MyTable]( [RecordID] [int] IDENTITY(1,1) NOT NULL, [Procedure_Code] [varchar](10) NU

我有下表,根据4列,其中的记录应该是唯一的

我使用HASHBYTES添加了一个HashCol。现在是一条错误消息 表“RCM\u EM\u Benchmarks”中的列“HashCol”不能用于索引或统计信息,也不能用作分区键,因为它是不确定的。

如何在这种情况下保持一致性

CREATE TABLE [dbo].[MyTable](
    [RecordID] [int] IDENTITY(1,1) NOT NULL,
    [Procedure_Code] [varchar](10) NULL,
    [Procedure_Percentage] [decimal](6, 2) NULL,
    [Claim_Count] [int] NULL,
    [Benchmark] [varchar](40) NULL,
    [Practice] [varchar](40) NULL,
    [Month_Start_Date] [date] NULL,
    [Procedure_Type] [varchar](40) NULL,
    [CreatedOnDate] [date] NULL,
    HashCol AS HASHBYTES('SHA1', [Procedure_Code] + [Benchmark]+ [Practice]+ CONVERT(VARCHAR(25),  [Month_Start_Date]) )
) ON [PRIMARY]
GO

ALTER  TABLE  [MyTable] ADD CONSTRAINT hashCol_Unique UNIQUE (HashCol)
GO

使用convert函数的style参数应该使其具有确定性

例如:

而不是:

HashCol AS HASHBYTES('SHA1', [Procedure_Code] + [Benchmark]+ [Practice]+ CONVERT(VARCHAR(25),  [Month_Start_Date]) )
使用此选项,它使用101作为样式参数:

 HashCol AS HASHBYTES('SHA1', [Procedure_Code] + [Benchmark]+ [Practice] + CONVERT(VARCHAR(25),  [Month_Start_Date], 101 ) )

使用convert函数的style参数应该使其具有确定性

例如:

而不是:

HashCol AS HASHBYTES('SHA1', [Procedure_Code] + [Benchmark]+ [Practice]+ CONVERT(VARCHAR(25),  [Month_Start_Date]) )
使用此选项,它使用101作为样式参数:

 HashCol AS HASHBYTES('SHA1', [Procedure_Code] + [Benchmark]+ [Practice] + CONVERT(VARCHAR(25),  [Month_Start_Date], 101 ) )
这对我很有用:

use tempdb;
drop table if exists dbo.myTable;
CREATE TABLE [dbo].[MyTable](
    [RecordID] [int] IDENTITY(1,1) NOT NULL,
    [Procedure_Code] [varchar](10) NULL,
    [Procedure_Percentage] [decimal](6, 2) NULL,
    [Claim_Count] [int] NULL,
    [Benchmark] [varchar](40) NULL,
    [Practice] [varchar](40) NULL,
    [Month_Start_Date] [date] NULL,
    [Procedure_Type] [varchar](40) NULL,
    [CreatedOnDate] [date] NULL,
    HashCol AS HASHBYTES('SHA1', [Procedure_Code] + [Benchmark] + [Practice] + convert(char(10), [Month_Start_Date], 126))
) ON [PRIMARY]
GO

ALTER  TABLE  [MyTable] ADD CONSTRAINT hashCol_Unique UNIQUE (HashCol)
GO
说到为什么,
convert()
在某些情况下(包括默认样式)是不确定的。您必须选择在中未标记为非确定性的样式。具有讽刺意味的是,我尝试了样式23(它只返回yyyy mm dd的日期,并且没有标记为非确定性),这也是一个不可行的方法。在上面链接的同一个文档中,有一句废话说100以下的样式是不确定的,所以我尝试了一下我个人最喜欢的126,它成功了。请注意,我将数据类型更改为
char(10)
,因为将日期转换为该样式将始终为10个字节

尽管由于任何原因,
hashbytes()
被列为返回“varbinary(最大8000字节)”,这仍然会引发警告。然而,在文档中,它也给出了不同哈希算法的实际输出长度。您可以显式地将
hashbytes()
调用的结果强制转换为该长度,以避免警告,或者忽略它,因为我认为在实际操作中,它永远不会超过算法规定的长度

我要说的最后一件事是,SHA1已经被弃用了一段时间。对于新开发,您应该使用SHA2变体之一。由于您的问题被标记为SQL 2016,您可以使用SHA2_256和SHA2_512。

这对我很有用:

use tempdb;
drop table if exists dbo.myTable;
CREATE TABLE [dbo].[MyTable](
    [RecordID] [int] IDENTITY(1,1) NOT NULL,
    [Procedure_Code] [varchar](10) NULL,
    [Procedure_Percentage] [decimal](6, 2) NULL,
    [Claim_Count] [int] NULL,
    [Benchmark] [varchar](40) NULL,
    [Practice] [varchar](40) NULL,
    [Month_Start_Date] [date] NULL,
    [Procedure_Type] [varchar](40) NULL,
    [CreatedOnDate] [date] NULL,
    HashCol AS HASHBYTES('SHA1', [Procedure_Code] + [Benchmark] + [Practice] + convert(char(10), [Month_Start_Date], 126))
) ON [PRIMARY]
GO

ALTER  TABLE  [MyTable] ADD CONSTRAINT hashCol_Unique UNIQUE (HashCol)
GO
说到为什么,
convert()
在某些情况下(包括默认样式)是不确定的。您必须选择在中未标记为非确定性的样式。具有讽刺意味的是,我尝试了样式23(它只返回yyyy mm dd的日期,并且没有标记为非确定性),这也是一个不可行的方法。在上面链接的同一个文档中,有一句废话说100以下的样式是不确定的,所以我尝试了一下我个人最喜欢的126,它成功了。请注意,我将数据类型更改为
char(10)
,因为将日期转换为该样式将始终为10个字节

尽管由于任何原因,
hashbytes()
被列为返回“varbinary(最大8000字节)”,这仍然会引发警告。然而,在文档中,它也给出了不同哈希算法的实际输出长度。您可以显式地将
hashbytes()
调用的结果强制转换为该长度,以避免警告,或者忽略它,因为我认为在实际操作中,它永远不会超过算法规定的长度


我要说的最后一件事是,SHA1已经被弃用了一段时间。对于新开发,您应该使用SHA2变体之一。因为您的问题被标记为SQL 2016,所以您可以使用SHA2_256和SHA2_512。

这可能是一个愚蠢的问题,但为什么不在构成哈希计算的列上创建一个唯一的索引呢?(这样,您不需要计算列具有确定性,但也不会受到罕见(尽管可能)哈希冲突的保护)。这可能是一个愚蠢的问题,但为什么不在构成哈希计算的列上创建一个唯一的索引呢?(这样,您不需要计算列具有确定性,但也不会受到罕见(尽管可能)哈希冲突的保护)。