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

时间:2012-02-27 06:01:12

标签: sql-server tsql string-comparison unique-index

我正在使用Microsoft SQL Server 2008 R2(带有最新的Service Pack /补丁程序),数据库归类是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

产生以下结果:

  

(1行受影响)

     

Msg 2601,Level 14,State 1,Line 8

     

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

     

声明已经终止。

     

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

     

&GT;样品&LT;

     

(1行受影响)

我的问题是:

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

1 个答案:

答案 0 :(得分:13)

Trailing blanks explained

  

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

     

此规则的唯一例外是LIKE谓词。当正确的时候   LIKE谓词表达式的一侧具有带尾随的值   空间,SQL Server不会将这两个值填充到相同的长度   在比较之前。因为喜欢的目的   根据定义,谓词是为了促进模式搜索   比简单的字符串相等测试,这不违反该部分   前面提到的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

以下是有关trailing blanks and the LIKE clause的更多详细信息。

关于索引:

  

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

PaddedColumn
------------
'abc'
'abc '
'abc  '
'abc    '

(取自here。)