【问题标题】:Persisted column throwing non-deterministic error using convert使用转换的持久列抛出非确定性错误
【发布时间】:2018-06-27 21:49:00
【问题描述】:

使用 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 列来保存我的表中所有值的哈希值。

有什么想法吗?

谢谢!

【问题讨论】:

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


    【解决方案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;
    

    结果

    【讨论】:

    • 这是一个公平的观点。我正在使用合并,因为会有空值,但我看到 concat 也会处理它。真的没有什么好理由。非常感谢!
    • 声明列的方式不会有空值。目前,您每个人都有“不为空”。
    • @Anssssss 正确,但我的意思是 concat() 将创建字符串无转换
    【解决方案2】:

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

    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 和其他数据类型。

    【讨论】:

    • 这正是我所缺少的。非常感谢。
    【解决方案3】:

    这是上面两个答案的组合的最终结果。非常感谢您的帮助。

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多