我想在表中查询另一个表上列表中的所有值以查找匹配项,但我知道任何一个表中的某些值可能输入错误。一个表可能有'10Hf7K8'而另一个表可能有'1OHf7K8',但我仍然希望它们匹配。
另一个例子,如果一个表有'STOP',但我知道在myTable中,有些字段可能会说'5T0P'或'ST0P'或'5TOP'。我希望那些结果也是如此。如果我想要'ZEPT'和'2EPT'匹配,'2'和'Z'可能会出现同样的情况。
所以,如果我知道要解释'0'和'O','5'和'S'以及'Z'和'2'之间的不一致,并且知道它们将在同一个地方,但我做不知道它们在单词中的确切位置或单词将包含多少个字母,是否可以忽略这些字母进行查询?
附加信息:这些值是数百个串行密钥,我无法确认两个表之间的版本是否正确。我不应该在我的例子中使用实际的单词,这些值可以是任何顺序的字母和数字的任意组合。没有明显的模式我可以硬编码。
解决方案:Goat CO,Learning和user3216429的答案包含了我需要的解决方案。我能够在保留基础数据的同时找到匹配的值。
答案 0 :(得分:0)
最好使用清理数据,但如果无法更改基础数据,则可以使用嵌套的REPLACE()
语句:
SELECT *
FROM Table1 a
JOIN Table2 b
ON REPLACE(REPLACE(REPLACE(a.field1,'2','Z'),'5','S'),'0','O') = REPLACE(REPLACE(REPLACE(b.field1,'2','Z'),'5','S'),'0','O')
清理数据可以是相同的嵌套替换语句:
ALTER TABLE Table1 ADD cleanfield VARCHAR(25)
UPDATE Table1
SET cleanfield = REPLACE(REPLACE(REPLACE(dirtyfield,'2','Z'),'5','S'),'0','O')
然后你就可以加入干净的领域了。
答案 1 :(得分:0)
您可以而且应该做的是清理您的数据,将所有这些2,0,5
替换为Z,O and S
。
但是如果你想尝试其他解决方案,那么你可以尝试这样的事情
select case when
REPLACE(REPLACE(REPLACE('stop','0','o'),'5','s'),'2','Z') = REPLACE(REPLACE(REPLACE('5t0p','0','o'),'5','s'),'2','Z') then 1 else 2 end
答案 2 :(得分:0)
如前所述,如果你有时间,请清理数据。
如果没有,SQL SERVER提供两个可能有用的字符串函数。
这个例子来自我的博客文章。 http://craftydba.com/?p=5211
SOUNDEX()函数将单词转换为4个字符的值。 DIFFERENCE()函数告诉你两个单词的接近程度。
你的例子似乎只有一个字。您可能希望使用计算列并对其进行索引,以使where子句具有SARGABLE。
如果您使用段落,请使用标准分割功能将文本段落转换为单词。使用这些功能搜索数据。但是,这将导致非SARGABLE表达。
-- Example returns 4, words are very close
select
soundex('Dog') as word_val1,
soundex('Dogs') as word_val2,
difference('Dog', 'Dogs') as how_close
-- Example returns 0, words are very different
select
soundex('Rattle-Snake') as word_val1,
soundex('Mongoose') as word_val2,
difference('Rattle-Snake', 'Mongoose') as how_close
output:
word_val1 word_val2 how_close
--------- --------- -----------
D200 D200 4
word_val1 word_val2 how_close
--------- --------- -----------
R340 M522 0
最后但同样重要的是,您还可以查看全文索引的速度。这需要一些额外的开销(FTI结构和更新FTI的过程)。
答案 3 :(得分:0)
select REPLACE(REPLACE( REPLACE([column_name],'O','0'),'Z','2'),'5','S')
from [table_name]
答案 4 :(得分:0)
1)要过滤掉包含所有形式的STOP字(STOP,5TOP,ST0P,5T0P)的所有行,您可以使用以下基于LIKE的查询:
SELECT *
FROM (
SELECT 1, 'CocoJambo' UNION ALL
SELECT 2, '5T0P' UNION ALL
SELECT 3, ' 5TOP ' UNION ALL
SELECT 4, ' ST0P ' UNION ALL
SELECT 5, ' STOP ' UNION ALL
SELECT 6, 'ZTOP'
) x (ID, ColA)
WHERE x.ColA LIKE '%[5S]T[0O]P%';
输出:
ID ColA
----------- ---------
2 5T0P
3 5TOP
4 ST0P
5 STOP
2)关于你的问题:
对于每张桌子
首先,我会尝试为每个单词构建一个包含所有模式的表格,对于每个模式,我会存储正确/准确的单词,
然后我会尝试用适当的单词替换每一个模式
在这两个表的预先之后,我将尝试匹配这两个表。
此脚本仅替换第一个出现的模式
SELECT x.*, oa.*,
CASE
WHEN oa.PatIx > 0 THEN STUFF( x.ColA , oa.PatIx , LEN(oa.Word), oa.Word )
ELSE x.ColA
END AS NewColA
FROM (
SELECT 1, 'CocoJambo' UNION ALL
SELECT 2, '5T0P' UNION ALL
SELECT 3, ' 5TOP ' UNION ALL
SELECT 4, ' ST0P ' UNION ALL
SELECT 5, ' STOP jambo jumbo 5TOP bOb ' UNION ALL
SELECT 6, 'ZTOP'
) x (ID, ColA)
OUTER APPLY (
SELECT *
FROM (
SELECT w.WordPattern, w.Word, PATINDEX( w.WordPattern , x.ColA ) AS PatIx
FROM @Words w
) y
WHERE y.PatIx > 0
) oa
输出:
ID ColA WordPattern Word PatIx NewColA
-- ----------------------------- ------------ ---- ----- ----------------------------
1 CocoJambo %b[o0]% bob 8 CocoJambob
2 5T0P %[5S]T[0O]P% STOP 1 STOP
3 5TOP %[5S]T[0O]P% STOP 2 STOP
4 ST0P %[5S]T[0O]P% STOP 3 STOP
5 STOP jambo jumbo 5TOP bOb %[5S]T[0O]P% STOP 4 STOP jambo jumbo 5TOP bOb
5 STOP jambo jumbo 5TOP bOb %b[o0]% bob 12 STOP jambobjumbo 5TOP bOb
6 ZTOP NULL NULL NULL ZTOP
注意:这个解决方案只是一个概念验证。它需要发展。
或者您可以尝试使用正确格式替换所有错误单词的解决方案:
CREATE TABLE dbo.Words ( Id INT IDENTITY PRIMARY KEY, WordSource NVARCHAR(50) NOT NULL, Word NVARCHAR(50) NOT NULL );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'5T0P' , N'STOP' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'5TOP' , N'STOP' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'ST0P' , N'STOP' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'b0b' , N'bob' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'bOb' , N'bob' );
GO
CREATE FUNCTION dbo.ReplaceWords (@ColA NVARCHAR(4000), @Num INT)
RETURNS TABLE
AS
RETURN
WITH CteRecursive
AS
(
SELECT w.Id, w.WordSource, w.Word, REPLACE(@ColA, w.WordSource, w.Word) AS NewColA
FROM dbo.Words w
WHERE w.Id = 1
UNION ALL
SELECT w.Id, w.WordSource, w.Word, REPLACE(prev.NewColA, w.WordSource, w.Word) AS NewColA
FROM CteRecursive prev INNER JOIN dbo.Words w ON prev.Id + 1 = w.Id
WHERE prev.Id + 1 <= @Num
)
SELECT r.NewColA
FROM CteRecursive r
WHERE r.Id = @Num
GO
-- Testing
SELECT * FROM dbo.ReplaceWords(N' ST0P jambo 5TOP bOb jumbo ', 5) f;
输出
NewColA
----------------------------
STOP jambo STOP bob jumbo
您可以使用以前的函数替换每个表中的所有错误单词,然后您可以比较两个表:
DECLARE @Num INT;
SET @Num = (SELECT COUNT(*) FROM dbo.Words);
SELECT x.*, rpl.NewColA
FROM (
SELECT 1, N'CocoJambo' UNION ALL
SELECT 2, N'5T0P' UNION ALL
SELECT 3, N' 5TOP ' UNION ALL
SELECT 4, N' ST0P ' UNION ALL
SELECT 5, N' STOP jambo jumbo 5TOP bOb ' UNION ALL
SELECT 6, N'ZTOP' UNION ALL
SELECT 7, N'' UNION ALL
SELECT 8, NULL
) x (ID, ColA)
OUTER APPLY dbo.ReplaceWords(x.ColA, @Num) rpl
输出:
ID ColA NewColA
-- ----------------------------- ----------------------------
1 CocoJambo CocoJambo
2 5T0P STOP
3 5TOP STOP
4 ST0P STOP
5 STOP jambo jumbo 5TOP bOb STOP jambo jumbo STOP bob
6 ZTOP ZTOP
7
8 NULL NULL