2017-10-10 134 views
1

我有如下表:的SQL Server 2008 R2:字符串匹配

表:

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   
+0

的比较字符串的结尾[最好的方式复制,使用权,像或其他?](https://stackoverflow.com/questions/7394276/best-way-to-compare-the-end-of-a-string-use-right-like-or-other) –

+2

@TabAlleman [这是一个数据资源管理器查询](https://data.stackexchange.com/stackoverflow/query/738866/answers-to-duplicate-questions-by-user),所以你可以找到标记为用户标识符重复的问题的所有答案。您可以从用户ID 1507566开始。 – SqlZim

回答

2

这应该这样做(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 
+0

因为您在'cross apply()'中使用'union'而不是'union all',您是否需要'distinct'和'union'? – SqlZim

+0

@SqlZim当然我不需要内部'UNION' - s1.colstr <> s2.colstr'表示它们永远不会相同。将更改 –

+0

@MartinSmith,执行41k条记录需要超过15分钟的时间。 – MAK

1

它可以匹配在任何点。

要匹配的任何点,使用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 | 
+-----------------+ 

鉴于马丁·史密斯的回答,我猜我误解背后“在任何时候比赛”你的意图,所以只匹配字符串的结尾,你会不会使用后+ '%'

1

你可以用它。

;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