使用convert持久化列引发不确定性错误

时间:2018-06-27 21:49:00

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

使用SQL Server 2016时,我遇到了一些问题。

这是我的用例,给我造成问题...

create table dbo.Example (
    Id int identity (1, 1) not null,
    [Name] nvarchar(100) not null,
    Email nvarchar(255) not null,
    DOB datetime2(7) not null,
    RowHash as convert(nvarchar(66), hashbytes('SHA1', coalesce(
        convert(nvarchar(max), [Name]), 
        convert(nvarchar(max), Email), 
        convert(nvarchar(max), DOB)
    ))) persisted
    constraint [PK_Example] primary key clustered (Id asc)
);
drop table dbo.Example;

我收到的消息是:

  

消息4936,第16级,状态1,第1行   表'Example'中的计算列'RowHash'无法保留,因为该列不确定。

当我将列设置为不持久时,数据类型正确解释为nvarchar(66),但是我希望它持久。问题似乎与datetime2列有关,但是我在表上混合了数据类型。

所以目标是使用一个持久的hashbytes列来保存表中所有值的哈希值。

有什么想法吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

为什么用coalesce()而不是concat()

示例

create table dbo.Example (
    Id int identity (1, 1) not null,
    [Name] nvarchar(100) not null,
    Email nvarchar(255) not null,
    DOB datetime2(7) not null,
    RowHash as convert(nvarchar(66), hashbytes('SHA1', concat(
        [Name], 
        Email, 
        DOB
    ))) persisted
    constraint [PK_Example] primary key clustered (Id asc)
);

Select * from [dbo].[Example]
--drop table dbo.Example;

结果

enter image description here

答案 1 :(得分:1)

您可以通过指定日期转换格式来解决此问题:

create table dbo.Example (
    Id int identity (1, 1) not null,
    [Name] nvarchar(100) not null,
    Email nvarchar(255) not null,
    DOB date not null,  -- I figure date is good enough
    RowHash as convert(nvarchar(66), hashbytes('SHA1', concat(
        convert(nvarchar(max), [Name]), 
        convert(nvarchar(max), Email),
        convert(nvarchar(max), DOB, 121)
    ))) persisted
    constraint [PK_Example] primary key clustered (Id asc)
);

问题在于,默认的日期到字符串的转换取决于系统参数,因此不确定。对于持久化列,所有组件都必须是确定性的。

我想说文档很好地平衡了这一奇异之处。不完全的。您可以从此documentation中获得想法。请原谅-它也适用于datedatetime2和其他数据类型。

答案 2 :(得分:0)

这是上面两个答案的总和。非常感谢您的帮助。

create table dbo.Example (
    Id int identity (1, 1) not null,
    [Name] nvarchar(100) not null,
    Email nvarchar(255) not null,
    DOB datetime2(7) null,
    RowHash as convert(nvarchar(66), hashbytes('SHA1', concat(
        convert(nvarchar(max), [Name]),
        convert(nvarchar(max), Email),
        convert(nvarchar(max), DOB, 121)
    ))) persisted
    constraint [PK_Example] primary key clustered (Id asc)
);
drop table dbo.Example;