Suchen...
Generic filters
Exact matches only
Search in title
Search in excerpt
Search in content

Varchar(max) schneidet Texte ab - Die wundersame Welt der Strings im SQL-Server

Kürzlich stand ich im Rahmen der DeltaMaster-ETL-Entwicklung vor einem Rätsel, welches ich mir nicht erklären konnte. Es ging um die dynamische Erzeugung eines SQL-Objekts aus zusammengesetzten Strings. Trotz der Nutzung des Datentyps varchar(max) wurde der String abgeschnitten. Bis dato dachte ich, varchar(max) wäre eine sichere Bank, um das Abschneiden von Textketten zu verhindern. Weit gefehlt. Unter gewissen Umständen werden auch varchar(max)-Texte gekürzt. Die Lösung dafür ist banal, aber darauf kommen muss man erstmal. Der vorliegende Artikel spart hoffentlich allen Lesern langwieriges Knobeln.

Varchar(max) wird abgeschnitten

Schauen wir uns zunächst das erste Phänomen an. Ich hatte eine Variable als varchar(max) definiert und habe in dieser aus mehreren Einzelblöcken ein SQL-Kommando zusammengebaut. Das hat bis-lang auch immer einwandfrei funktioniert. Nun hatte ich aber einen der Einzelblöcke geringfügig erweitert, was dazu geführt hat, dass ich die magische 8000er-Grenze der String-Länge überschritten habe. Das wiederum hat dazu geführt, dass das Kommando abgeschnitten wurde. Aber warum? Die Zielvariable war doch varchar(max)?! Bauen wir uns zunächst mal ein Beispiel auf, um das Verhalten nachzuvollziehen.

Ich erstelle eine Zielvariable mit dem Datentyp varchar(max) und weise dieser ein Kommando aus mehreren einzelnen Quellvariablen zu. Anschließend lasse ich mir den Text samt länge ausgeben und führe den Befehl aus:

Führt man das Beispielskript schlägt die Ausführung fehl:

Prüft man den erzeugten String sowie die Länge stellt man fest, dass der String nach 8000 Zeichen abgeschnitten wird:

Der String endet folgenermaßen:

Das kann natürlich nicht funktionieren. Die spannende Frage ist nur warum? Der String müsste doch eigentlich in die Variable „reinpassen“?!

Varchar(max) wird nicht abgeschnitten

Durchsucht man die einschlägigen Webseiten stößt man sogar bei Microsoft auf einen entsprechen-den Hinweis. Dort existiert in der Online-Dokumentation ein eigener Artikel, in dem es nur um das Verketten von Zeichenketten geht:

https://docs.microsoft.com/de-de/sql/t-sql/language-elements/string-concatenation-transact-sql?view=sql-server-ver15

Dort existiert sogar ein Beispiel, welches unserem sehr ähnlich ist:

Zunächst fällt hier auf, dass das Gesamtergebnis nur eine Länge von 16.000 Zeichen aufweist (und nicht 24.000 wie es korrekt wäre). Trotz allem ist die Länge größer als 8.000 Zeichen wie in unserem Beispiel? Bei genauerer Betrachtung fällt auf, dass eine der drei Variablen selbst als varchar(max) deklariert ist, die anderen als varchar(8000). In der Zuweisung der Variablen an das Endergebnis wird dabei die alphabetische Reihenfolge vertauscht. Im beschreibenden Text zu dem Bei-spiel findet man die ersten entscheidenden Hinweise:

Da die Verkettung von links interpretiert wird, wird der Text der ersten Verkettung bei 8000 Zeichen abgeschnitten, in der zweiten Verkettung nicht?! Offensichtlich hat die Länge der Einzelblöcke also einen Einfluss auf die Länge der Zielvariable bzw. darauf, ob Text abgeschnitten wird oder nicht! Und das obwohl, dass Ziel die Länge aufnehmen könnte!

Weiter oben in den Bemerkungen des Artikels findet man dann die entscheidenden zwei Zeilen, welche die Vermutung noch einmal bestätigen:

Sprich dadurch, dass in unserem Beispiel weder die verwendeten Einzel-Code-Blöcke, noch der konstante Text größer als 8000 Zeichen ist, wird der gesamte verkettete Text abgeschnitten. Unabhängig davon, wie groß die Zielvariable ist.
Daraus folgere ich, dass es reichen müsste, eine der Einzelvariablen entsprechend zu vergrößern. Fangen wir einmal von hinten an und versuchen den konstanten Text zu vergrößern:

Das einzige was wir damit allerdings erreichen ist eine neue Fehlermeldung:

Ein Blick auf das Prüfstatement verrät die Ursache:


Offensichtlich wurde der erste Teil des Strings durch die Vergrößerung gar nicht verändert, lediglich das Ergänzen des letzten (vergrößerten) Blocks hat die 8000 vergrößert.
Wie wir weiter oben in der Hilfe gelesen haben wird das Statement von links interpretiert. Sprich erst werden @SQLBlock1 und @SQLBlock2 verkettet. Da diese beiden jeweils varchar(6000) sind, wird die Gesamtlänge des Statements nicht über die 8000er-Grenze vergrößert. Auch das Ergänzen der nächsten varchar(6000)-Variable @SQLBlock3 ändert daran nichts. Das Ergebnis bleibt 8000 Zeichen lang. Erst der letzte Teil schafft es den String zu vergrößern.
Ergo müssen wir möglichst weit links in der Kette mit der Vergrößerung beginnen. Daher probieren wir folgendes Statement:

Diese Abfrage läuft schließlich fehlerfrei und liefert das gewünschte Ergebnis:

Wie versprochen eine triviale Lösung. Nur drauf kommen muss man erstmal.
Bisher jedenfalls war mir dieses Phänomen weder bewusst, noch ist es mir in meiner mehr als 20-jährigen Beraterpraxis je untergekommen. Again what learned!