【问题标题】:SQL Server 2008 R2: Matching stringsSQL Server 2008 R2:匹配字符串
【发布时间】:2017-10-10 12:56:32
【问题描述】:

我有下表:

表:

CREATE TABLE str_matching
(
    colstr varchar(200)
);

插入数据:

INSERT INTO str_matching VALUES('5sXYZA1010B')
INSERT INTO str_matching VALUES('A1010B')
INSERT INTO str_matching VALUES('AMZ103B15K')
INSERT INTO str_matching VALUES('B15K')
INSERT INTO str_matching VALUES('XC101')
INSERT INTO str_matching VALUES('C101')
INSERT INTO str_matching VALUES('502KMD1FZ10009L')
INSERT INTO str_matching VALUES('FZ10009L')
INSERT INTO str_matching VALUES('A9L')
INSERT INTO str_matching VALUES('XZ049L')
INSERT INTO str_matching VALUES('LM101')

预期输出:我只想显示那些具有重复条目的记录,如果一个字符串匹配任何字符串的最后一部分,那么我认为是重复的。

例如:我有两个字符串

  1. 5sXYZA1010B
  2. A1010B

第二个字符串匹配在第一个字符串的末尾,所以想显示这样的记录。

注意:字符串的长度不固定,可以任意匹配。

预期结果:

colstr              
--------------------
5sXYZA1010B         
A1010B              
AMZ103B15K          
B15K                
XC101               
C101                
502KMD1FZ10009L     
FZ10009L        

【问题讨论】:

标签: sql sql-server sql-server-2008-r2


【解决方案1】:

应该这样做 (demo)

SELECT DISTINCT CA.colstr
FROM   str_matching s1
       JOIN str_matching s2
         ON s1.colstr <> s2.colstr
            AND s2.colstr LIKE '%' + s1.colstr
       CROSS APPLY (VALUES(s1.colstr),
                          (s2.colstr)) CA(colstr) 

但是,如果str_matching 有很多行,性能会很差。在字符串的反面添加索引可以大大改善事情 - 如下例所示。

CREATE TABLE str_matching
(
    colstr varchar(200),
    colstr_rev AS REVERSE(colstr)
);

CREATE INDEX ix_colstr_rev on str_matching(colstr_rev)

SELECT colstr = REVERSE(CA.colstr_rev)
FROM   str_matching s1
       JOIN str_matching s2
         ON s1.colstr_rev <> s2.colstr_rev
            AND s2.colstr_rev LIKE  s1.colstr_rev + '%' 
       CROSS APPLY (VALUES(s1.colstr_rev),
                          (s2.colstr_rev)) CA(colstr_rev) 
GROUP BY CA.colstr_rev

【讨论】:

  • 您是否需要distinctunion,因为您在cross apply() 中使用union 而不是union all
  • @SqlZim 我当然不需要内部的UNION - s1.colstr &lt;&gt; s2.colstr 意味着它们永远不会相同。会改变
  • @MartinSmith,41k 条记录的执行时间超过 15 分钟。
  • @MAK - 我并不感到惊讶。这将需要对 1,681,000,000 个交叉连接的行进行比较。要优化它,您需要存储字符串的反向副本并索引该列并重写查询以使用该列和尾随通配符。
  • @MAK - 添加了一个例子
【解决方案2】:

你可以使用它。

;WITH CTE AS (
    select *,RN = ROW_NUMBER() OVER (ORDER BY LEN(colstr)) from str_matching 
)
,CTE2 AS (
    SELECT T1.colstr colstr1 ,X.colstr colstr2 FROM CTE T1
        CROSS APPLY (SELECT * FROM CTE T2 WHERE T2.RN > T1.RN AND RIGHT(T2.colstr, LEN(T1.colstr)) = T1.colstr) AS X
)
SELECT colstr1 FROM CTE2 
UNION ALL 
SELECT colstr2 FROM CTE2

结果:

5sXYZA1010B         
A1010B              
AMZ103B15K          
B15K                
XC101               
C101                
502KMD1FZ10009L     
FZ10009L 

【讨论】:

    【解决方案3】:

    它可以在任何时候匹配。

    要匹配任何点,请在每一侧使用带有通配符 (%) 的 like

    对于多个匹配,添加distinct

    select l.colstr
    from str_matching l
      inner join str_matching r
        on l.colstr<>r.colstr
       and (l.colstr like '%' + r.colstr +'%'
         or r.colstr like '%' + l.colstr +'%'
          )
    

    rextester 演示:http://rextester.com/ICIKJ2256

    返回:

    +-----------------+
    |     colstr      |
    +-----------------+
    | A1010B          |
    | 5sXYZA1010B     |
    | B15K            |
    | AMZ103B15K      |
    | C101            |
    | XC101           |
    | FZ10009L        |
    | 502KMD1FZ10009L |
    +-----------------+
    

    鉴于 Martin Smith 的回答,我猜我误解了您在“任意点匹配”背后的意图,因此仅匹配字符串的结尾您不会使用尾随 + '%'

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多