SQL Server 2008空字符串与空格

jha*_*ale 81 t-sql sql-server string-length sql-server-2008 datalength

今天早上我遇到了一些奇怪的事情,并认为我会提交评论.

有人可以解释为什么以下SQL查询在针对SQL 2008运行时打印"相等".数据库兼容级别设置为100.

if '' = ' '
    print 'equal'
else
    print 'not equal'
Run Code Online (Sandbox Code Playgroud)

这返回0:

select (LEN(' '))
Run Code Online (Sandbox Code Playgroud)

它似乎是自动修剪空间.我不知道在以前版本的SQL Server中是否就是这种情况,我不再需要测试它.

我遇到了这个,因为生产查询返回了错误的结果.我无法在任何地方找到这种行为.

有没有人有这方面的任何信息?

but*_*ken 84

varchar在TSQL中,s和平等是棘手的.该LEN函数表示:

返回给定字符串表达式的字符数,而不是字节数,不包括尾随空格.

您需要使用DATALENGTH来获得有byte问题的数据的真实计数.如果您有unicode数据,请注意在这种情况下获得的值与文本的长度不同.

print(DATALENGTH(' ')) --1
print(LEN(' '))        --0
Run Code Online (Sandbox Code Playgroud)

当谈到表达式的相等性时,将比较两个字符串的相等性,如下所示:

  • 获得更短的字符串
  • 用空白填充,直到长度等于较长的字符串
  • 比较两者

这是导致意外结果的中间步骤 - 在该步骤之后,您有效地将空白与空白进行比较 - 因此它们被视为相等.

LIKE表现好=于"空白"情况,因为它不会对您尝试匹配的模式执行空白填充:

if '' = ' '
print 'eq'
else
print 'ne'
Run Code Online (Sandbox Code Playgroud)

会给予eq同时:

if '' LIKE ' '
print 'eq'
else
print 'ne'
Run Code Online (Sandbox Code Playgroud)

会给 ne

LIKE虽然小心:它不是对称的:它将尾随空格视为模式(RHS)中的重要空白而不是匹配表达式(LHS).以下是从这里采取的:

declare @Space nvarchar(10)
declare @Space2 nvarchar(10)

set @Space = ''
set @Space2 = ' '

if @Space like @Space2
print '@Space Like @Space2'
else
print '@Space Not Like @Space2'

if @Space2 like @Space
print '@Space2 Like @Space'
else
print '@Space2 Not Like @Space'

@Space Not Like @Space2
@Space2 Like @Space
Run Code Online (Sandbox Code Playgroud)

  • @butterchicken:对不起这么晚的帖子,我刚看到这个问题,但是当我在我的`sql-server-2008 r2上运行这个(最后一个)时,我得到了,`@ Space不喜欢@Space2 @ Space2不喜欢@Space` 知道为什么吗? (3认同)
  • 问题比将空格与空字符串进行比较要大.比较以不同数量的空格结尾的任何两个字符串表现出相同的行为. (2认同)

Ste*_*ass 19

=运算符是T-SQL并不是"等于",因为"根据表达式上下文的排序规则,它是相同的单词/短语",而LEN是"单词/短语中的字符数".没有归类将尾随空白视为它们之前的单词/短语的一部分(尽管它们确实将前导空格视为它们之前的字符串的一部分).

如果你需要将'this'与'this'区分开来,你不应该使用"是相同的单词或短语"运算符,因为'this'和'this'是同一个单词.

对way = works的贡献是,字符串相等运算符应该依赖于它的参数的内容和表达式的排序上下文,但它不应该依赖于参数的类型,如果它们都是字符串类型的话.

"这些是同一个词"的自然语言概念通常不够精确,不能被像=这样的数学运算符捕获,并且在自然语言中没有字符串类型的概念.上下文(即整理)很重要(并且以自然语言存在)并且是故事的一部分,而其他属性(一些看起来很古怪)是=的定义的一部分,以便在非自然世界中明确定义数据.

在类型问题上,当它们存储在不同的字符串类型中时,您不希望更改单词.例如,类型VARCHAR(10),CHAR(10)和CHAR(3)都可以包含单词'cat'的表示,并且?='cat'应该让我们决定这些类型的值是否包含单词'cat'(由排序确定的案例和重音问题).

回复JohnFx的评论:

请参阅联机丛书中使用char和varchar数据.从该页面引用,强调我的:

每个char和varchar数据值都有一个排序规则.排序定义属性,例如用于表示每个字符的位模式, 比较规则以及对大小写或重音的敏感性.

我同意它可能更容易找到,但它已被记录.

值得注意的是,SQL的语义,其中=与现实世界数据和比较的上下文(与存储在计算机上的位相对的东西相反)已经成为SQL的一部分很长一段时间了.RDBMS和SQL的前提是真实数据的忠实表示,因此在类似的想法(例如CultureInfo)进入类似Algol语言的领域之前,它多年来支持整理.这些语言的前提(至少直到最近)是工程中的问题解决,而不是业务数据的管理.(最近,在搜索等非工程应用程序中使用类似语言正在取得一些进展,但Java,C#等依旧在其非商业根源上挣扎.)

在我看来,批评SQL与"大多数编程语言"不同是不公平的.SQL旨在支持业务数据建模的框架,该框架与工程非常不同,因此语言不同(并且更好地实现其目标).

哎呀,首次指定SQL时,某些语言没有任何内置字符串类型.而在某些语言中,字符串之间的equals运算符根本不会比较字符数据,而是比较引用!如果在另一个十年或两年内,==依赖文化的想法成为常态,我不会感到惊讶.

  • BOL 是这样描述 = 运算符的:“比较两个表达式的相等性(比较运算符)。” 无论这种行为是否正确,您都必须承认在大多数编程语言中使用此运算符是极其混乱和不标准的。MS 至少应该在文档中添加有关此行为的警告。 (2认同)

Joh*_*nFx 9

我发现这篇博客文章描述了行为并解释了原因.

SQL标准要求字符串比较有效地用空格字符填充较短的字符串. 这导致令人惊讶的结果N''= N''(空字符串等于一个或多个空格字符的字符串),并且更通常地,如果它们仅仅通过尾随空格区别,则任何字符串等于另一个字符串.在某些情况下,这可能是一个问题.

更多信息也可以在MSKB316626找到


Ada*_*Dev 5

前段时间有一个类似的问题,我在这里调查了一个类似的问题

而不是LEN(''),请使用DATALENGTH('')-为您提供正确的值。

解决方案是使用LIKE子句(如我在此处的答案所述),和/或在WHERE子句中包含第二条件以检查DATALENGTH。

阅读该问题及其中的链接。