SQL中筛选相似字符串并取较长者(解决Msg 8120错误)
解决SQL的Msg 8120错误 + 实现“相似字符串选较长者”逻辑
嘿,我来帮你捋清楚这个问题!首先那个Msg 8120错误是SQL Server的经典坑——当你用GROUP BY或者聚合逻辑时,SELECT列表里的列要么得放在GROUP BY子句里,要么得用聚合函数(比如MAX()、MIN())或者窗口函数包裹,不然数据库根本不知道该返回哪条数据的这个列值,自然就报错了。
接下来咱们一步步解决你的需求:先搞定错误,再加上相似性判断,最后结合选较长字符串的逻辑。
第一步:理解错误根源
举个例子,如果你之前的代码大概是这样:
SELECT Product, MAX(LEN(Product)) FROM SortData -- 这里如果没把Product放进GROUP BY,就会触发Msg 8120 GROUP BY SomeOtherColumn;
问题就出在Product列不在GROUP BY里,也没被聚合函数处理,数据库不知道要返回哪一行的Product。所以咱们得用窗口函数或者合理分组来解决这个问题。
第二步:选择相似性判断逻辑
SQL里有几种常用的相似性判断方式,你可以根据需求选:
- 发音相似判断:用
SOUNDEX()和DIFFERENCE()函数,适合判断读音相近的字符串(比如"Smith"和"Smyth")。DIFFERENCE()返回0-4,数值越高越相似,一般选3或4作为相似阈值。 - 包含关系判断:用
CHARINDEX()检查一个字符串是否包含另一个,适合部分匹配的场景。 - 精确相似(编辑距离):如果需要更精准的相似性(比如拼写差异在2个字符以内),可以自定义Levenshtein距离函数(这个需要自己写,或者用内置的字符串函数模拟)。
第三步:完整实现代码
场景1:分组筛选每组相似字符串中的最长者
比如你想把发音相似的产品归为一组,然后选每组里最长的那个:
WITH RankedProducts AS ( SELECT Product, LEN(Product) AS ProductLength, -- 用SOUNDEX把发音相似的字符串归为一组 SOUNDEX(Product) AS SoundGroup, -- 按长度倒序排名,每组第一就是最长的 ROW_NUMBER() OVER ( PARTITION BY SOUNDEX(Product) ORDER BY LEN(Product) DESC ) AS RankInGroup FROM SortData ) SELECT Product FROM RankedProducts WHERE RankInGroup = 1;
这个写法用窗口函数ROW_NUMBER()给每组相似的字符串排名,完美避开了Msg 8120的问题,因为所有列要么被窗口函数处理,要么在CTE里是基础列。
场景2:对比两列字符串,相似时选较长者
如果你的表有两个字符串列(比如ProductA和ProductB),要判断它们是否相似,相似就选较长的:
SELECT CASE -- 这里用DIFFERENCE+包含关系做双重相似判断,你可以调整阈值 WHEN DIFFERENCE(ProductA, ProductB) >= 3 OR CHARINDEX(ProductA, ProductB) > 0 OR CHARINDEX(ProductB, ProductA) > 0 THEN CASE WHEN LEN(ProductA) >= LEN(ProductB) THEN ProductA ELSE ProductB END -- 不相似时可以返回NULL,或者根据需求返回其中一个 ELSE NULL END AS SelectedLongSimilarProduct FROM YourTable;
这个写法用CASE嵌套,先判断相似性,再选择较长的字符串,完全不会触发Msg 8120,因为没有用到分组逻辑,所有列都是单行列。
小提示
如果你的相似性需求更复杂,比如需要自定义编辑距离,可以写一个用户自定义函数(UDF)来计算Levenshtein距离,然后在CASE或者窗口函数里调用它就行。
内容的提问来源于stack exchange,提问作者Ollie Beumkes
相关产品推荐
相关产品推荐

