Sql server 带异常的T-SQL模式匹配

Sql server 带异常的T-SQL模式匹配,sql-server,tsql,dataexplorer,Sql Server,Tsql,Dataexplorer,这是我在使用时反复遇到的一个问题,它基于T-SQL: 如何搜索字符串,除非它作为其他字符串的子字符串出现 例如,如何选择表MyTable中的所有记录,其中列mycl包含字符串foo,但忽略作为字符串foobar一部分的任何foo 快速而肮脏的尝试可能是: 选择* 从MyTable 其中MyCol像“%foo%” MyCol不喜欢“%foobar%” 但显然,这将无法匹配,例如,mycl=“并非所有的foo都是foobars”,我确实希望匹配 我提出的一个解决方案是用一些伪标记(不是foo的子字

这是我在使用时反复遇到的一个问题,它基于T-SQL:

如何搜索字符串,除非它作为其他字符串的子字符串出现

例如,如何选择表
MyTable
中的所有记录,其中列
mycl
包含字符串
foo
,但忽略作为字符串
foobar
一部分的任何
foo

快速而肮脏的尝试可能是:

选择*
从MyTable
其中MyCol像“%foo%”
MyCol不喜欢“%foobar%”
但显然,这将无法匹配,例如,
mycl=“并非所有的foo都是foobars”
,我确实希望匹配

我提出的一个解决方案是用一些伪标记(不是
foo
的子字符串)替换所有出现的
foobar
,然后检查是否有剩余的
foo
,如下所示:

选择*
从MyTable
其中替换(mycl,'foobar,'X'),如“%foo%”
这是可行的,但我怀疑它不是很有效,因为它必须在表中的每个记录上运行
REPLACE()
。(对于SEDE来说,这通常是
Posts
表,目前约有3000万行。)有更好的方法吗


(FWIW,引发这个问题的原因是搜索带有图像URL的帖子,这些帖子使用
http://
scheme前缀,但不指向主机
i.stack.imgur.com

三级过滤器应该可以工作:

  • 收集与“%foo%”匹配的所有行

  • 将“foobar”的所有实例替换为不存在的字符串(例如“”)

  • 再次检查是否匹配“%foo%”

  • 这里只对可能匹配的行执行替换,而不是对所有行执行替换。如果您只希望匹配的比例很小,那么这应该会更有效率

    SQL将如下所示:

    ;with data as (
        select * 
        from MyTable 
        where MyCol like '%foo%'      
    )
    select *
    from data
    where replace(MyCol, 'foobar', 'X') like '%foo%'
    

    注意,子查询是必需的,因为SQL中没有表达式捷径;该引擎可以根据需要对布尔术语进行重新排序,以便在单个查询级别内进行高效处理。

    假设您只对查找
    foo
    的实例感兴趣,这些实例周围有空格

     SELECT * 
     FROM MyTable 
     WHERE MyCol LIKE 'foo %' OR MyCol LIKE '% foo %' OR MyCol LIKE '% foo'
    

    这将比您当前的查询更快:

    SELECT * 
    FROM MyTable 
    WHERE 
      MyCol like '%foo%' AND
      REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%'
    
    替换是在应用MyCol后计算的,因此这比以下速度更快:

    REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%'
    

    到目前为止给出的两种方法都不能保证像广告中所宣传的那样工作,只能对行的子集执行
    REPLACE

    SQL Server和

    唯一保证()工作的是
    CASE
    语句。下面我使用了
    IIF
    的语法变体,扩展到
    CASE

    SELECT *
    FROM   MyTable
    WHERE  1 = IIF(MyCol LIKE '%foo%', 
                   IIF(REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%', 1, 0), 
                   0);
    

    唉,这将不匹配,例如,
    'a fooing foore foos the foos'
    ,我确实希望匹配。让我更新我在问题中的例子。那么你想匹配fooing、Foore和foos,但不匹配foobar?是的。引发这个问题的真正用例实际上是查找带有图像URL的帖子,这些图片URL使用
    http://
    scheme前缀,但不指向主机
    i.stack.imgur.com
    。在相同的选择中执行所有这些操作将与fast@t-clausen.dk:SQL没有布尔表达式短路。确保仅对已经通过第一个测试的行执行替换和测试的唯一方法是嵌套查询。一个人不能根据任何特定的执行计划来判断。@PieterGeerkens-这也不能保证任何事情。@MartinSmith:谢谢。不管这意味着什么,至少这是一个计划最终修复的bug。你是在玩托管版本,还是下载数据在本地系统上玩?如果您正在本地下载,或者如果您不知道这是一个选项,那么您可以通过SQLCLR添加正则表达式功能。例如,你可以下载这个库(我写的,但是RegEx的东西是免费的),将它安装到
    实用程序
    DB中,然后在查询这个或其他东西时使用它:-)。@srutzky:我使用的是托管的DB。我想我可以考虑下载数据,但最好是一个在线解决方案。