【问题标题】:TSQL String matching questionTSQL 字符串匹配问题
【发布时间】:2011-06-15 09:18:56
【问题描述】:

我正在尝试使用 TSQL 匹配 2 个字符串。

第一个字符串:   ABCD DFHG KLJKL

第二个字符串:ABCD DFHG KLJKL - 4536764

匹配规则:如果第二个字符串以第一个字符串开头,后跟“-”(即空格、破折号、空格)和一组数字(仅此而已),则认为它是匹配的。

有什么想法吗?

【问题讨论】:

  • 如果第一个字符串是任何地方的子字符串?如果有多余的字符怎么办? ABC 会匹配 -123ABC1545555645 它似乎遵循规定的规则。
  • SQL Server 2008。第一个字符串应该是从第二个子字符串开始的子字符串,而不是任何地方。所以它是一个匹配当且仅当第二个字符串从开始就具有第一个字符串,并且以“-”和一些数字结尾。
  • 而且- 必须完全跟在第一个字符串之后,中间没有其他字符吗? ABC 会匹配 ABC£$-123 吗?
  • - 应该跟在第一个字符串后面,前后只有一个空格。所以 ABC 将匹配 ABC - 12345

标签: sql string tsql sql-server-2008 pattern-matching


【解决方案1】:

此查询满足所有要求。

select *
from #strings
where
  -- s2 contains s1 as the prefix.
  -- The addition of '.' is because sql considers ('abc' = 'abc ')
  LEFT(s2,Len(s1))+'.' = s1+'.'

  -- next 4 chars are space-dash-space-digit
  AND SUBSTRING(s2, Len(s1)+1, Len(s2)) LIKE ' - %[0-9]%'

  -- no non-digit letters after that
  AND NOT STUFF(s2, 1, len(s1)+4, '') LIKE '%[^0-9]%' 

  AND s1 > '' -- reject empty string1, added just in case

这是一个测试表,显示所有测试用例

create table #strings (s1 varchar(100), s2 varchar(100))
insert into #strings values
    ('ABCD DFHG KLJKL', 'ABCD DFHG KLJKL - abc'), -- no, not number
    ('ABCD DFHG KLJKL', 'ABCD DFHG KLJKL - 123'), -- yes
    ('ABCD ', 'ABCD - 123'), -- no, 2nd string is first + '-' without space
    ('ABCD DFHG KLJKL - 123', 'ABCD DFHG KLJKL'), -- no, reversed
    ('KLJKL', 'KLJKL - 1.234'), -- ?? no, 2nd string is not digits only
    ('KL%', 'KLJKL - 1.234'), -- ?? no, 2nd string is not digits only
    ('', ' - 5234'), -- ?? no, blank string is not a match
    (null, ' - 1234'), -- ?? no, null is not equal to blank, which is not a match anyway
    ('ABCD DFHG KLJKL', null) -- no, of course not

【讨论】:

  • 我同意更紧密地匹配要求,但我认为有些事情可以简化。
  • 实际上,就像@Martin 在对我的回答的评论中所说的那样,您在这里假设 FirstString 不包含任何具有特殊意义的字符,例如 %。如果 FirstString 是 ABC% 而第二个字符串是 ABCQWE - 123 这将返回一个匹配项。似乎您的第一个答案可能会更好,具体取决于字符串是否可以包含这些字符。
【解决方案2】:

我有两个答案。

  1. 假设您的 FirstString 值不包含任何字符 %_[,这将返回您所要求的内容。它不仅保证第二个字符串以第一个字符串开头,后跟空格-破折号和一个数字,还确保从该点开始只有数字。

    如果您的表非常宽,那么包含 FirstString 和 SecondString 以及您想要选择的任何其他列(或它们在聚集索引中)的非聚集索引将使该索引完全覆盖查询并且可以大大提高性能。

    SELECT * 
       FROM Strings
       WHERE
          SecondString LIKE FirstString + ' - [0-9]%'
          AND SecondString NOT LIKE FirstString + ' - %[^0-9]%';
    

    我还提出,如果 FirstString 为空白且 SecondString 立即以 ' - ' 开头,那么根据规范它是正确的。

  2. 如果您的 FirstString 值确实包含上述​​任何字符,那么这是一种处理方法:

    SELECT * 
       FROM Strings
       WHERE
          Left(SecondString, Len(FirstString) + 3) = FirstString + ' - '
          AND Len(SecondString) > Len(FirstString) + 3
          AND Substring(SecondString, Len(FirstString) + 4, 2147483647) NOT LIKE '%[^0-9]%';
    

    这里有点奇怪,所以我也会尝试这个版本,看看它是否表现更好:

    WITH S AS (
       SELECT
          *,
          Replace(Replace(Replace(Replace(
             FirstString,
             '\', '\\'),
             '%', '\%'),
             '_', '\_'),
             '[', '\[' --' just a comment to fix wonky code colorization
          ) FirstStringEscaped
       FROM Strings
    )
    SELECT *
    FROM S
    WHERE
       SecondString LIKE FirstStringEscaped + ' - [0-9]%' ESCAPE '\' --'
       AND SecondString NOT LIKE FirstStringEscaped + ' - %[^0-9]%' ESCAPE '\'; --'
    

请注意,如果您想正确处理 FirstString 末尾的空格,可能需要进行一些调整(使用 Len 的第二个查询不能正确处理这种情况)。

【讨论】:

  • 我认为您在这里假设FirstString 不包含在% 等模式中具有特殊意义的任何字符。如果 FirstString 是 ABC% 而第二个字符串是 ABCQWE - 123 这将返回一个匹配项。
【解决方案3】:
select * 
from theTable 
where SecondString like FirstString + ' - %[0-9]'
and SecondString not like FirstString + ' - %[^0-9]%'

这将选择包含您的字符串的任何内容,后跟 1 个空格,后跟一个破折号,再后跟 1 个空格,然后是任何一组数字,除了数字之外什么都没有。

已编辑:在破折号之后过滤掉任何杂乱无章的结果,而不仅仅是字母。

【讨论】:

  • 到目前为止,这最符合标准,考虑到我们对字符串末尾的“数字”一无所知。
  • 除非它不...匹配最后至少有一个数字,以及大量其他杂物,例如当 FirstString = abc 和 SecondString = abc - def alj2139087@[23 -=#@ ": ljskla 3wh5
  • 有趣的是,一旦 cmets 出现,所有答案都开始看起来几乎相同。 :) 并不是说​​你的答案很糟糕。
  • 啊!在我发布最新更新之前,我什至没有看到cyberwiki、你的和我的几乎相同。我从之前的 SO 帖子中得到了最后一行:stackoverflow.com/questions/2032742/…
  • 我喜欢你对最后一个条件的解决方案......它完全删除了任何功能并且是最好的。但是第一个条件困扰着我,将数字放在最后而不是在破折号之后。我知道在这种情况下这无关紧要,但是在 FirstString 来自另一个表的另一个查询中,您的条件在 SecondString 上不会是 sargable。
【解决方案4】:
select * 
from theTable 
where (FirstString = SecondString) 
or (FirstString = SUBSTRING(SecondString, 0, CHARINDEX('-', SecondString))

【讨论】:

  • 如果他的数据总是包含在FirstString之后的空格,请不要忘记空格
猜你喜欢
  • 2011-11-25
  • 1970-01-01
  • 2011-05-01
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
相关资源
最近更新 更多