2015-06-21 140 views
2

我正在尋找匹配來自兩個不同表的字符串的連接表達式,這兩個表都包含4個連續字符的相同子字符串。匹配任意4個連續字符的子字符串

例如,下面應符合:

String1 String2 
-------- ----------- 
xxjohnyy abcjohnabc  [common substring: "john"] 
xxjohnyy johnny   [common substring: "john"] 
birdsings ravenbird  [common substring: "bird"] 
singbird a singer  [common substring: "sing"] 
+1

不確切地確定你在這裏想要什麼。你只是比較同一行的值,意思是t1.row1和t2.row2?或者,您是否正在查看t1中的每一行並在t2中查找所有匹配的內容?另外,當你找到一場比賽時你想做什麼?加入表格並添加一列指示什麼4char字符串匹配?另外,如果有2個4字符匹配(即duoew39uoie和uoewiyuoie)會怎樣? – DiscipleMichael

+1

兩張桌子有多大?這將涉及具有非平凡聯接條件的交叉聯接。 –

+0

@DiscipleMichael我想要「查看t1中的每一行並在t2中查找所有匹配」。背景:客戶端維護了兩個凌亂的Excel表格,每個表格有5000條記錄,這些記錄將被清理並移入數據庫。兩個表都包含一個「項目描述」,這是匹配所需要的,但是隻能使用一個帶描述的子字符串(例如姓氏)。此SQL僅在清理和導入過程中使用。基本上,我會爲了完成95%的工作而加入,其餘部分將進行手動審查。 –

回答

1

這個問題很相似,找到Longest Common Substring問題。你找到最長的公共子串,然後你選擇共同字符串爲4的那些。你一定會發現this linkthis link對你很有幫助。

+0

謝謝,這看起來像是進入正確的方向。我會盡量在明天提供更多反饋。 –

1

這是一個很好的練習。這是我使用Tally Table的嘗試。

SQL Fiddle

;WITH E1(N) AS(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
), 
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), 
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), 
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), 
Tally(N) AS(
    SELECT TOP (
     SELECT 
      CASE 
       WHEN MAX(LEN(String1)) > MAX(LEN(String2)) THEN MAX(LEN(String1)) 
       ELSE MAX(LEN(String2)) 
      END 
     FROM TestTable 
    ) 
     ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) 
    FROM E8 
), 
CteTable AS(-- Added an ID to uniquely identify each row 
    SELECT *, Id = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM TestTable 
), 
CteSubStr1 AS(
    SELECT 
     ct.*, 
     substr = SUBSTRING(ct.String1, t.N, 4) 
    FROM CteTable ct 
    CROSS APPLY(
     SELECT N FROM Tally 
     WHERE N <= LEN(ct.String1) - 3 
    )t 
), 
CteSubStr2 AS(
    SELECT 
     ct.*, 
     substr = SUBSTRING(ct.String2, t.N, 4) 
    FROM CteTable ct 
    CROSS APPLY(
     SELECT N FROM Tally 
     WHERE N <= LEN(ct.String2) - 3 
    )t 
), 
CteCommon AS(
    SELECT * FROM CteSubStr1 c1 
    WHERE EXISTS(
     SELECT 1 FROM CteSubStr2 
     WHERE 
      Id = c1.Id 
      AND substr = c1.substr 
    ) 
) 
SELECT 
    String1, String2, substr 
FROM (
    SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY Id ORDER BY LEN(substr) DESC) 
    FROM CteCommon 
)t 
WHERE RN = 1 

結果

| String1 | String2 | substr | 
|-----------|------------|--------| 
| xxjohnyy | abcjohnabc | john | 
| xxjohnyy |  johnny | john | 
| birdsings | ravenbird | bird | 
| singbird | a singer | sing | 

這部分尋找最長公共子。

SELECT 
    String1, String2, substr 
FROM (
    SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY Id ORDER BY LEN(substr) DESC) 
    FROM CteCommon 
)t 
WHERE RN = 1 

要獲得所有常見字符串,而不是使用:

SELECT * FROM CteCommon 
+0

嘿,非常感謝,看起來很有趣!不知道有什麼像'用x(n)'...想想我需要研究這一段時間... –

+0

你是指'E1(n)'..如果是的話,簡稱爲「公共表格表達式」或「CTE」。 –

+0

我知道CTE並將它們用於遞歸查詢,但我不知道你可以使用括號'(n)' –

1
;with pos as(select 1 as p 
      union all 
      select p + 1 from pos where p < 100), 
     uni as(select *, row_number() over(order by (select null)) id from t) 
select t1.s1, t1.s2, ca.s 
from uni t1 
cross apply(select substring(t2.s2, p, 4) s 
      from uni t2 
      cross join pos 
      where t1.id = t2.id and 
        len(substring(t2.s2, p, 4)) = 4 and 
        t1.s1 like '%' + substring(t2.s2, p, 4) + '%')ca 

Fiddlee http://sqlfiddle.com/#!3/bd4dd/16

只要改變100你列的實際長度......

+0

謝謝!這是短而有希望的。那麼,今天我將討論所有這些答案。 –

+0

注意:我建議不要爲此使用遞歸cte或'rCTE'。使用Tally表進行計數要快得多。請參閱此[**文章**](http://www.sqlservercentral.com/articles/T-SQL/74118/)以獲取更多信息。 –

+0

@wewesthemenace,在這種特殊情況下,差異會很小。即使您的色譜柱長度爲8000,反覆次數與計數之差也是300毫升。它不像你每行鬆散300毫秒,你每聲明300毫秒。 –

相關問題