代码之家  ›  专栏  ›  技术社区  ›  jhale

SQL Server 2008空字符串与空间

  •  77
  • jhale  · 技术社区  · 17 年前

    今天早上我遇到了一件有点奇怪的事情,我想我会把它交给评论。

    有人能解释为什么在对SQL 2008运行时,以下SQL查询会打印“equal”。数据库兼容级别设置为100。

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

    返回0:

    select (LEN(' '))
    

    它似乎在自动修剪空间。我不知道在以前的SQL Server版本中是否会出现这种情况,而且我再也没有机会测试它了。

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

    有人知道这方面的情况吗?

    7 回复  |  直到 10 年前
        1
  •  79
  •   butterchicken    15 年前

    varchar 在TSQL中,S和平等是棘手的。这个 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

    小心 喜欢 尽管:它不是对称的:它在模式(rhs)中将尾随空格视为显著的,而不是匹配表达式(lhs)。以下内容摘自 here :

    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
    
        2
  •  17
  •   Steve Kass    17 年前

    根据表达式上下文的排序规则,=operator is t-sql不像“equals”那样“是同一个单词/短语”,len是“单词/短语中的字符数”。没有排序规则将尾随空格视为它们前面的单词/短语的一部分(尽管它们确实将前导空格视为它们前面的字符串的一部分)。

    如果需要区分“this”和“this”,则不应使用“are the same word or phrase”运算符,因为“this”和“this”是同一个词。

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

    “这些是同一个词”的自然语言概念通常不够精确,无法被数学运算符(如=)捕获,自然语言中没有字符串类型的概念。上下文(即,整理)很重要(并且存在于自然语言中),是故事的一部分,而附加属性(有些似乎很奇怪)是=定义的一部分,以便在非自然的数据世界中对其进行定义。

    在类型问题上,当单词存储在不同的字符串类型中时,您不希望它们发生更改。例如,varchar(10)、char(10)和char(3)类型都可以保存单词“cat”的表示,并且?='cat'应该让我们决定这些类型的值是否包含单词'cat'(大小写和重音问题由排序规则决定)。

    对johnfx评论的回应:

    Using char and varchar Data 在网上的书中。引用那一页,强调我的:

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

    我同意这可能更容易找到,但有文件证明。

    同样值得注意的是,SQL的语义,其中=与实际数据和比较上下文(与存储在计算机上的位相反)有很长一段时间是SQL的一部分。RDBMSS和SQL的前提是真实数据的忠实表示,因此在类似的思想(如cultureInfo)进入类似algol的语言领域之前,RDBMS和SQL支持多年的排序。这些语言(至少直到最近)的前提是在工程中解决问题,而不是管理业务数据。(最近,类似的语言在搜索等非工程应用中的使用正在产生一些影响,但Java、C等仍在与它们的非商业根源斗争。)

    在我看来,批评SQL不同于“大多数编程语言”是不公平的。SQL的设计是为了支持一个与工程非常不同的业务数据建模框架,因此该语言是不同的(并且更好地实现其目标)。

    heck,当第一次指定SQL时,某些语言没有任何内置的字符串类型。在某些语言中,字符串之间的equals运算符根本不比较字符数据,而是比较引用!如果在未来的十年或二十年里,==文化依赖性的想法成为常态,我也不会感到惊讶。

        3
  •  9
  •   JohnFx    17 年前

    我发现了这个 blog article 它描述了行为并解释了原因。

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

    更多信息也可在 MSKB316626

        4
  •  4
  •   Community Mohan Dere    9 年前

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

    使用datalength(“”)而不是len(“”),它提供正确的值。

    解决方案是使用一个类似的子句,如我在这里的答案中所解释的,和/或在WHERE子句中包含第二个条件来检查数据长度。

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

        5
  •  3
  •   David G    15 年前

    要将值与文本空间进行比较,还可以使用此技术作为LIKE语句的替代方法:

    IF ASCII('') = 32 PRINT 'equal' ELSE PRINT 'not equal'
    
        6
  •  0
  •   Herbert    11 年前

    有时必须处理数据中的空格,包括或不包括任何其他字符,即使使用空值的想法更好——但并不总是可用的。 我确实遇到了所描述的情况,并通过以下方式解决了它:

    …其中(“>'+@space+'<')<gt;('>'+@space2+'<')

    当然,你不会做大量的FPR数据,但它工作迅速和容易,为几百行…

    赫伯特

        7
  •  0
  •   Orix    11 年前

    如何在SQL Server上使用字段char/varchar区分select上的记录: 例子:

    declare @mayvar as varchar(10)
    
    set @mayvar = 'data '
    
    select mykey, myfield from mytable where myfield = @mayvar
    

    预期

    mykey(int)myfield(varchar10)

    1“数据”

    获得

    米基米菲尔德

    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上有一个索引,它将在每种情况下使用。

    我希望它会有帮助。

    推荐文章