唯一索引值中有问题的斜线和问号

coc*_*lla 5 sql-server unicode sql-server-2016

PhoneSQL Server 在唯一索引中将它们视为相同的下面插入的值是什么意思?

CREATE TABLE Phone
(
  Id int identity(1, 1) primary key,
  Phone nvarchar(448) not null
)
go

create unique index IX_Phone on Phone(Phone)
with (data_compression = page);
go

insert into Phone Values ('?281/?263-?8400');
insert into Phone Values ('?281/?263-?8400');

select * from Phone;

drop table Phone;
Run Code Online (Sandbox Code Playgroud)

我收到一条错误消息:

消息 2601,级别 14,状态 1,第 13 行无法在唯一索引为“IX_Phone”的对象“dbo.Phone”中插入重复的键行。重复的键值为 (?281/?263-?8400)。

sep*_*pic 4

您的问题是您将unicode字符串作为non-unicode传递。

\n\n

你的\'\xe2\x80\x8e281/\xe2\x80\x8e263-\xe2\x80\x8e8400\'是一个15个字符的字符串,而不是12个,有3个不可打印的8206符号,从左到右标记

\n\n
select len(\'\xe2\x80\x8e281/\xe2\x80\x8e263-\xe2\x80\x8e8400\'); -- 15 !!!\n
Run Code Online (Sandbox Code Playgroud)\n\n

尝试一下我将 unicode 值作为unicode传递的代码,看看完全没有问题:

\n\n
CREATE TABLE dbo.Phone\n(\n  Id int identity(1, 1) primary key,\n  Phone nvarchar(448) not null\n)\ngo\n\ncreate unique index IX_Phone on Phone(Phone)\nwith (data_compression = page);\ngo\n\ninsert into Phone(phone) Values (N\'?281/?263-?8400\');\ninsert into Phone(phone) Values (N\'\xe2\x80\x8e281/\xe2\x80\x8e263-\xe2\x80\x8e8400\');\n\nselect * from Phone;\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是你的字符串 \'\xe2\x80\x8e281/\xe2\x80\x8e263-\xe2\x80\x8e8400\' 真正包含的内容(dbo.nums是我包含自然数的表):

\n\n
declare @t table(col1 nvarchar(100), col2 nvarchar(100));\ninsert into @t values (N\'?281/?263-?8400\',  N\'\xe2\x80\x8e281/\xe2\x80\x8e263-\xe2\x80\x8e8400\'); \n\nselect n, unicode(substring(col1, n, 1)), unicode(substring(col2, n, 1))\nfrom @t cross join dbo.nums\nwhere n <= 15;\n
Run Code Online (Sandbox Code Playgroud)\n\n

在此输入图像描述

\n\n

现在,当您将 unicode 字符串作为非 unicode 传递时会发生什么。

\n\n

您的不可打印符号 8206 会转换为?,这就是非 unicode 字符串的工作方式:在相应代码页中找不到并表示为 ascii 代码的每个字符都用问号替换。

\n\n

因此,例如,如果您使用拉丁语排序规则并尝试比较希伯来语和西里尔字符(相同数量的字符),因为varchar它们总是相等,只是因为它们在比较时被转换为问号nvarchar它们不同:

\n\n

在此输入图像描述

\n\n

因此,如果现在您尝试将这 2 个值(希伯来语 + 西里尔字母)插入到您的 Phone 表中,将它们传递为non-unicode(不使用N)传递,则只会插入其中一个,而另一个将被唯一约束拒绝。\n并且如果您尝试从电话中选择,将返回“??????”

\n