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
答案 0 :(得分:1)
它得到了正确的填充。当您尝试指定通常应该等效的数字十六进制值时,BINARY
数据会变得棘手。如果您尝试这样做,它将起作用:
insert into #sql_table1 values (0x32),(CAST(50 as VARBINARY(25)));
-- inserts 0x00000032
-- and 0x32
但这些在数值上是等价的。一般来说,将任何类型的BINARY
列作为主键或尝试在其上添加唯一索引是一个坏主意(比CHAR
/ VARCHAR
/ {{更多1}}列) - 任何插入其中的应用程序几乎肯定会NVARCHAR
从某些本机格式/表示形式转换为二进制,但不能保证CAST
实际上以独特的方式工作在任一方向 - 应用程序是否插入值CAST
(50
),或者是否尝试插入文字= 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
列伪装它。