Auge: Sortierung von Strings in MySQL mit utf8_bin

Hallo

Eine Tabelle mit Benutzerdaten in einer MySQL-Datenbank enthält, wie überraschend, eine Spalte für den Benutzernamen user_name. Die Tabelle wurde mit CHARSET=utf8 und COLLATE=utf8_general_ci erstellt. Irgendwann ist aufgefallen, dass eine Suche nach "Änni" auch "Anni" ausspuckt. Als Konsequenz daraus wurde für die Spalte user_name die Kollation utf8_bin festgelegt.

Nun wird, wie es gewünscht ist, bei der Suche nach "Änni" nicht mehr "Anni" gefunden, schließlich sool es nicht möglich sein, dass sich mehrere Benutzer mit dem selben Namen registrieren, aber es soll auch nicht "Änni" von der Registrierung ausgeschlossen werden, weil es schon "Anni" gibt. Dies hat aber den Nebeneffekt, dass die Ausgabe, wenn sie nach der Spalte user_name sortiert wird, getrennt nach Namen mit und ohne Großschreibung aufgelistet wird. Warum das so ist, ist klar, utf8_bin unterscheidet strikt nach den Codepoints der Zeichen.

Da die Tabelle in einer Software, die sprachneutral agieren soll, enthalten ist, kann nicht einfach auf eine sprachabhängige Kollation umgestellt werden. Welche Möglichkeiten habe ich, eine Ausgabe unabhängig von Groß- und Kleinschreibung zu sortieren, ohne die Unterscheidung von z.B. "ä" und "a" aufzugeben?

Ist es eventuell sinnvoller, die Kollation der Spalte user_name auf utf8_general_ci zurückzustellen und nur für Vergleiche utf8_bin zu benutzen?

Tschö, Auge

--
Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
Toller Dampf voraus von Terry Pratchett

akzeptierte Antworten

  1. Hello,

    hast Du mal probiert, als Collation utf8_unicode_ci zu verwenden? Das kannst Du auch in der Order-Klausel angeben.

    Liebe Grüße
    Tom S.

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.
  2. Tach!

    Welche Möglichkeiten habe ich, eine Ausgabe unabhängig von Groß- und Kleinschreibung zu sortieren, ohne die Unterscheidung von z.B. "ä" und "a" aufzugeben?

    SELECT name COLLATE utf8_general_ci FROM …

    dedlfix.

    1. Hallo

      Welche Möglichkeiten habe ich, eine Ausgabe unabhängig von Groß- und Kleinschreibung zu sortieren, ohne die Unterscheidung von z.B. "ä" und "a" aufzugeben?

      SELECT name COLLATE utf8_general_ci FROM …

      Hmm, in der Ergebnismenge aus der Abfrage ist das Arrayelement $row['user_name'] (wie das Feld in echt™️ heißt) laut PHP-Fehlermeldung unbekannt. Erweitere ich deinen Ansatz um ein Alias, das mit dem Feldnamen identisch ist, funktioniert die Abfrage.

      SELECT
        ein,
        feld,
        user_name COLLATE utf8_general_ci AS user_name,
        und,
        weitere,
        felder
      FROMORDER BY user_name ASC
      

      Der Ansatz von @TS, die Kollationsangabe in der ORDER-BY-Klausel zu notieren, funktioniert ebenfalls und sieht mMn auch schlüssiger aus, schließlich geht es ja um die Sortierung. Allerdings wird die ORDER-BY-Klausel in meinem Fall dynamisch zusammengebaut, womit eine Kollationsangabe falsch sein kann. Damit ich faul sein kann und nicht noch zusätzliche Fallunterscheidungen treffen muss, bleibe ich bei deiner Lösung. In anderen Anwendungsfällen ist TS' Lösung vermutlich ebenbürtig, oder gibt es da Fallstricke?

      Danke

      Tschö, Auge

      --
      Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
      Toller Dampf voraus von Terry Pratchett
      1. Tach!

        SELECT name COLLATE utf8_general_ci FROM …

        Hmm, in der Ergebnismenge aus der Abfrage ist das Arrayelement $row['user_name'] (wie das Feld in echt™️ heißt) laut PHP-Fehlermeldung unbekannt.

        Es ist halt eine Expression und nicht nur ein Feld. Es ist in $row, aber unter anderem Key als user_name. print_r() oder var_dump() klärt auf.

        Erweitere ich deinen Ansatz um ein Alias, das mit dem Feldnamen identisch ist, funktioniert die Abfrage.

        Ja, ein Alias geht natürlich, um einen freundlichen Namen zu bekommen.

        Der Ansatz von @TS, die Kollationsangabe in der ORDER-BY-Klausel zu notieren, funktioniert ebenfalls und sieht mMn auch schlüssiger aus, schließlich geht es ja um die Sortierung.

        Das war auch mein erster Gedanke, aber den hatte ich wieder verworfen, weil ich im Handbuch nach einem COLLATE in der ORDER BY-Syntax gesucht und nicht gefunden hatte. Aber klar, das geht dort auch, weil name COLLATE utf8_general_ci als Expression gilt und damit genauso gültig ist, wie beispielsweise RAND().

        In anderen Anwendungsfällen ist TS' Lösung vermutlich ebenbürtig, oder gibt es da Fallstricke?

        Kann ich mir nicht vorstellen. Die Kollation ändert an den Daten nichts, anders als beispielsweise eine andere Kodierung zu verwenden. Also sollte es egal sein, ob du das beim SELECT angibst und dann sortierst oder ob du es nur zum Sortieren berücksichtigst.

        dedlfix.

        1. Hallo

          SELECT name COLLATE utf8_general_ci FROM …

          Hmm, in der Ergebnismenge aus der Abfrage ist das Arrayelement $row['user_name'] (wie das Feld in echt™️ heißt) laut PHP-Fehlermeldung unbekannt.

          Es ist halt eine Expression und nicht nur ein Feld. Es ist in $row, aber unter anderem Key als user_name. print_r() oder var_dump() klärt auf.

          Erweitere ich deinen Ansatz um ein Alias, das mit dem Feldnamen identisch ist, funktioniert die Abfrage.

          Ja, ein Alias geht natürlich, um einen freundlichen Namen zu bekommen.

          Wenn ich wegen des an user_name angehängten . nicht die anderen Stellen, an denen der Wert unter seinem ursprünglichen Namen verwendet wird, ändern will – und das will ich nicht –, ist das die Lösung der Wahl. 😀

          Tschö, Auge

          --
          Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
          Toller Dampf voraus von Terry Pratchett
          1. Hello,

            Du hast aber schon gesehen, dass ich utf8_unicode_ci geschrieben hatte und nicht utf8_general_ci?

            Wenn es darum geht, dass Ä # A behandelt wird, ist das mMn besser. Vermutlich gehört es dann aber sogar schon in die Spaltendefinition?

            Liebe Grüße
            Tom S.

            --
            Es gibt nichts Gutes, außer man tut es!
            Das Leben selbst ist der Sinn.
            1. Hallo

              Hello,

              Du hast aber schon gesehen, dass ich utf8_unicode_ci geschrieben hatte und nicht utf8_general_ci?

              Ja, ist mir nicht entgangen.

              Wenn es darum geht, dass Ä # A behandelt wird, ist das mMn besser. Vermutlich gehört es dann aber sogar schon in die Spaltendefinition?

              Das muss ich mir noch einmal anschauen (unicode vs. general). Mit utf8_bin in der Spaltendefinition passt das schon mit den Unterscheidungen. Eine andere Kollation brauche ich ja nur für die Sortierung der Namensliste. Die Spaltendefinition selbst möchte ich, wenn es sich vermeiden lässt, nicht noch einmal anfassen müssen.

              Tschö, Auge

              --
              Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
              Toller Dampf voraus von Terry Pratchett
              1. Hello,

                kommt drauf an, ob Du auch Versalien und Gemeine unterscheinden willst. Dann wäre ut8_bin richtig. Sonst ist utf8_unicode_ci besser in der Spaltendefinition.

                Liebe Grüße
                Tom S.

                --
                Es gibt nichts Gutes, außer man tut es!
                Das Leben selbst ist der Sinn.
                1. Hello,

                  ich habe das eben selber mal auf einer Version 5.5.39 ausprobiert. Eine neuere habe im Moment ich leider nicht für Tests.

                  Leider funktioniert der Tabellentyp/Spaltentyp utf8_unicode_ci auf einer Spalte mit unique Index nicht mit "Jylmaz" + "Jÿlmaz". Da gibt es einen Duplicate Key Error, obwohl es laut Beschreibung eigentlich funktionieren sollte.

                  Das könnte jetzt selbstverständlich auch an der GUI liegen. Ich will also nicht sofort MySQL den Bug zuschieben.

                  Mir dünkt noch eine andere Erklärung:
                  Ein show character set zeigt nur eine übersichtliche Auswahl.
                  Wenn utf8_unicode_ci nicht installiert ist, fällt das vermutlich auf utf8_general_cizurück.

                  Liebe Grüße
                  Tom S.

                  --
                  Es gibt nichts Gutes, außer man tut es!
                  Das Leben selbst ist der Sinn.