使用模糊字符串函数查找近似匹配项
实际数据很少完全匹配。 客户名称可能拼写错误、地址缩写不同或产品说明输入不一致。 模糊字符串匹配函数可帮助你查找类似但不完全相同的记录,从而改进数据质量、重复检测和更灵活的搜索功能。
了解字符串相似性概念
模糊匹配算法通过计算两个字符串之间的差异来度量两个字符串的相似程度。 通常使用两种主要方法:
编辑距离(Levenshtein 距离) 计算将一个字符串转换为另一个字符串所需的最小单字符作数(插入、删除、替换)。 较低的值表示更相似的字符串。
相似性分数 将字符串之间的关系表示为百分比或比率,其中较高的值表示更大的相似性。
请考虑下列示例:
- color→"colour":编辑距离=1(插入'u')
- database→"databaes":编辑距离=2(交换'e'和's')
- “Microsoft”→“Microsft”:编辑距离 = 1(删除'o')
注释
与完全匹配相比,模糊匹配的计算成本很高。 请策略性地使用它,通常用于已使用其他条件预先筛选的候选集。
使用 EDIT_DISTANCE 计算编辑距离
该 EDIT_DISTANCE 函数返回两个字符串之间的 Levenshtein 距离,这是将一个字符串转换为另一个字符串所需的最小编辑数。 目标是根据定义的阈值查找类似字符串。
以下示例演示如何使用 EDIT_DISTANCE:
SELECT
EDIT_DISTANCE('color', 'colour') AS ColorVariant, -- Returns 1
EDIT_DISTANCE('database', 'databaes') AS Typo, -- Returns 2
EDIT_DISTANCE('SQL Server', 'SQL Server') AS Exact, -- Returns 0
EDIT_DISTANCE('hello', 'world') AS Different; -- Returns 4
你可以使用 EDIT_DISTANCE 查找可能存在细微变化的重复或匹配的记录。
-- Find customers with similar names to a search term
DECLARE @searchName NVARCHAR(100) = 'Jon Smith';
SELECT
CustomerID,
FirstName,
LastName,
FirstName + ' ' + LastName AS FullName,
EDIT_DISTANCE(@searchName, FirstName + ' ' + LastName) AS EditDistance
FROM SalesLT.Customer
WHERE EDIT_DISTANCE(@searchName, FirstName + ' ' + LastName) <= 3
ORDER BY EDIT_DISTANCE(@searchName, FirstName + ' ' + LastName);
此外,还可以找到潜在的重复产品:
-- Find product pairs with similar names
SELECT
p1.ProductID AS Product1ID,
p1.Name AS Product1Name,
p2.ProductID AS Product2ID,
p2.Name AS Product2Name,
EDIT_DISTANCE(p1.Name, p2.Name) AS EditDistance
FROM SalesLT.Product AS p1
INNER JOIN SalesLT.Product AS p2
ON p1.ProductID < p2.ProductID
WHERE EDIT_DISTANCE(p1.Name, p2.Name) <= 5
ORDER BY EDIT_DISTANCE(p1.Name, p2.Name);
小窍门
最大有意义的编辑距离取决于字符串长度。 对于短字符串(5-10 个字符),编辑距离为 1-2 表示相似性。 对于较长的字符串,可以允许 3-5 的距离。
通过EDIT_DISTANCE_SIMILARITY测量相似性
EDIT_DISTANCE_SIMILARITY 返回介于 0 和 100 之间的规范化相似性分数,其中 100 表示相同的字符串。 此基于百分比的指标比原始编辑距离更容易解释,尤其是在比较不同长度的字符串时:
SELECT
EDIT_DISTANCE_SIMILARITY('color', 'colour') AS ColorSimilarity, -- ~85
EDIT_DISTANCE_SIMILARITY('database', 'databaes') AS TypoSimilarity, -- ~75
EDIT_DISTANCE_SIMILARITY('SQL', 'SQL Server') AS PartialMatch, -- ~30
EDIT_DISTANCE_SIMILARITY('hello', 'hello') AS Exact; -- 100
可以使用相似性分数来查找具有阈值的近似匹配项,如以下示例所示:
-- Find products similar to a search term (at least 70% similar)
DECLARE @searchTerm NVARCHAR(100) = 'Mountain Bike Frame';
SELECT
ProductID,
Name,
EDIT_DISTANCE_SIMILARITY(@searchTerm, Name) AS SimilarityScore
FROM SalesLT.Product
WHERE EDIT_DISTANCE_SIMILARITY(@searchTerm, Name) >= 70
ORDER BY EDIT_DISTANCE_SIMILARITY(@searchTerm, Name) DESC;
使用 JARO_WINKLER_DISTANCE 计算拼音相似性
Jaro-Winkler 算法专为比较名称和短字符串而设计。 它对从开头就匹配的字符串给予更高的分数,这使得在前缀较为重要的人名中效果特别显著。
SELECT
JARO_WINKLER_DISTANCE('MARTHA', 'MARHTA') AS NameTypo, -- ~0.96
JARO_WINKLER_DISTANCE('JONES', 'JOHNSON') AS SimilarNames, -- ~0.83
JARO_WINKLER_DISTANCE('JOHN', 'JON') AS NameVariant, -- ~0.93
JARO_WINKLER_DISTANCE('SMITH', 'SMYTH') AS SpellingVar; -- ~0.96
Jaro-Winkler 分数范围为 0 到 1,其中 1 表示相同的字符串。 高于 0.9 的分数通常表示名称的强匹配。
以下示例查找名称类似于搜索输入的客户:
-- Find customers with names similar to a search
DECLARE @searchFirst NVARCHAR(50) = 'John';
DECLARE @searchLast NVARCHAR(50) = 'Smythe';
SELECT
CustomerID,
FirstName,
LastName,
JARO_WINKLER_DISTANCE(@searchFirst, FirstName) AS FirstNameScore,
JARO_WINKLER_DISTANCE(@searchLast, LastName) AS LastNameScore,
(JARO_WINKLER_DISTANCE(@searchFirst, FirstName) +
JARO_WINKLER_DISTANCE(@searchLast, LastName)) / 2 AS CombinedScore
FROM SalesLT.Customer
WHERE JARO_WINKLER_DISTANCE(@searchFirst, FirstName) > 0.85
AND JARO_WINKLER_DISTANCE(@searchLast, LastName) > 0.85
ORDER BY CombinedScore DESC;
注释
Jaro-Winkler 针对名称等短字符串进行优化。 对于地址或说明等较长字符串, EDIT_DISTANCE_SIMILARITY 通常提供更好的结果。
性能注意事项
模糊匹配函数会检查这两个字符串中的每个字符,使其计算密集型。 精确的字符串比较可以在字符不同的时候立即停止,而索引查找使用高效的 B 树遍历方式。 相比之下,模糊算法必须按字符计算相似性分数。 对于包含 100 万行的表,未优化模糊搜索可能会执行 100 万个相似性计算,每个计算涉及数十个字符的比较。
有效模糊匹配的关键是在应用昂贵的模糊函数之前减少候选集。 使用索引列、LIKE 模式、相关字段的精确匹配或范围筛选器来首先缩小结果范围。 然后,才对较小的候选集应用模糊匹配。
以下示例显示了这种渐进式筛选方法:
-- Not good: Fuzzy match against entire table
SELECT * FROM LargeCustomerTable
WHERE EDIT_DISTANCE_SIMILARITY('John Smith', FullName) > 70;
-- Better: Pre-filter before fuzzy matching
SELECT * FROM LargeCustomerTable
WHERE FullName LIKE 'J%' -- First letter filter
AND EDIT_DISTANCE_SIMILARITY('John Smith', FullName) > 70;
-- Best: Use multiple pre-filters
SELECT * FROM LargeCustomerTable
WHERE FirstName LIKE 'Jo%'
AND LastName LIKE 'Sm%'
AND JARO_WINKLER_DISTANCE('John', FirstName) > 0.85
AND JARO_WINKLER_DISTANCE('Smith', LastName) > 0.85;
重要
模糊字符串匹配函数(如 EDIT_DISTANCE、EDIT_DISTANCE_SIMILARITY 和 JARO_WINKLER_DISTANCE)在 SQL Server 2025 及更高版本、Azure SQL 数据库和 Microsoft Fabric 的 SQL 数据库中可用。 查看平台的文档以获取特定功能可用性。
有关模糊字符串匹配的详细信息,请参阅 字符串函数。