【问题标题】:What is the correct pattern matching string to exclude records containing "x"排除包含“x”的记录的正确模式匹配字符串是什么
【发布时间】:2021-03-17 02:23:34
【问题描述】:
DECLARE @data TABLE
(   sample_text VARCHAR(20))

DECLARE @match TABLE
(   match_text VARCHAR(20),
    return_value INT
)

INSERT INTO @data
VALUES ('sample'),
       ('text'),
       ('fuzzy'),
       ('kittens')

INSERT INTO @match
VALUES ('%e%', 1),
       ('[^t]%', 2),
       ('%[^t]%', 3)

SELECT *
  FROM @data  d 
  JOIN @match m ON d.sample_text LIKE m.match_text

我正在尝试根据字段中的数据是否与正则表达式匹配来返回一个值。

正则表达式应该使我能够匹配正数(例如以 T 开头)和负数(例如不以 T 开头),而无需更改底层 SQL。

简单的情况有效(例如,包含“e”,不以“t”开头),但是当我想返回不包含“t”的行时,我遇到了问题。

我知道我可以通过多种方式使用NOT LIKE,但我正在寻找一个通用的解决方案。

返回值为 3 的唯一行应该是“sample”和“fuzzy”。 “text”和“kittens”不应该匹配,因为它们都包含字符“t”。

在我的脑海中"%[^t]%" 的意思是“不包含字符't'”。在您的回答中,您能否澄清它的真正含义?你能用同样的方式翻译你的建议以帮助我理解吗?

【问题讨论】:

  • 为什么投反对票?
  • LIKE 不是正则表达式,不要自欺欺人。 % 匹配任何字符(如果有),[^ 匹配任何不在括号中的单个字符,t] 指定字符 t 不匹配,% 匹配任何剩余字符(如果有)。所以它会匹配任何包含不是t的字符的东西,即使它确实包含t
  • 谢谢@Charlieface,那么我将如何修复“匹配”字符串,以便如果记录包含t 而不会返回任何其他字符?
  • '%[^t]%' 表示“至少包含一个 't'的字符”。你可以用一个额外的列做一些(可怕的)事情,例如NotLike as Bit,然后将您的逻辑构建为case when d.Sample_Text like m.Match_Text then 1 - m.NotLike else m.NotLike end = 1。或( m.NotLike = 0 and d.Sample_Text like m.Match_Text ) or ( m.NotLike = 1 and d.Sample_Text not like m.Match_Text )。而不是另一列,您可以破坏模式并将其分开,例如如果第一个字符是'¬',则删除它并反转逻辑。
  • 你不能。正则表达式中没有等价于+,所以你不能做[^t]+,你必须使用NOT LIKE。正要建议第二个专栏case

标签: sql-server tsql pattern-matching sql-server-2019


【解决方案1】:

您可以通过反转 LIKE 匹配的含义来排除记录,即:NOT LIKE

作为一般规则,任何带有NOT INNOT LIKE 的查询在规模上都会执行得非常糟糕,但这是一种查找与给定模式不匹配的项目的方法...

DECLARE @data TABLE
(   sample_text VARCHAR(20))

DECLARE @match TABLE
(   match VARCHAR(20),
    not_match VARCHAR(20),
    return_value INT
)

INSERT INTO @data
VALUES ('sample'),
       ('text'),
       ('fuzzy'),
       ('kittens')

INSERT INTO @match
VALUES ('%e%', null, 1),
       (null, 't%', 2),
       (null, '%t%', 3)

SELECT *
FROM @data  d 
JOIN @match m
  ON (m.match is not null and d.sample_text LIKE m.match)
  OR (m.not_match is not null and d.sample_text NOT LIKE m.not_match);

【讨论】:

    【解决方案2】:

    万一它对任何人有用......

    与往常一样,实际问题比我们在此处发布的重现问题的最小步骤稍微复杂一些。

    我的具体场景涉及在 4 个单独的列上进行匹配,因此为每个现有列添加一个新列来表示 NOT LIKE 场景会使已经很麻烦的解决方案变得更加麻烦。

    鉴于模式匹配不会让我到达那里,我决定的解决方案是为LIKE 场景和NOT LIKE 场景设置单独的行,然后将它们组合在一起以获得结果。

    DECLARE @data TABLE
    (   sample_text VARCHAR(20))
    
    DECLARE @match TABLE
    (   rule_type    INT, -- 1 = Include, 0 = Exclude
        match_text   VARCHAR(20),
        return_value INT
    )
    
    INSERT INTO @data
    VALUES ('sample' ),
           ('ample'  ),
           ('dimple' ),
           ('text'   ),
           ('fuzzy'  ),
           ('kittens')
    
    INSERT INTO @match
    VALUES ('1', '%mple%', 1),
           ('0', 'd%'    , 1),
           ('1', '[^t]%' , 2),
           ('0', '%mple%', 2)
    
    SELECT sample_text, return_value
      FROM @data  d 
      JOIN @match m ON d.sample_text LIKE m.match_text
     GROUP BY sample_text, return_value
    HAVING MIN(rule_type) <> 0 -- any number of "include" rules can match but if any "exclude" rule is matched the record is not returned.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-06-10
      • 2014-09-27
      • 2015-04-23
      • 1970-01-01
      • 2016-04-21
      • 1970-01-01
      相关资源
      最近更新 更多