唯一索引,varchar列和(空白)空格的行为

Eri*_*ric 11 t-sql sql-server unique-index string-comparison

我正在使用Microsoft SQL Server 2008 R2(带有最新的Service Pack/patches),数据库排序规则是SQL_Latin1_General_CP1_CI_AS.

以下代码:

SET ANSI_PADDING ON;
GO

CREATE TABLE Test (
   Code VARCHAR(16) NULL
);
CREATE UNIQUE INDEX UniqueIndex
    ON Test(Code);

INSERT INTO Test VALUES ('sample');
INSERT INTO Test VALUES ('sample ');

SELECT '>' + Code + '<' FROM Test WHERE Code = 'sample        ';
GO
Run Code Online (Sandbox Code Playgroud)

产生以下结果:

(1排受影响)

Msg 2601,Level 14,State 1,Line 8

无法在对象'dbo.Test'中插入具有唯一索引'UniqueIndex'的重复键行.重复键值为(样本).

该语句已终止.

------------

>样品<

(1排受影响)

我的问题是:

  1. 我假设索引不能存储尾随空格.任何人都可以指向我指定/定义此行为的官方文档吗?
  2. 是否有一个设置来改变这种行为,也就是说,让它将'sample'和'sample'识别为两个不同的值(顺便说一句,它们都是这样),因此两者都可以在索引中.
  3. 为什么地球上的SELECT会返回一行?SQL Server必须使用WHERE子句中的空格做一些非常有趣/聪明的事情,因为如果删除索引中的唯一性,两个INSERT都将运行正常,SELECT将返回两行!

任何帮助/指针在正确的方向将不胜感激.谢谢.

Ole*_*Dok 14

尾随空白解释:

SQL Server遵循ANSI/ISO SQL-92规范(第8.2节,一般规则#3)关于如何比较字符串 和空格.ANSI标准要求对比较中使用的字符串进行填充,以便在比较它们之前使它们的长度匹配.填充直接影响WHERE和HAVING子句谓词以及其他Transact-SQL字符串比较的语义.例如,Transact-SQL认为字符串'abc'和'abc'在大多数比较操作中都是等效的.

此规则的唯一例外是LIKE谓词.当LIKE谓词表达式的右侧具有带尾随空格的值时,SQL Server不会在比较发生之前将这两个值填充到相同的长度.因为根据定义,LIKE谓词的目的是促进模式搜索而不是简单的字符串相等性测试,这不违反前面提到的ANSI SQL-92规范的部分.

这是上面提到的所有案例的一个众所周知的例子:

DECLARE @a VARCHAR(10)
DECLARE @b varchar(10)

SET @a = '1'
SET @b = '1 ' --with trailing blank

SELECT 1
WHERE 
    @a = @b 
AND @a NOT LIKE @b
AND @b LIKE @a
Run Code Online (Sandbox Code Playgroud)

这里有关于尾随空白和LIKE子句的更多细节.

关于指数:

如果提供的值仅通过尾随空格提供与现有值不同的值,则插入其值必须唯一的列将失败.以下字符串将被唯一约束,主键或唯一索引视为等效.同样,如果您有一个包含以下数据的现有表并尝试添加唯一限制,则它将失败,因为这些值被视为相同.

PaddedColumn
------------
'abc'
'abc '
'abc  '
'abc    '
Run Code Online (Sandbox Code Playgroud)

(取自这里.)

  • 伙计们,感谢指点.Mea culpa因为我自己懒得谷歌.在我看来,标准定义的行为并不直观.我想,10个开发者中有9个会说'a'和'a'不是同一个字符串,但是哦. (2认同)