SQL WHERE 子句将值与尾随空格匹配

Posted

技术标签:

【中文标题】SQL WHERE 子句将值与尾随空格匹配【英文标题】:SQL WHERE clause matching values with trailing spaces 【发布时间】:2011-05-09 03:30:19 【问题描述】:

在 SQL Server 2008 中,我有一个名为 Zone 的表,其中有一个列 ZoneReference varchar(50) not null 作为主键。

如果我运行以下查询:

select '"' + ZoneReference + '"' as QuotedZoneReference
from Zone
where ZoneReference = 'WF11XU'

我得到以下结果:

"WF11XU "

注意尾随空格。

这怎么可能?如果该行上确实存在尾随空格,那么我希望返回 zero 结果,所以我假设它是 SQL Server Management Studio 奇怪地显示的其他内容。

在 C# 代码中调用 zoneReference.Trim() 会删除它,这表明它是某种空白字符。

谁能帮忙?

【问题讨论】:

【参考方案1】:

这是预期的结果:在 SQL Server 中,= 运算符在进行比较时会忽略尾随空格。

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 规范部分。

Source

【讨论】:

我相信WHERE ZoneReference = 'WF11XU' AND DATALENGTH(ZoneReference) = DATALENGTH('WF11XU') 也会起作用,并且可能比LIKE 更快 @MarkByers 是的,我明白了 - 我试过 where 'WF11XU' like ZoneReference 并且成功了!越来越诡异。不过,每天都是上学日! LIKE 不能双向工作,SELECT IIF('WF11XU ' LIKE 'WF11XU', 1, 0) 返回1【参考方案2】:

尾随空格并不总是被忽略。 我今天遇到了这个问题。我的表有 NCHAR 列并且正在连接到 VARCHAR 数据。 由于表中的数据没有字段宽,SQL Server 会自动添加尾随空格。

我有一个采用 varchar 参数的 ITVF(内联表值函数)。 这些参数用于与具有 NCHAR 字段的表的 JOIN。

连接失败,因为传递给函数的数据没有尾随空格,但表中的数据有。为什么会这样?

我被数据类型优先级绊倒了。 (见http://technet.microsoft.com/en-us/library/ms190309.aspx)

在比较不同类型的字符串时,先将低优先级类型转换为高优先级类型再进行比较。所以我的 VARCHAR 参数被转换为 NCHAR。比较了 NCHAR,显然空间​​很重要。

我是如何解决这个问题的?我更改了函数定义以使用 NVARCHAR 参数,这些参数的优先级高于 NCHAR。现在 SQL Server 自动将 NCHAR 更改为 NVARCHAR,并且忽略尾随空格。

我为什么不直接执行 RTRIM?测试表明,RTRIM 降低了性能,阻止了 SQL Server 原本会使用的 JOIN 优化。

为什么不改变表的数据类型呢?这些表已经安装在客户站点上,他们不想运行维护脚本(时间+金钱来支付 DBA)或让我们访问他们的机器(可以理解)。

【讨论】:

【参考方案3】:

是的,马克是正确的。运行以下 SQL:

create table #temp (name varchar(15))
insert into #temp values ('james ')
select '"' + name + '"' from #temp where name ='james'
select '"' + name + '"' from #temp where name like 'james'
drop table #temp

但是,关于“like”语句的断言在上面的示例中似乎不起作用。输出:

(1 row(s) affected)

-----------------
"james "

(1 row(s) affected)


-----------------
"james "

(1 row(s) affected)

编辑: 为了让它工作,你可以把它放在最后:

and name <> rtrim(ltrim(name))

虽然丑。

EDIT2: 鉴于上面的 cmets,以下将起作用:

select '"' + name + '"' from #temp where 'james' like name

【讨论】:

【参考方案4】:

试试

    select Replace('"' + ZoneReference + '"'," ", "") as QuotedZoneReference from Zone where ZoneReference = 'WF11XU'

【讨论】:

你有点没抓住重点。关键是我没想到where 子句会匹配这条记录。 是的,我认为 Neil 知道该怎么做,他只是想知道为什么他会看到观察到的行为。 恐怕我投了反对票,因为这篇文章没有帮助,因为它偏离了正在回答的实际问题。

以上是关于SQL WHERE 子句将值与尾随空格匹配的主要内容,如果未能解决你的问题,请参考以下文章

SQL查询where子句如果没有匹配记录则省略

SQL WHERE 子句中的 IF 语句

SQL - 使用常量值与参数的任何性能差异?

SQL在where子句中转换日期格式

SQL WHERE 子句与拉丁文和泰文字符的列不匹配

where 子句限制完全匹配的行,显示部分匹配的行