【问题标题】:Search for “whole word match” with SQL Server LIKE pattern使用 SQL Server LIKE 模式搜索“全词匹配”
【发布时间】:2011-07-23 14:12:18
【问题描述】:

有人有一个只匹配整个单词的LIKE 模式吗?

它需要将空格、标点符号和字符串的开头/结尾作为单词边界。

我没有使用 SQL 全文搜索,因为它不可用。当LIKE 应该能够做到这一点时,我认为没有必要进行简单的关键字搜索。但是,如果有人针对LIKE 模式测试了全文搜索的性能,我很想听听。

编辑:

我到了这个阶段,但它不匹配字符串的开始/结束作为单词边界。

where DealTitle like '%[^a-zA-Z]pit[^a-zA-Z]%' 

我希望它匹配句子或单个单词中的“pit”而不是“spit”。

例如DealTitle 可能包含“绝望的坑”或“坑你的智慧”或“坑”或“坑”。或“坑!”或者只是“坑”。

【问题讨论】:

  • 如果你不知道如何做你需要做的事情,你怎么能说 LIKE 应该能够做到这一点?
  • 您应该为此使用全文搜索。如果它真的不可用(为什么不可用?它甚至带有 Express 和 Advanced Services)CLR 和正则表达式将比 LIKE 更合适
  • 为什么全文搜索比 LIKE 更好。它更快吗?还是您认为 LIKE 无法完成整个单词?
  • 全文搜索带有一个分词器,可以将文本分开并预先索引它们。 LIKE 带有前导通配符将始终涉及对所有数据的全面扫描。
  • 即使在一个句子中,像“pit5”或“3pit”这样的情况呢? '%[^a-z]pit[^a-z]%' 会允许它们,看来你不是故意的。

标签: sql sql-server


【解决方案1】:

您可以在 SQL 中搜索整个字符串:

select * from YourTable where col1 like '%TheWord%'

然后您可以过滤返回的行客户端站点,添加它必须是一个完整的单词的额外条件。例如,如果它匹配正则表达式:

\bTheWord\b

另一种选择是使用 SQL Server 2005 及更高版本中提供的 CLR 函数。这将允许您搜索正则表达式服务器端。这个MSDN artcile 详细介绍了如何设置dbo.RegexMatch 函数。

【讨论】:

    【解决方案2】:

    全文索引就是答案。

    可怜的表亲替代品是

    '.' + column + '.' LIKE '%[^a-z]pit[^a-z]%'
    

    仅供参考,除非您使用 _CS 排序规则,否则不需要 a-zA-Z

    【讨论】:

    • 太棒了。好想法。我不想要全文索引的原因是我不能依赖该选项被打开。无论如何,它实际上明显更好吗?
    • 我该怎么写?.. 是的,是的! (无论如何大部分时间)。简单来说,FTE 将文本列分解为单词并分别索引每个单词。 (普通索引只会将一条记录放入索引一次)所以如果100万条记录中有99条出现了“坑”这个词,那么它与识别100万条记录中的99条记录的普通索引一样好(不执行任何模式匹配),而不是扫描所有这些并为每个执行全字符串长度比较(LIKE)。真是太好了。
    • 好的,谢谢!我想我最好做一些真实世界的测试来检查性能。使用 LIKE 肯定更方便,因为您可以在任何随机字段上执行此操作而无需任何设置,因此这对于例如管理员搜索页面很有用,您可以在其中搜索任何表的任何字段。谢谢。
    • 好的,我已经在一个有 11,000 行的表上进行了测试,在两列中搜索三个关键字。使用全文索引 CONTAINS((col1,col2), 'keyword1 AND keyword2 AND keyword3') 是 15 毫秒,而 LIKE 模式(具有三个 AND 和三个 OR)为 350 毫秒。所以使用全文索引要快 25 倍。但是,考虑到 LIKE 进行全表扫描,它似乎仍然非常有效,因此在某些情况下这肯定是足够的 - 取决于用户量。
    • 关于.(点)字符的解释:[^a-z] 部分需要精确匹配单个字符。所以空字符将不匹配。例如,OP 的 LIKE 不会匹配 'pit'、'pit' 或 'pit'。通过添加点,[^a-z] 部分与这些点匹配。
    【解决方案3】:

    另一个简单的选择:

    WHERE DealTitle like '%[^a-z]pit[^a-z]%' OR 
          DealTitle like '[^a-z]pit[^a-z]%' OR 
          DealTitle like '%[^a-z]pit[^a-z]'
    

    【讨论】:

    • 不处理与 'pit' 的完全相等性
    • 试试这个作为初始词和最终词:WHERE DealTitle like '%[^az]pit[^az]%' OR DealTitle like 'pit[^az]%' OR DealTitle like '%[^ az]pit'
    【解决方案4】:

    我认为推荐的模式排除了开头或结尾没有任何字符的单词。我会使用以下附加标准。

    where DealTitle like '%[^a-z]pit[^a-z]%' OR 
      DealTitle like 'pit[^a-z]%' OR 
      DealTitle like '%[^a-z]pit'
    

    希望对大家有帮助!

    【讨论】:

    • 不处理与 'pit' 的完全相等性
    【解决方案5】:

    这是一个很好的话题,我想补充一下,某人如何需要在某个字符串中找到某个单词,并将其作为查询的元素传递。

    SELECT 
        ST.WORD, ND.TEXT_STRING
    FROM 
        [ST_TABLE] ST
    LEFT JOIN 
        [ND_TABLE] ND ON ND.TEXT_STRING LIKE '%[^a-z]' + ST.WORD + '[^a-z]%'
    WHERE 
        ST.WORD = 'STACK_OVERFLOW' -- OPTIONAL
    

    有了这个,您可以在ND.TEXT_STRING 中列出ST.WORD 的所有出现次数,并且您可以使用WHERE 子句使用一些词来过滤它。

    【讨论】:

      【解决方案6】:

      尝试使用charindex 查找匹配项:

      Select * 
      from table 
      where charindex( 'Whole word to be searched', columnname) > 0
      

      【讨论】:

      • 这不是全词搜索。那仍然是部分单词搜索
      【解决方案7】:

      用空格包围你的字符串并创建一个这样的测试列:

       SELECT t.DealTitle 
       FROM yourtable t
       CROSS APPLY (SELECT testDeal = ' ' + ISNULL(t.DealTitle,'') + ' ') fx1
       WHERE fx1.testDeal LIKE '%[^a-z]pit[^a-z]%'
      

      【讨论】:

        【解决方案8】:

        您可以将以下条件用于空格分隔符:

        (' '+YOUR_FIELD_NAME+' ') like '% doc %'
        

        它比其他解决方案运行得更快更好。所以在你的情况下,它适用于“绝望的坑”或“坑你的智慧”或“一个坑”或“一个坑”。或只是“pit”,但不适用于“pit!”。

        【讨论】:

          【解决方案9】:

          如果您可以在 SQL 查询中使用 regexp 运算符..

          用于查找空格、标点符号和字符串开头/结尾的任意组合作为单词边界:

          where DealTitle regexp '(^|[[:punct:]]|[[:space:]])pit([[:space:]]|[[:punct:]]|$)'
          

          【讨论】:

            猜你喜欢
            • 2012-08-22
            • 1970-01-01
            • 2014-02-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-06-15
            • 2011-08-10
            相关资源
            最近更新 更多