【问题标题】:ANSI_PADDING on varbinary(16) not workingvarbinary(16) 上的 ANSI_PADDING 不起作用
【发布时间】:2018-10-18 03:29:35
【问题描述】:

当我向现有的非空表添加具有默认约束 0x00000000000000000000000000000000 的新固定长度 varbinary 列时,表中的现有记录正在接收默认约束 0x00 的修剪版本。

新记录的后续插入确实正确应用了默认约束。

这只发生在 SQL 2017 中,以前的 SQL 版本正确地将默认约束应用于所有现有记录。

包含 'SET ANSI_PADDING ON' 不会影响结果。

0x11111111110000000... 也以相同的方式运行,它会修剪尾随零。

我也尝试过使用默认值DEFAULT Cast(0x00000000000000000000000000000000 as varbinary(16)),但结果相同。


运行 Microsoft SQL Server 2017 (RTM-CU11) (KB4462262) - 14.0.3038.14 (X64)


复制:

create table #test (id int);
insert into #test (id) values (1), (2), (3);
alter table #test add testvarbinary VARBINARY(16) NOT NULL CONSTRAINT 
DF_MyTable_NewColumn DEFAULT 0x00000000000000000000000000000000;
insert into #test (id) values (4); 
select * from #test;

结果:

+----+------------------------------------+
| id |           testvarbinary            |
+----+------------------------------------+
|  1 | 0x00                               |
|  2 | 0x00                               |
|  3 | 0x00                               |
|  4 | 0x00000000000000000000000000000000 |
+----+------------------------------------+

【问题讨论】:

  • @MitchWheat 使用的 TSQL 与上面的添加列相同,我只是修改了表/列名称,之后的插入只是 INSERT INTO MyTable (Id) VALUES (1) 其中 MyTable 有 Id 列和新列。如前所述,SQL 2016 上完全相同的 TSQL(一直到 2005 年)表现相同,只是在 SQL 2017 中表现不同。我明天回到办公桌后会尝试 Cast。
  • @MitchWheat 我刚刚添加了编辑 3 和要重现的代码。
  • 对不起,同样的结果。创建表#test(id int);插入#test(id)值(1),(2),(3); alter table #test add testvarbinary VARBINARY(16) NOT NULL CONSTRAINT DF_test DEFAULT Cast(0x000000000000000000000000000000000 as varbinary(16));插入#test(id)值(4);从#test中选择*;给出: id testvarbinary 1 0x00 2 0x00 3 0x00 4 0x00000000000000000000000000000000
  • 我们在 SO 上有编辑历史。您可以考虑将您的问题浓缩为一个连贯的问题,而不使用所有单独的 Edit 标记。
  • 感谢您的帮助,我已经报告了uservoice。

标签: sql sql-server tsql sql-server-2017


【解决方案1】:

有一个功能 introduced in SQL Server 2012 允许将 NOT Null 列添加到现有表中(具有默认约束) 这是为了允许将非空值添加到非常大的表中。

这仅限于企业版和功能等效的 SKU,这就是为什么您只能在测试中的某些实例上看到这一点。

它的工作方式是保留现有行 NULL 直到下一次被触摸并从元数据中检索值。

元数据本身很好,可以用

检查
SELECT pc.default_value
FROM   tempdb.sys.system_internals_partitions p
       JOIN tempdb.sys.system_internals_partition_columns pc
         ON p.partition_id = pc.partition_id
WHERE  p.object_id = OBJECT_ID('tempdb..#test')
       AND default_value IS NOT NULL; 

但是当读取这些值时,0x00 的变化就会发生。

有趣的是 - 如果您将默认设置更改为 0x00000000000000000000000000000001 然后用正确的值更新所有行:

id  testvarbinary
1   0x00000000000000000000000000000001
2   0x00000000000000000000000000000001
3   0x00000000000000000000000000000001
4   0x00000000000000000000000000000001

一种可能的解决方法是使默认约束具有不确定性(并且无法缓存为运行时常量)以防止在线列添加。尽管您会失去该功能的性能优势。

下面的默认约束表达式避免了这个问题

DEFAULT 0x00000000000000000000000000000000 + CAST(LEFT(NEWID(),0) AS varbinary(1))

您应该在the uservoice site 上将此作为错误报告。

【讨论】:

    猜你喜欢
    • 2013-08-31
    • 1970-01-01
    • 2022-09-27
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 2022-11-05
    相关资源
    最近更新 更多