今天早上我遇到了一些奇怪的事情,我想我应该将其提交以供评论。

有人可以解释为什么以下 SQL 查询在针对 SQL 2008 运行时会打印“等于”吗?数据库兼容性级别设置为 100。

if '' = ' '
    print 'equal'
else
    print 'not equal'

返回 0:

select (LEN(' '))

它似乎正在自动修剪空间。我不知道以前版本的 SQL Server 中是否存在这种情况,而且我也没有办法测试它。

我遇到这个问题是因为生产查询返回了错误的结果。我在任何地方都找不到这种行为的记录。

有人有这方面的信息吗?

有帮助吗?

解决方案

varchars 和相等性在 TSQL 中是棘手的。这 LEN 函数说:

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

你需要使用 DATALENGTH 得到一个真实的 byte 相关数据的计数。如果您有 unicode 数据,请注意,在这种情况下您获得的值将与文本的长度不同。

print(DATALENGTH(' ')) --1
print(LEN(' '))        --0

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

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

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

LIKE 表现得比 = 在“空白”情况下,因为它不会对您尝试匹配的模式执行空白填充:

if '' = ' '
print 'eq'
else
print 'ne'

会给 eq 尽管:

if '' LIKE ' '
print 'eq'
else
print 'ne'

会给 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

其他提示

=运算符是T-SQL与其说“等于”,因为它是“相同词/短语,根据表达式的上下文的整理”和LEN是“在单词中的字符数/短语。”没有归类请客尾随空白作为词/短语部分前述它们(虽然他们治疗的前导空白,因为它们先于字符串的一部分)。

如果您需要区分“这”从“这个”,你不应该用“是同一个词或短语”运算符,因为“这个”和“本”是同一个词。

贡献的方式=作品是,字符串相等运算应取决于它的参数的内容以及在表达的整理上下文想法,但它不应该依赖于类型的参数,如果它们是两个字符串类型。

的“这些是相同的单词”自然语言概念通常不是足够精确的,以便能够通过像=数学运算符来捕捉,而且也没有在自然语言串类型的概念。上下文(即整理)事项(以及自然语言存在),是故事的一部分,和其他属性(一些看似古怪的)是=的定义的一部分,以使非自然世界里明确数据

在该类型的问题,你不希望的话变化时,它们存储在不同的字符串类型。例如,类型VARCHAR(10),CHAR(10)和CHAR(3)这个词 '猫',以及所有持有交涉? =“猫”应该让我们决定是否任何这些类型的一个值保持字“猫”(与由核对确定大小写和重音的问题)。

<强>响应于JohnFx的评论:

请参阅使用char和varchar数据联机丛书的。从该页面,重点煤矿引用:

  

每个char和varchar数据值具有排序规则。排序规则定义   作为位模式用来表示每个字符的属性,例如,   的 比较规则 ,然后灵敏度情况下或重音。

我同意它可能是更容易找到,但它的记录。

值得注意的,也就是SQL的语义,其中=必须与真实世界的数据和比较(相对于一些关于存储在计算机上的比特)的情况下做已经SQL的部分很长一段时间。的RDBMS和SQL的前提是真实世界的数据的忠实代表,因此它的排序规则的支持,很多年以前类似的想法(如CultureInfo的)进入的类ALGOL语言的境界。这些语言(至少直到最近)的前提是在工程中解决问题,而不是业务数据的管理。 (最近,使用非工程应用,如搜索类似的语言正在采取一些进展,但Java,C#等仍与它们的非businessy根挣扎。)

在我看来,这是不公平的批评SQL的不同于“大多数的编程语言。” SQL旨在支持企业数据建模这是从工程非常不同的框架,所以语言是不同的(和它的目标更好)。

哎呀,当第一次被指定SQL,一些语言没有任何内置的字符串类型。而且在某些语言尽管如此,等于字符串不比较,在所有字符数据之间的运营商,但比较的参考!如果在十年或二十年,那种认为==是文化依赖成为常态它不会让我感到吃惊。

我发现这个博客它描述了行为和文章解释了为什么。

  

<强> SQL标准要求该字符串   比较,有效,垫   较短的字符串与空格字符。   这导致了令人惊讶的结果   该N“” = N”'(空字符串   等于一个或多个空格的字符串   字符),更一般地任何   字符串等于另一个字符串,如果他们   只有尾随空格不同。这个   可以是一个问题在一些情况下

更多信息也可用的 MSKB316626

不久前有一个类似的问题,我研究了类似的问题 这里

使用 DATALENGTH(' ') 代替 LEN(' ') - 这将为您提供正确的值。

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

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

要的值比较,以文字的空间,则也可使用这种技术来替代LIKE语句:

IF ASCII('') = 32 PRINT 'equal' ELSE PRINT 'not equal'

有时一个人来处理空间数据,有或没有任何其它字符,即使使用空的想法是更好 - 但并不总是使用。 我也碰到所描述的情况,并解决了它这种方式:

...其中( '>' + @space + '<')<>( '>' + @空间2 + '<')

当然,你不会这么做的FPR大量的数据,但它工作快速,轻松几百行...

赫伯特

如何在SELECT DISTINCT记录与字段CHAR / VARCHAR SQL Server上: 例如:

declare @mayvar as varchar(10)

set @mayvar = 'data '

select mykey, myfield from mytable where myfield = @mayvar

<强>预期

的myKey(INT)| MyField的(varchar10)

1 | '数据'

<强>获得

的myKey | MyField的

1 | '数据' 2 | '数据'

,即使我的写 select mykey, myfield from mytable where myfield = 'data'(无最终空白) 我得到相同的结果。

我怎么解决?在这种模式下:

select mykey, myfield
from mytable
where myfield = @mayvar 
and DATALENGTH(isnull(myfield,'')) = DATALENGTH(@mayvar)

和是否有上MyField的一个索引,它会被在每种情况下使用。

我希望这将是有益的。

另一种方法是把它放回该空间具有的值的状态。 例如:已知象一个字符替换空间_

if REPLACE('hello',' ','_') = REPLACE('hello ',' ','_')
    print 'equal'
else
    print 'not equal'

返回:不等于

不理想,可能是缓慢的,但另一种快速前进的方向需要时迅速。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top