Jens Heidrich

Ein regelmäßig auftretendes Problem in großen Datenmengen ist es, mögliche redundante Daten aufzuspüren und zu eliminieren. Man denke hier z.B. an Dubletten im Kundenbestand. Die Schwierigkeit dabei ist, dass diese Dubletten nicht exakt der gleichen Schreibweise folgen müssen. So wäre beispielsweise Thomas Müller, Musterstrasse 12 identisch mit Tomas Mueller, Musterstraße 12.

Um diesem Problem zu begegnen existieren verschiedene Ansätze. Alle beruhen darauf, Zeichenketten mit unterschiedlicher Schreibweise miteinander vergleichbar zu machen. So ist ein Ansatz die Fuzzy-String-Suche oder auch unscharfe Suche, die mit Hilfe verschiedener String-Matching-Algorithmen versucht, eine Zeichenkette in einer längeren Zeichenkette oder einem Text zu finden. Hier spielt die Levenshtein-Distanz eine wichtige Rolle, die die minimale Anzahl von Einfüge-, Lösch- und Ersetz-Operationen angibt, um die erste Zeichenkette in die zweite umzuwandeln (s. http://www.levenshtein.de).

Eine andere Möglichkeit zum Vergleichen von Zeichenketten ist die phonetische Suche. Hierbei wird mit Hilfe der Phonetik versucht eine klangliche Repräsentation der Zeichenketten zu finden und diese zu vergleichen.

Es gibt verschiedene Verfahren, die sich in ihrer jeweiligen Vorgehensweise unterscheiden. Im SQL Server ist der sogenannte Soundex-Algorithmus bereits als Funktion implementiert, der beliebig lange Zeichenketten immer auf einen vierstelligen alphanumerischen Code reduziert. Dieses Verfahren wurde von Russell Anfang des 20. Jahrhunderts in den USA entwickelt und ist deshalb für die englische Sprache optimiert.

Besser auf die deutsche Sprache zugeschnitten ist die Kölner Phonetik. Diese bildet nach bestimmten Regeln jeden Buchstaben eines Wortes auf eine Ziffer zwischen 0 und 8 ab. Die Länge des phonetischen Codes ist dabei im Gegensatz zum Soundex nicht beschränkt (s. http://de.wikipedia.org/wiki/K%C3%B6lner_Phonetik).

Eine mögliche Implementierung der Kölner Phonetik als Funktion für den SQL Server 2012 soll hier vorgestellt werden.

CREATE FUNCTION [dbo].[SOUNDEX_GER] (@strWord NVARCHAR(1000))
RETURNS NVARCHAR(1000) AS
BEGIN

DECLARE
       @Word NVARCHAR(1000),
       @WordLen int,
       @Code NVARCHAR(1000) = “,
       @PhoneticCode NVARCHAR(1000) = “,
       @index int,
       @RegEx NVARCHAR(50),
       @previousCharval nvarchar(1) = ‚|‘,
       @Charval nvarchar(1)

   SET @Word = lower(@strWord);
   IF len(@Word) < 1
      RETURN 0;

    — Umwandlung:
    — v->f, w->f, j->i, y->i, ph->f, ä->a, ö->o, ü->u, ß->ss, é->e, è->e, à->a, ç->c

  SET @Word = REPLACE(
                                  REPLACE(
                                        REPLACE(
                                               REPLACE(
                                                      REPLACE(
                                                            REPLACE(
                                                                   REPLACE(
                                                                          REPLACE(
                                                                                 REPLACE(
                                                                                       REPLACE(
                                                                                              REPLACE(
                                                                                                     REPLACE(
                                                                                                            REPLACE(
                                                                                                                  REPLACE(
                                                                                                                         REPLACE(@Word,’v‘,’f‘),
                                                                                                                  ‚w‘,’f‘),
                                                                                                            ‚j‘,’i‘),
                                                                                                     ‚y‘,’i‘),
                                                                                              ‚ä‘,’a‘),
                                                                                       ‚ö‘,’o‘),
                                                                                 ‚ü‘,’u‘),                                                                                                 
                                                                          ‚é‘,’e‘),
                                                                   ‚è‘,’e‘),
                                                            ‚ê‘,’e‘),
                                                      ‚à‘,’a‘),
                                               ‚á‘,’a‘),
                                        ‚ç‘,’c‘),
                                  ‚ph‘, ‚f‘),
                              ‚ß‘, ’ss‘);


      — Zahlen und Sonderzeichen entfernen

       SET @RegEx = ‚%[^a-z]%‘;
       WHILE PatIndex(@RegEx, @Word) > 0
           SET @Word = Stuff(@Word, PatIndex(@RegEx, @Word), 1, “);


     — Bei Strings der Länge 1 wird ein Leerzeichen angehängt, um die Anlautprüfung auf den zweiten Buchstaben zu ermöglichen.

    SET @WordLen = LEN(@Word);
    IF @WordLen = 1
        SET @Word += ‚ ‚; 

    — Sonderfälle am Wortanfang

    IF (substring(@Word,1,1) = ‚c‘)
   BEGIN
  — vor a,h,k,l,o,q,r,u,x
            SET @Code =
                  CASE
                      WHEN substring(@Word,2,1) IN (‚a‘,’h‘,’k‘,’l‘,’o‘,’q‘,’r‘,’u‘,’x‘)
                         THEN ‚4‘
                         ELSE ‚8‘
                   END;
           SET @index = 2
       END
   ELSE
      SET @index = 1;


   — Codierung    

   WHILE @index <= @WordLen
   BEGIN 
        SET @Code =
           CASE
              WHEN substring(@Word,@index,1) in (‚a‘,’e‘,’i‘,’o‘,’u‘)
                  THEN @Code + ‚0‘
              WHEN substring(@Word,@index,1) = ‚b‘
                  THEN @Code + ‚1‘
              WHEN substring(@Word,@index,1) = ‚p‘
                  THEN IIF (@index < @WordLen, IIF(substring(@Word,@index+1,1) = ‚h‘, @Code+’3′, @Code+’1′), @Code+’1′)
              WHEN substring(@Word,@index,1) in (‚d‘,’t‘)
                  THEN IIF (@index < @WordLen, IIF(substring(@Word,@index+1,1) in (‚c‘,’s‘,’z‘), @Code+’8′, @Code+’2′), @Code+’2′)
              WHEN substring(@Word,@index,1) = ‚f‘
                  THEN @Code + ‚3‘
              WHEN substring(@Word,@index,1) in (‚g‘,’k‘,’q‘)
                  THEN @Code + ‚4‘
              WHEN substring(@Word,@index,1) = ‚c‘
                  THEN IIF (@index < @WordLen, IIF(substring(@Word,@index+1,1) in (‚a‘,’h‘,’k‘,’o‘,’q‘,’u‘,’x‘), IIF(substring(@Word,@index-1,1) = ’s‘ or substring(@Word,@index-1,1) = ‚z‘, @Code+’8′, @Code+’4′), @Code+’8′), @Code+’8′)
              WHEN substring(@Word,@index,1) = ‚x‘
                  THEN IIF (@index > 1, IIF(substring(@Word,@index-1,1) in (‚c‘,’k‘,’x‘), @Code+’8′, @Code+’48‘), @Code+’48‘)
              WHEN substring(@Word,@index,1) = ‚l‘
                  THEN @Code + ‚5‘
              WHEN substring(@Word,@index,1) = ‚m‘ or substring(@Word,@index,1) = ’n‘
                  THEN @Code + ‚6‘
              WHEN substring(@Word,@index,1) = ‚r‘
                  THEN @Code + ‚7‘
              WHEN substring(@Word,@index,1) = ’s‘ or substring(@Word,@index,1) = ‚z‘
                  THEN @Code + ‚8‘
              ELSE @Code
         END;
         SET @index += 1;
     END


   — die mehrfachen Codes entfernen und erst dann die „0“ eliminieren
   — Am Wortanfang bleiben „0“-Codes erhalten

   SET @index = 0;
   WHILE @index < LEN(@code) 
   BEGIN 
      SET @charval = SUBSTRING(@code, @index+1, 1);
      IF @charval <> @previousCharval 
      BEGIN 
         IF @charval <> ‚0‘ OR @index = 0 
         BEGIN  
             SET @PhoneticCode += @charval;
         END   
     END 
     SET @previousCharval = @charval;
     SET @index += 1;
   END  
 RETURN @PhoneticCode;

 END;

Ein möglicher Anwendungsfall für diese Funktion ist die Datenqualitätsverbesserung durch oben angesprochene Dublettenbereinigung im Datenbestand. Hier kann beispielsweise ein manuelles Screening auf Dubletten durch die Fachabteilung bzw. einen Data Steward im Rahmen eines Master Data Management erfolgen.