匹配任意4个连续字符的子字符串
我正在寻找匹配来自两个不同表的字符串的连接表达式,这两个表都包含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"]
这是一个很好的练习。这是我使用Tally Table的尝试。
;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
嘿,非常感谢,看起来很有趣!不知道有什么像'用x(n)'...想想我需要研究这一段时间... –
你是指'E1(n)'..如果是的话,简称为“公共表格表达式”或“CTE”。 –
我知道CTE并将它们用于递归查询,但我不知道你可以使用括号'(n)' –
;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
你列的实际长度......
谢谢!这是短而有希望的。那么,今天我将讨论所有这些答案。 –
注意:我建议不要为此使用递归cte或'rCTE'。使用Tally表进行计数要快得多。请参阅此[**文章**](http://www.sqlservercentral.com/articles/T-SQL/74118/)以获取更多信息。 –
@wewesthemenace,在这种特殊情况下,差异会很小。即使您的色谱柱长度为8000,反复次数与计数之差也是300毫升。它不像你每行松散300毫秒,你每声明300毫秒。 –
不确切地确定你在这里想要什么。你只是比较同一行的值,意思是t1.row1和t2.row2?或者,您是否正在查看t1中的每一行并在t2中查找所有匹配的内容?另外,当你找到一场比赛时你想做什么?加入表格并添加一列指示什么4char字符串匹配?另外,如果有2个4字符匹配(即duoew39uoie和uoewiyuoie)会怎样? – DiscipleMichael
两张桌子有多大?这将涉及具有非平凡联接条件的交叉联接。 –
@DiscipleMichael我想要“查看t1中的每一行并在t2中查找所有匹配”。背景:客户端维护了两个凌乱的Excel表格,每个表格有5000条记录,这些记录将被清理并移入数据库。两个表都包含一个“项目描述”,这是匹配所需要的,但是只能使用一个带描述的子字符串(例如姓氏)。此SQL仅在清理和导入过程中使用。基本上,我会为了完成95%的工作而加入,其余部分将进行手动审查。 –