如何使SQL Server返回FALSE以比较带有和不带尾随空格的varchars?

时间:2010-10-15 00:21:15

标签: sql-server varchar

如果我故意在VARCHAR列中存储尾随空格,我如何强制SQL Server将数据视为不匹配?

SELECT 'foo' WHERE 'bar' = 'bar    '

我试过了:

SELECT 'foo' WHERE LEN('bar') = LEN('bar    ')

我看到浮动的一种方法是在每个字符串的末尾添加一个特定字符,然后将其删除以用于我的演示......但这看起来很傻。

有没有一种方法我忽略了?

我注意到它不适用于前导空间,所以也许我运行一个在比较之前反转字符顺序的函数....问题是这使得查询unSARGable .. ..

7 个答案:

答案 0 :(得分:6)

来自LEN (Transact-SQL)上的文档:

  

返回指定字符串表达式的字符数,不包括尾随空白。要返回用于表示表达式的字节数,请使用DATALENGTH函数

此外,来自How SQL Server Compares Strings with Trailing Spaces上的支持页面:

  

SQL Server遵循ANSI / ISO SQL-92规范,介绍如何将字符串与空格进行比较。 ANSI标准要求填充比较中使用的字符串,以便在比较它们之前匹配它们的长度

更新我使用LIKE(在比较期间不填充空格)和DATALENGTH()删除了我的代码,因为它们对于比较字符串并非万无一失

在许多其他地方也有人问过其他解决方案:

答案 1 :(得分:3)

就像你说的,我不认为有很多选择。我能想出的唯一两个是:

DECLARE @x nvarchar(50)
DECLARE @y nvarchar(50)
SET @x = 'CAT     '
SET @y = 'CAT'

SELECT 1 WHERE len(@x + '_') = len(@y + '_')

SELECT 1 WHERE reverse(@x) = reverse(@y)

修改

第三个想法:

SELECT 1 WHERE REPLACE(@x, ' ', '_') = REPLACE(@y, ' ', '_')

还有第四个,假设您使用的是SQL 2005 +

SELECT 1 WHERE QUOTENAME(@x) = QUOTENAME(@y)

就个人而言,我最喜欢reverse这个想法,但这一切都取决于哪一个最适合你。

答案 2 :(得分:2)

你可以尝试这样的事情:

declare @a varchar(10), @b varchar(10)
set @a='foo'
set @b='foo   '

select @a, @b, DATALENGTH(@a), DATALENGTH(@b)

答案 3 :(得分:1)

我只有两个建议。一种是重新审视需要您存储尾随空格的设计 - 在SQL中处理它们总是很痛苦。

第二个(给出您的SARG能力评论)是将已计算的列添加到存储长度的表中,并将此列添加到适当的索引。这样,至少,长度比较应该是SARG能力的。

答案 4 :(得分:1)

经过一番搜索,我找到的最简单的解决方案是Anthony Bloesch WebLog

只需在数据末尾添加一些文字(字符就够了)(追加)

SELECT 'foo' WHERE 'bar' + 'BOGUS_TXT' = 'bar    ' + 'BOGUS_TXT'

也适用于'WHERE IN'

SELECT <columnA>
FROM <tableA>
WHERE <columnA> + 'BOGUS_TXT' in ( SELECT <columnB> + 'BOGUS_TXT' FROM <tableB> )

答案 5 :(得分:1)

我打算使用的方法是使用正常的比较,该比较应该是索引可键控的(“sargable”),由DATALENGTH补充(因为LEN忽略空格)。它看起来像这样:

DECLARE @testValue VARCHAR(MAX) = 'x';

SELECT t.Id, t.Value
FROM dbo.MyTable t
WHERE t.Value = @testValue AND DATALENGTH(t.Value) = DATALENGTH(@testValue)

由查询优化器来决定过滤器的顺序,但如果对正在测试的表有意义,则应该选择使用索引进行数据查找,然后通过长度进一步过滤剩余的结果更昂贵的标量操作。但是,正如另一个答案所述,最好通过使用索引计算列来完全避免这些标量操作。如果您无法控制架构,或者如果您想避免创建计算列,或者创建和维护计算列被认为比查询性能更差,那么此处介绍的方法可能有意义。

答案 6 :(得分:0)

有时候最愚蠢的解决方案是最好的:

SELECT 'foo' WHERE 'bar' + 'x' = 'bar     ' + 'x'

因此,在进行比较之前,基本上将任何字符都添加到两个字符串中。