【问题标题】:SQL: Using <= and >= to compare string with wildcardSQL:使用 <= 和 >= 将字符串与通配符进行比较
【发布时间】:2019-02-14 14:54:30
【问题描述】:

假设我的表格如下所示:

Id  |  Name  |  Age
=====================
1   |  Jose  | 19

2   |  Yolly | 26

20  |  Abby  | 3

29  |  Tara  | 4

而我的查询语句是:

1) Select * from thisTable where Name &lt;= '*Abby'; 它返回 0 行

2) Select * from thisTable where Name &lt;= 'Abby'; 与 Abby 一起返回行

3) Select * from thisTable where Name &gt;= 'Abby'; 返回所有行 // 第 1-4 行

4) Select * from thisTable where Name &gt;= '*Abby'; 返回所有行; // 第 1-4 行

5) Select * from thisTable where Name &gt;= '*Abby' and Name &lt;= "*Abby"; 返回 0 行。

6) Select * from thisTable where Name &gt;= 'Abby' and Name &lt;= 'Abby'; 与 Abby 一起返回行;

我的问题:为什么我会得到这些结果?通配符如何影响查询结果?如果条件是Name &lt;= '*Abby',为什么我没有得到任何结果?

【问题讨论】:

  • 通配符不是比较。 SQL,这种语言,无论如何都不使用* 作为通配符。如果要执行通配符搜索,请使用LIKE,例如LIKE 'Abby%'
  • 您的所有结果都被简单地解释为* 在这里没有特殊含义,无论您使用什么排序规则,它都排在A 之前。
  • 您不要在文本列上使用&gt;=&lt;= 等。对于通配符搜索,请使用 LIKE
  • 比较字符串时,*_% 只是字符。在*B 之间应用与AB 之间相同的排序规则。
  • 即使星号是一个通配符(它不是),你希望发生什么? '*' 将匹配 'A' 和 'Z' (以及任何其他字符甚至字符组)。那么“Jose”会出现在“*Abby”之前还是之后呢?它肯定在“AAbby”之后和“ZAbby”之前。这种比较没有任何意义,对吧?

标签: sql sql-server wildcard string-comparison


【解决方案1】:

在 SQL Server 中处理字符串时,对每个字母进行排序,这些字母的排序顺序取决于排序规则。对于某些字符,排序方法更容易理解,它是按字母或数字顺序排列的:例如'a' &lt; 'b''4' &gt; '2'。根据排序规则,这可能是先字母再大写 ('AaBbCc....'),也可能是先大写再字母 ('ABC...Zabc')。

我们取一个像'Abby'这样的字符串,它会按照字母A、b、b、y的顺序排序(它们出现的顺序会根据你的排序,我不知道它是什么是,但我将假设 'AaBbCc....' 排序规则,因为它们更常见)。任何以'Aba' 开头的字符串都将具有比'Abby' 出售的价值,因为第三个字符(第一个不同的字符)具有“较低的价值”。就像'Abbie' 这样的值('i' 的值低于'y')。同样,像'Abc' 这样的字符串会有更大的值,因为'c' 的值高于'b'(这是第一个不同的字符)。

如果我们将数字混入其中,您可能会感到惊讶。例如字符串(重要,我没有说明数字)'123456789' 的值低于 字符串'9'。这是因为第一个字符比第一个字符不同。 '9' 大于 '1',因此 '9' 具有“更高”的值。这就是为什么确保将数字存储为数值数据类型如此重要的原因之一,因为否则行为不太可能是您所期望/想要的。

但是,对于您要问的问题,SQL Server 的通配符是 '%''_'(还有 '^',m 但我不会在这里介绍)。 '%' 表示多个字符,而 '_' 表示单个字符。如果您想专门查找其中一个字符,您必须在括号中引用它们 ([])。

使用等于 (=) 运算符不会解析通配符。你需要使用一个函数,比如LIKE。因此,如果您想要一个以'A' 开头的单词,您可以使用表达式WHERE ColumnName LIKE 'A%'。如果您想搜索包含 6 个字符并以 'ed' 结尾的字符,您可以使用 WHERE ColumnName LIKE '____ed'

就像我之前说的,如果您想搜索其中一个特定字符,请引用。因此,如果您想搜索包含下划线的字符串,则语法为 WHERE ColumnName LIKE '%[_]%'

编辑:同样值得注意的是,当使用像 LIKE 这样的东西时,它们会受到排序规则的影响;例如,大小写和口音。例如,如果您使用区分大小写的排序规则,则声明 WHERE 'Abby' LIKE 'abb%' 不正确,并且 'A''a' 的大小写不同。同样,声明 WHERE 'Covea' = 'Covéa' 在区分重音的排序规则中为 false('e''é' 不被视为相同的字符)。

【讨论】:

    【解决方案2】:

    有一些答案,还有一些 cmets - 我会试着总结一下。

    首先,wildcard in SQL 是 %,而不是 *(用于多个匹配项)。因此,包括 * 在内的查询要求与该文字字符串进行比较。

    其次,比较具有大于/小于运算符的字符串可能不会达到您想要的效果 - 它使用 collation order 来查看排序顺序中哪些其他字符串“较早”或“较晚”。排序顺序是一个中等复杂的概念,并且会因机器安装而异。

    SQL operator for string pattern matchingLIKE

    我不确定我是否理解您使用 &gt;=&lt;= 语句的意图 - 您的意思是要返回名称的第一个字母在字母表中的“A”之后的行吗?

    【讨论】:

      【解决方案3】:

      通配符用于替换字符串中的任何其他字符。它们与WHERE 子句中的SQL LIKE 运算符一起使用。例如。

      Select * from thisTable WHERE name LIKE '%Abby%'
      

      这将返回字符串中任意位置的任何 Abby 值。

      查看此链接了解所有通配符https://www.w3schools.com/sql/sql_wildcards.asp

      【讨论】:

        【解决方案4】:

        只有在您使用 LIKE 运算符时才会解释通配符。

        因此,当您尝试与字符串进行比较时,它将按字面意思进行处理。因此,在您的比较中使用了字典顺序。

        1) * 之前没有字母,因此您没有返回任何行。

        2) A 是字母表中的第一个字母,所以其余的名字更大然后是 Abby,只有 Abby 等于它自己。

        3) 与 2) 相反

        4) 见 1)

        5) 见 1)

        6) 这个条件等价于Name = 'Abby'

        【讨论】:

          【解决方案5】:

          这是因为&gt;=&lt;= 是比较运算符。他们根据 ASCII 值比较字符串。

          由于 * 的 ASCII 值是 42 并且大写字母的 ASCII 值从 65 开始,这就是为什么当您尝试 name&lt;='*Abby' , sql-server 选择了字符串中第一个字符的 ASCII 值(即 42),因为您的数据中没有任何值的第一个字符的 ASCII 值小于 42,因此没有选择数据。

          您可以参考 ASCII 表了解更多:

          http://www.asciitable.com/

          【讨论】:

          • 不,SQL Server 使用 collat​​ions 来确定排序顺序。很少有排序规则遵循 ASCII 规则。
          • @Damien_The_Unbeliever 是正确的。在某些排序规则上,例如 'B' &gt; 'a',但是在其他排序规则上是 'B' &lt; 'a'
          猜你喜欢
          • 2014-11-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-20
          • 2010-10-06
          相关资源
          最近更新 更多