客户发现了一个错误,在尝试对其进行修复时,我遇到了这种奇怪的现象。我已经花了几个小时对它进行各种测试,但我仍在努力理解它。绝对可以在SQL2016和2017(最新CU)和不同版本的Management Studio上重现。下面的示例是从1000行proc中获取的简化示例:
要开始创建必要的对象,请执行以下操作:
CREATE DATABASE TestDB;
GO
USE TestDB;
CREATE TABLE test (
id int IDENTITY,
pdate datetime);
INSERT test
VALUES('1-Feb-2018'),('1-Mar-2018'),(NULL);
现在快速查看一下表中的值:
SELECT * FROM test
现在我想将pdate转换为特定格式,如果pdate为NULL,则返回一个空字符串:
SELECT * FROM
(
SELECT
id,
IIF(pdate IS NULL, '', FORMAT(pdate, 'yyyy-MM-dd')) pdate2
FROM test
) a
WHERE pdate2 = ''
上面的查询产生带有空字符串的id 3,即预期的结果。但是,当我在引号之间放置任意数量的空格字符时,结果中仍会得到同一行:
SELECT * FROM
(
SELECT
id,
IIF(pdate IS NULL, '', FORMAT(pdate, 'yyyy-MM-dd')) pdate2
FROM test
) a
WHERE pdate2 = ' '
为什么会这样?
如果不是等号,我使用不带通配符的LIKE,即:
SELECT * FROM
(
SELECT
id,
IIF(pdate IS NULL, '', FORMAT(pdate, 'yyyy-MM-dd')) pdate2
FROM test
) a
WHERE pdate2 LIKE ' '
这给了我预期的结果-没有返回行。
这是一个错误,还是有一些深层的技术原因可将空字符串视为等于n个空格字符的字符串?如果是这样,那么为什么LIKE给我正确的结果?
答案 0 :(得分:2)
根据ANSI SQL标准,字符字段比较通常忽略尾随空格。所以这个:
SELECT 1 WHERE '' = ' '
将返回1
。
KB316626 INF: How SQL Server Compares Strings with Trailing Spaces 描述了这种行为(强调我的行为):
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规范。
[...]
SET ANSI_PADDING设置不会影响SQL Server填充 字符串比较之前。 SET ANSI_PADDING仅影响是否 从插入表中的值中修剪掉尾随的空白, 因此它会影响存储,但不会影响比较。
请注意,它们也涵盖了您在LIKE中发现的差异。
Brent Ozar关于此行为here的博客。