Problem Char-Set's WIN1251 vs WIN 1252

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

Antworten
Hamburgo
Beiträge: 125
Registriert: Di 28. Mai 2019, 17:28

Hallo zusammen,

ich muss zugeben, dass mich bisher Zeichensätze recht wenig interessiert
haben.

Ich habe meine Daten per PHP in der DB gespeichert und wenn ich Selbige wieder gelesen habe,
sind sie auch korrekt wieder rausgekommen. Soweit so gut.

Im Rahmen meines aktuellen Projektes "Erhöhung der Performance meiner DB-Update-Routine"
kommen da so Statements wie z.B.:

Code: Alles auswählen

UPDATE POSTEN SET KLEIN = LOWER (BEZEICHNUNG1 || " " || BEZEICHNUNG2);
und andere zum Einsatz. Für die meisten von Euch wohl täglich Brot, aber ich nutze sowas zum ersten mal.

In den meisten Tabelle funktioniert das auch wunderbar, aber das obige Beispiel fliegt mir
mit folgender Fehler-Meldung um die Ohren:
SQLSTATE[HY000]: General error: -802 arithmetic exception, numeric overflow, or string truncation Cannot transliterate character between character set
Nach einiger Recherche meine ich nun den Grund dafür gefunden zu haben. Das Grund-Gerüst meiner DB habe ich mal aus einem Projekt eines Ex-Freundes übernommen und der hat wohl, warum auch immer, als Basis-CharSet für die DB WIN1251 (Kyrillisch) definiert. (Vielleicht, weil er einen griechischen Migrations-Hintergrund hat.)

Die meinsten Domains für String-Variablen sind jedoch explizit mit CharSet WIN1252 (Westeuropäisch) definiert.

Einige wenige Domains aber nicht, weshalb sie den DB-CharSet WIN1251 übernommen haben.

Fakt ist aber, dass in diesen Feldern / Spalten Daten mit den deutschen Sonder-Zeichen "ä ö ü ß" und auch mit €-Symbol gespeichert sind, also im WIN1252 Charset.

Nun meine Frage:

Wie schaffe ich diesen Murks am schellsten, einfachsten und besten aus der Welt ?

a. Kann ich den Basis-Char-Set der DB nachträglich einfach auf WIN1252 ändern, ohne das es nachteilige Auswirkungen auf die Bestands-Daten hat ?

b. Übernehmen dann die Domains ohne explizite CharSet-Definition automatisch den neuen Basis-CharSet der DB, ohne das es nachteilige Auswirkungen auf die Bestands-Daten hat ?

c. Wenn a. und/oder b. = nein, wie gehe ich dann am klügsten vor, ohne die Bestands-Daten zu gefährden ?

d. Oder anders gefragt: Muss ich zwingend neue Databanken erstellen und manell die Daten von der alten in die neue "pumpen" ?


Danke und viele Grüße
Hamburgo
Zuletzt geändert von Hamburgo am Di 19. Apr 2022, 17:40, insgesamt 1-mal geändert.
Benutzeravatar
martin.koeditz
Beiträge: 443
Registriert: Sa 31. Mär 2018, 14:35

Hallo Hamburgo,

du kannst den "Standard-Zeichensatz" für die Datenbank ändern:

Code: Alles auswählen

ALTER CHARACTER SET <charset_name>
    SET DEFAULT COLLATION <collation_name>
Dieser gilt dann aber nur für neuerstellte Objekte.

Der Zeichensatz für ein vorhandenes Datenbankobjekt kann leider nicht ohne weiteres geändert werden.

Ich bin in diesen Fällen im so vorgegangen:
1. Restore der Datenbank ohne Daten, also nur die Struktur
2. Änderung der Datenbankobjekte
3. Kopieren der Daten aus der alten DB in die neue.

Je nachdem wie viele Tabellen betroffen sind, kannst du auch temporäre Tabellen mit der korrigierten DDL-Struktur erzeugen und die Daten zunächst dorthin kopieren.
1. Neue (temporäre) Tabelle mit neuer Struktur erzeugen
2. Daten in temporäre Tabelle kopieren
3. Alte Tabelle löschen
4. Tabelle unter altem Namen mit neuer DLL-Struktur erzeugen
5. Daten aus temporärer Tabelle überspielen.

Gruß
Martin
Martin Köditz
it & synergy GmbH
Hamburgo
Beiträge: 125
Registriert: Di 28. Mai 2019, 17:28

Hallo Martin,

danke für die schnelle Reaktion.

Ich verstehe Dich dahingehend richtig, dass pro DB-Variante eine "neue"
DB-Struktur mit neuem einheitlichem CharSet (WIN1252) erstellt werden muss und die
Daten Tabelle für Tabelle manuell von der alten DB in die neue DB "ge-pumpt" werden müssen.

Entspricht also meiner "nachgestellten" Frage d. !

Korrekt ?

Danke und viele Grüße
Hamburgo
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Ja, "d" ist die einzig machbare Variante.
Der Default Charset gilt für alle Char-Spalten ausschließlich beim Erstellen von Tabellen. In diesem Fall wird der Charset in die Domain übernommen.
Ein Ändern der Domain (die immer vorhanden ist) hat leider keine Auswirkungen auf vorhandene Daten in den Tabellen.
Man erreicht dann ggf. eine korrupte DB.

Die sicherste (und einzige) Möglichkeit überhaupt ist, Tabelle für Tabelle in einer neuen DB mit anderem CHARSET erstellen und die Daten satzweise kopieren.

Da die aktuelle Clientsprachen alle unicodefähig sind (Strings sind Unicode bzw. UTF16), hast du auch keine Schwierigkeiten beim Lesen 1251 in Unicode in 1252 zu konvertieren.
1251 direkt in 1252 klappt leider nicht.

Wenn du deine Anwendung allerdings multinational machen willst, solltest du ensprechende Felder dezidiert als UTF8 definieren.
Nachweislich halt bei Namensfelder (Name, Ort, Straße, Bezeichnung, ...).
Im Client brauchst du das jedoch nicht berücksichtigen, das ist das Praktische an Strings.

Eine DB in UTF8 hat nur einen kleinen Performancenachteil. Auf Grund der Komprimierung der Zeilen wird die DB nur unwesentlich größer.
UTF8 ist ein variabler Zeichensatz von 1-4 Bytes je Zeichen.
Die FB legt daher UTF8-Felder in 4facher Größe an, was die max. Zeilenlänge dann eben drastisch verkleinert. Aber bei einer vernünftig normierten DB spielt das fast keine Rolle.
Antworten