在同一个表中选择类似的行

时间:2009-03-11 14:38:16

标签: sql sql-server sql-server-2005

我正在尝试编写一个查询来查找USERS表中类似的所有USERS。它就像查找所有非不同的行但使用LIKE语句而不是equals语句。下面是USERS表的示例列

 USERNAME 
------------
tim.smith
doug.funny
tim.smith1
dan.snyder
tim.smith20
doug.funny2
emily.hunt

查询后输出应如下所示。

tim.smith
tim.smith1
tim.smith20
doug.funny
doug.funny2

7 个答案:

答案 0 :(得分:1)

如果您的数据与您描述的完全一致,您可以在订购之前修剪数字,但我怀疑您的实际数据比这更复杂。

您可能希望查看sql server SOUNDEX and DIFFERENCE函数。它可能不是你所需要的,但它可能会让你接近

答案 1 :(得分:1)

我一直在寻找使用交叉连接的正当理由

Select Distinct u1.UserID 
from username  u1 Cross join username u2
where u1.UserID <> u2.UserID
and 
(PatIndex('%' + u1.UserID  + '%', u2.UserID)  <> 0
 OR
PatIndex('%' + u2.UserID  + '%', u1.UserID)  <> 0)
order by u1.UserID

doug.funny
doug.funny2
tim.smith
tim.smith1
tim.smith20

答案 2 :(得分:0)

你能不能做到

select * from USERTABLE order by USERNAME;

答案 3 :(得分:0)

如果您准确定义“相似”的含义,将会很有帮助。条目是否始终遵循某种模式,例如“字母,句点,字母,可选数字”?

如果您正在寻找拼写错误或可能的拼写错误,您可以尝试模糊字符串匹配算法,例如soundex或Levenshtein编辑距离。

答案 4 :(得分:0)

基于Levenshtein距离的花式UDF:

CREATE FUNCTION edit_distance(@s1 nvarchar(3999), @s2 nvarchar(3999))
RETURNS int
AS
BEGIN
  DECLARE @s1_len int, @s2_len int, @i int, @j int, @s1_char nchar, @c int, @c_temp int,
    @cv0 varbinary(8000), @cv1 varbinary(8000)
  SELECT @s1_len = LEN(@s1), @s2_len = LEN(@s2), @cv1 = 0x0000, @j = 1, @i = 1, @c = 0
  WHILE @j <= @s2_len
    SELECT @cv1 = @cv1 + CAST(@j AS binary(2)), @j = @j + 1
  WHILE @i <= @s1_len
  BEGIN
    SELECT @s1_char = SUBSTRING(@s1, @i, 1), @c = @i, @cv0 = CAST(@i AS binary(2)), @j = 1
    WHILE @j <= @s2_len
    BEGIN
      SET @c = @c + 1
      SET @c_temp = CAST(SUBSTRING(@cv1, @j+@j-1, 2) AS int) +
        CASE WHEN @s1_char = SUBSTRING(@s2, @j, 1) THEN 0 ELSE 1 END
      IF @c > @c_temp SET @c = @c_temp
      SET @c_temp = CAST(SUBSTRING(@cv1, @j+@j+1, 2) AS int)+1
      IF @c > @c_temp SET @c = @c_temp
      SELECT @cv0 = @cv0 + CAST(@c AS binary(2)), @j = @j + 1
    END
    SELECT @cv1 = @cv0, @i = @i + 1
  END
  RETURN @c
END

(来自SQLTeam.com论坛。)

不幸的是,这仅在提供两个字符串时有效,并且在O(nm)时间内,其中n和m是两个字符串的长度。但是,你可以通过修改函数来改进,当@c大于3时,修改为“无匹配”。

但是你仍然需要一个光标来遍历表中的每个用户名并将其与其他每个用户进行比较。效率不高,这是肯定的。

答案 5 :(得分:0)

或者您可以编写一个计算levenshtein距离(http://de.wikipedia.org/wiki/Levenshtein-Distanz)的函数,然后使用类似

的表达式加入表格
levenshtein(a.username, b.username) <=2

你可能想要删除之前名字中的任何特殊字符,如果你认为这些字符'垃圾'

答案 6 :(得分:0)

SSIS具有为您处理此问题的功能。通过SSIS运行表格,它将显示表格和匹配项以及它们匹配的距离。