Firebird: Soundex

2 - Berechnung

Die Berechnung des Soundex ist nach den Vorbereitungen dann fast schon trivial. Das Wort wird in der SP "prc_soundex" zerlegt und über einen LEFT JOIN mit der Tabelle "soundex_weights" verknüpft. Das LEFT ist nötig, um auch nicht in der Tabelle vorhandene Zeichen als erstes Zeichen verwenden zu können.

Für diese Berechnung ist die SP "prc_soundex" zuständig. Anhand der ermittelten Gruppe jedes einzelnen Zeichens wird hier der Soundex aufgebaut. Als Besonderheit kann der SP noch die Länge des Soundex übergeben werden, um z.B. längere Soundex zu berechnen.

In der Beispieldatenbank wird die SP "prc_soundex" dazu verwendet, im Trigger "words_BIU0" die Spalten "wrd_soundex_eng" und "wrd_soundex_ger" mit dem englischen bzw. deutschen Soundex zu füllen.
CREATE OR ALTER PROCEDURE "prc_soundex" (
  IN_WORD TYPE OF "dom_Word",
  IN_LNG TYPE OF "dom_Lng_Token",
  IN_SOUNDEX_LENGTH TYPE OF "dom_INT16" = 4)
RETURNS (
  OUT_SOUNDEX "dom_Word")
AS
DECLARE VARIABLE L_CURRENT_CHAR TYPE OF "dom_SingleChar";
DECLARE VARIABLE L_LAST_CHAR TYPE OF "dom_SingleChar";
DECLARE VARIABLE L_LENGTH TYPE OF "dom_INT16";
DECLARE VARIABLE L_WEIGHT TYPE OF "dom_INT16";
BEGIN

  OUT_SOUNDEX = ''           ;
  L_LENGTH    = 0            ;
  L_LAST_CHAR = ASCII_CHAR(0);

  FOR
      SELECT CASE
              WHEN OUT_POSITION = 1
                 /* An erster Position den ersten Buchstaben ausgeben. */
                 THEN UPPER(OUT_CHAR)
                 /* Ansonsten die Gewichtung ausgeben. */
                 ELSE CAST(MAXVALUE("sxw_weight", 0) AS "dom_SingleChar")
             END,
             "sxw_weight"
        FROM
        (
             SELECT OUT_POSITION,
                    OUT_CHAR,
                    COALESCE("sxw_weight", -1) AS "sxw_weight"
          /* Wort in Buchstaben zerlegen */
               FROM "prc_soundex_chars"(:IN_WORD)
          /* Buchstabengewichtungen lesen */
          LEFT JOIN "soundex_weights" ON "sxw_character" = OUT_CHAR
                                     AND "sxw_language"  = UPPER(:IN_LNG)
        )
       WHERE "sxw_weight" BETWEEN -1 AND 9 /* Nur Gewichtungen von -1 bis 9 lesen */
    ORDER BY OUT_POSITION
  INTO
    :L_CURRENT_CHAR,
    :L_WEIGHT
  DO
  BEGIN
    /* Nur bis übergebene Soundex-Länge. */
    IF (L_LENGTH < IN_SOUNDEX_LENGTH)
    THEN
    BEGIN
      /* Nur hinzufügen, wenn sich das aktuelle Zeichen vom letzten Zeichen */
      /* unterscheidet und Gewichtung ungleich -1 ist. Die erste Position   */
      /* aber immer übernehmen.                                             */
      IF ((L_LAST_CHAR <> L_CURRENT_CHAR AND L_WEIGHT >= 0) OR L_LENGTH = 0)
      THEN
      BEGIN
        /* Das Zeichen '0' kennzeichnet ein Trennzeichen für gleiche */
        /* Konsonanten (Vokale und Y).                               */
        IF (L_CURRENT_CHAR <> '0' OR L_LENGTH = 0)
        THEN
        BEGIN
          OUT_SOUNDEX = OUT_SOUNDEX || L_CURRENT_CHAR;
          L_LENGTH    = L_LENGTH + 1                 ;
        END
        /* Aktuelles Zeichen für nächsten Vergleich merken */
        L_LAST_CHAR = L_CURRENT_CHAR;
      END
    END
    ELSE
    BEGIN
      /* Soundex-Länge erreicht */
      EXIT;
    END
  END

  /* auf Soundex-Länge auffüllen */
  WHILE (L_LENGTH < IN_SOUNDEX_LENGTH)
  DO
  BEGIN
    OUT_SOUNDEX = OUT_SOUNDEX || '0';
    L_LENGTH    = L_LENGTH + 1      ;
  END

END

Suche nach Soundex Werten

Für die Suche wandelt die SP "prc_soundex_list" die Soundex Berechnung in eine selektierbare Abfrage um. Diese gibt genau einen Datensatz zurück und kann damit z.B. in einem JOIN einer Abfrage verwendet werden.
CREATE OR ALTER PROCEDURE "prc_soundex_list" (
  IN_WORD TYPE OF "dom_Word",
  IN_LNG TYPE OF "dom_Lng_Token",
  IN_SOUNDEX_LENGTH TYPE OF "dom_INT16" = 4)
RETURNS (
  OUT_SOUNDEX "dom_Word")
AS
BEGIN
  /* Soundex berechnen */
  EXECUTE PROCEDURE "prc_soundex"(IN_WORD, IN_LNG, IN_SOUNDEX_LENGTH)
    RETURNING_VALUES OUT_SOUNDEX;
  /* als selektierbar ausgeben */
  SUSPEND;
END