2009-03-11 8 views
2

Ich versuche, eine Abfrage zu finden, um alle Benutzer in einer USERS-Tabelle zu finden, die ähnlich sind. Es ist so, als würde man alle nicht eindeutigen Zeilen finden, aber eine LIKE-Anweisung und keine Gleichheitsanweisung verwenden. Unten ist eine Beispielspalte einer USERS-TabelleWählen Sie ähnlich wie Zeilen in der gleichen Tabelle

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

nach Abfrage sollte der Ausgang wie folgt aussehen.

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

Die resultierende Abfrage enthält nicht alle Benutzernamen, sondern nur die Benutzernamen, die vor den Nummern am Ende übereinstimmen. IE emily.hunt und dan.snyder würden nicht im Abfrageergebnis sein –

+0

erwartest du, dass es mit Daten wie tim.smuth, tum.smith, tim.smiht funktioniert? –

+0

Nun das Muster ist immer das gleiche hat es ein Vorname.Nachname Format und dann gibt es eine Möglichkeit, dass einige Namen eine Nummer am Ende haben –

Antwort

1

Wenn Ihre Daten genau so, wie Sie beschreiben, könnten Sie schneiden nur die Zahlen aus dem Ende, bevor sie bestellen, aber ich vermute, Ihre Ist-Daten ist komplizierter als das.

Sie könnten sich die Funktionen des SQL-Servers SOUNDEX and DIFFERENCE ansehen. Es ist vielleicht nicht genau, was Sie brauchen, aber es würde wahrscheinlich erhalten Sie

0

schließen konnte nicht einfach tun

select * from USERTABLE order by USERNAME;
0

Es wäre hilfreich, wenn Sie genau definieren, was Sie mit „ähnlichen“ bedeuten. Folgen die Einträge immer einem bestimmten Muster wie "Buchstaben, Punkt, Buchstaben, optionale Zahlen"?

Wenn Sie nach Tippfehlern oder möglichen Rechtschreibfehlern suchen, können Sie Fuzzy-String-Matching-Algorithmen wie Soundex oder Levenshtein bearbeiten.

0

Fancy UDF basierend auf der Levenshtein-Distanz:

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, @[email protected], 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, @[email protected]+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 

(. Cribbed von SQLTeam.com Foren)

Leider funktioniert dies nur, wenn zwei Saiten versehen, und in O (nm) Zeit, wo n und m sind die Länge der zwei Saiten. Sie könnten dies jedoch verbessern, indem Sie die Funktion so ändern, dass sie als "NO MATCH" ausschaltet, wenn @c größer ist als beispielsweise 3.

Aber Sie brauchen immer noch einen Cursor, um durch jeden Benutzernamen zu gehen in der Tabelle und vergleichen Sie es mit jedem anderen Benutzer. Nicht sehr effizient, das ist sicher.

+0

Anstatt einen Cursor, könnten Sie eine kartesische Join (eine der wenigen Instanzen, wo Sie würde das wirklich wollen).Natürlich wäre die Aufführung immer noch furchtbar. –

0

Oder Sie könnten eine Funktion der Berechnung der Levenshtein-Distanz (http://de.wikipedia.org/wiki/Levenshtein-Distanz) und dann kommen die Tabelle mit einen Ausdruck schreiben wie

levenshtein(a.username, b.username) <=2 

Sie können alle Sonderzeichen aus den Namen vorher entfernen möchten, wenn Sie considere solche Zeichen ‚Müll‘

1

ich für einen legitimen Grund gesucht haben, um ein Kreuz zu verwenden beitreten

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 
+0

Super das hat super funktioniert! Vielen Dank! –

+0

Ich bin froh, dass ich helfen konnte. – cmsjr

+0

Hinweis: Dies funktioniert nur, wenn mindestens ein Vorkommen des Namens keine Nummer hat ... Wenn es Dan.Snyder1 und Dan.Snynder2 aber keinen Dan.Snyder gäbe, würde das nicht funktionieren ... – MatBailie

0

SSIS Funktion s darin, um das für Sie zu handhaben. Führen Sie die Tabelle durch SSIS und es wird die Tabellen und die Übereinstimmungen ausgespielt, zusammen mit wie nah sie übereinstimmen.

Verwandte Themen