SQL Server varbinary尾随0解释

时间:2016-03-01 02:28:29

标签: sql-server

CREATE TABLE [sql_table1] ([c0] varbinary(25) NOT NULL primary key) 
go

insert into sql_table1 values (0x3200),(0x32);
go

我得到了

  

无法在对象' dbo.sql_table'中插入重复键。重复   键值为(0x32)。

为什么呢? 0x32不等于0x3200

1 个答案:

答案 0 :(得分:1)

它得到了正确的填充。当您尝试指定通常应该等效的数字十六进制值时,BINARY数据会变得棘手。如果您尝试这样做,它将起作用:

insert into #sql_table1 values (0x32),(CAST(50 as VARBINARY(25)));
-- inserts 0x00000032
-- and     0x32

但这些在数值上是等价的。一般来说,将任何类型的BINARY列作为主键或尝试在其上添加唯一索引是一个坏主意(比CHAR / VARCHAR / {{更多1}}列) - 任何插入其中的应用程序几乎肯定会NVARCHAR从某些本机格式/表示形式转换为二进制,但不能保证CAST实际上以独特的方式工作在任一方向 - 应用程序是否插入值CAST50),或者是否尝试插入文字= 0x32,或者是否尝试插入{{1的ASCII值}(0x32),还是插入了其他东西的第一个字节....?如果一个应用程序提交2而另一个= 0x32提交的内容相同或不同(SQL Server说不同 - 请参阅下文)?

最重要的是,如果您尝试在没有某些上下文的情况下将二进制列进行比较,那么SQL Server将会表现异常。将使用0x32

比较二进制数据将起作用
0x0032

但同样,这只会帮助您看到二进制数据的十六进制表示不会完全按照它看起来的方式工作。关键是,您的主键将基于数据的BINARY_CHECKSUM而不是数据的任何特定格式/表示。通常这是一件好事,但是使用二进制数据(和填充)会变得更加棘手。即便如此,在上面的示例中,两列的SELECT BINARY_CHECKSUM(0x32) -- 50 SELECT BINARY_CHECKSUM(0x320) -- 16! -- it's treating this as having a different number or ordering of bytes SELECT BINARY_CHECKSUM(0x3200) -- 50 SELECT BINARY_CHECKSUM(0x32000) -- 16 SELECT BINARY_CHECKSUM(0x0032) -- 50 SELECT BINARY_CHECKSUM(0x00032) -- 50 SELECT BINARY_CHECKSUM(0x000000000032) -- 50 将完全相同(BINARY_CHECKSUM将为两行输出BINARY_CHECKSUM。很奇怪 - 进一步的测试表明,即使校验和相同(例如SELECT BINARY_CHECKSUM(c0) FROM sql_table1等),任何不同数量的前导0都会绕过唯一的检查。

如果您开始将不同版本的SQL Server投入混合(每MSDN documentation),这只会变得更糟。

你应该对桌面上的PK /唯一设计做些什么来弄清楚哪些上下文会理解这些数据 - 订单号,文件参考,时间戳,设备ID,一些其他业务或逻辑标识符等等....如果没有别的,请用50列伪装它。