2012-02-27 83 views
8

我正在使用Microsoft SQL Server 2008 R2(具有最新的Service Pack /修补程序),数据库归类为SQL_Latin1_General_CP1_CI_AS。唯一索引,varchar列和(空格)空格的行为

以下代码:

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行(S))

消息2601,级别14,状态1,行8

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

该声明已终止。

‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐

>样品<

(1行(一个或多个)受影响)

我的问题s是:

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

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

回答

11

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服用。)

+2

感谢您的指针,伙计们。因为我自己对Google太懒惰了。在我看来,标准定义的行为并不直观。我可以想象,10个开发者中有9个会说'a'和'a'不是同一个字符串,但是哦。 – Eric 2012-02-27 17:26:45