Heute kam es in einem meiner Projekt zu folgendem Fehler
Msg 6841, Level 16, State 1, Line 1
FOR XML konnte die Daten für den ‘Tabelle’-Knoten nicht serialisieren, weil ein in XML unzulässiges Zeichen (0x0000) enthalten ist. Um diese Daten mithilfe von FOR XML abzurufen, konvertieren Sie sie in den Datentyp ‘binary’, ‘varbinary’ oder ‘image’, und verwenden Sie die BINARY BASE64-Direktive.
Nach kurzem Suchen bemerkte ich dann, dass nicht die Ausgabe mittels FOR XML fehlerhaft war, sondern in einzelnen Feldern einer Tabelle CHAR(0)
-Zeichen enthalten waren, die da nicht hingehörten. Die Tabelle wird von anderer Stelle gefüllt und eigentlich wird dabei der entsprechende Text abgeschnitten, dieses Sonderzeichens in dem Fall wohl aber nicht mehr. Nachdem die Befüllung geändert wurde, mussten die bereits geschriebenen CHAR(0)
-Einträge noch geändert werden, doch das stellte sich als schwerer heraus als zuerst angenommen. Sicher war, dass die Zeichen nur am Ende eines Textes vorkamen. Zum Testen gab es folgende temporäre Tabelle
|
|
Das Problem sollte schnell gelöst werden können.
|
|
Sieht einfach aus, macht - zumindest theoretisch - genau dass, was ich will, funktioniert aber nicht :(
Führt man die Abfrage aus, werden nur 2 Datensätze angepasst - und das kann ja nicht sein, es werden definitiv 4 Zeilen mit CHAR(0)
gefüllt. Die WHERE
-Klausel muss also fehlerhaft sein. Ich dachte mir, dass LIKE
eventuell so seine Probleme mit CHAR(0)
hat und stellte die Abfrage um.
|
|
Doch auch diese Abfrage führte zur Änderung von lediglich zwei Datensätze - um genau zu sein, sind es die Datensätze, bei denen CHAR(0)
an erster Stelle steht. Folglich muss es aber so sein, dass auch SUBSTRING
nicht funktionieren kann, selbst wenn die WHERE
-Klausel korrekt wäre. Nun - so dachte ich - dann ersetze ich eben alle CHAR(0)
durch Leerzeichen und schneide in einem zweiten Schritt diese dann mit TRIMLEFT ab.
Doch auch das funktioniert einfach nicht. REPLACE findet nur CHAR(0)
in den beiden Zeilen, die auch mit CHAR(0)
anfangen. Beim Ersetzen wird aber nur das erste Vorkommen davon ersetzt, der Rest wird abgeschnitten. Nach
|
|
wird aus CHAR(0)
ebenso ‘X’ wie auch aus CHAR(0) + CHAR(0)
… Hier wird ein CHAR(0)
offensichtlich dazu verwendet, den Text als beendet zu kennzeichnen.
Warum es so ist wie es ist kann ich leider immer noch nicht sagen. Wenn man aber als COLLATION statt Latin1_General_CI_AS eine SQL-Server interne Sortierung wie z.B. SQL_Latin1_General_CP1_CI_AS verwendet (grob gilt, dass alle Sortiernamen mit dem Prefix “SQL_” SQL-Sortierungen und alle anderen Windows-Sortierungen sind), dann funktioniert alle bisher beschriebenen Abfragen. Wenn man diese aber nicht unbedingt in der Tabelle direkt Umstellen kann oder will, geht es auch inline. So liefert z.B.
|
|
ebenso das zuvor gewünschte Zwischenergebnis wie
|
|
das eigentlich gewünschte Endergebnis… Man darf es nur an keiner Stelle vergessen, bei der nach Sonderzeichen gesucht wird. Im ersten Parameter von SUBSTRING
ist es dagegen einfach nicht notwendig.