⚠️ THROW & das Semikolon – Die unsichtbare Stolperfalle in T-SQL
BEGIN TRY ... BEGIN CATCH ... THROW, aber SQL Server meldet: Falsche Syntax in der Nähe von 'THROW'.
Die Lösung ist simpler als gedacht: ;THROW statt THROW. Klingt banal? Ist es auch – aber dieses feine Semikolon hat schon viele Nächte zerstört. Hier kommt die ganze Geschichte.
THROW ab.
-- Diese Prozedur erzeugt einen Syntaxfehler!
CREATE PROC [dbo].[_01a_GetPropertiesForAllSQLEntries]
AS
SET NOCOUNT ON;
DECLARE @ManagedEntityRowId BIGINT
DECLARE db_cursor CURSOR FOR ...
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @ManagedEntityRowId
BEGIN TRY
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC ReadProperties @ManagedEntityRowId, 'SQLServer'
FETCH NEXT FROM db_cursor INTO @ManagedEntityRowId
END
END TRY
BEGIN CATCH
IF CURSOR_STATUS('local', 'db_cursor') >= 0
BEGIN
CLOSE db_cursor
DEALLOCATE db_cursor
END
THROW; -- ❌ Msg 102, Level 15: Falsche Syntax in der Nähe von 'THROW'
END CATCH
CLOSE db_cursor
DEALLOCATE db_cursor
GO
THROW direkt nach einem DEALLOCATE, CLOSE oder einem anderen Statement ohne abschließendes Semikolon kommt.
;THROW – das führende Semikolon trennt das vorherige Statement sauber ab.
BEGIN CATCH
IF CURSOR_STATUS('local', 'db_cursor') >= 0
BEGIN
CLOSE db_cursor
DEALLOCATE db_cursor
END
;THROW -- ✅ Jetzt wird es akzeptiert
END CATCH
CATCH-Block, in dem THROW nicht das allererste Statement ist, ein Semikolon davor.
;THROW ist die sicherste Variante – unabhängig vom vorherigen Code.
THROW ist im Vergleich zu RAISERROR strenger – es verlangt ein explizites Ende des vorherigen Befehls.
RAISERROR-Funktion war toleranter. THROW wurde mit einer strengeren Parser-Regel eingeführt.
-- RAISERROR (veraltet, aber oft noch gesehen)
RAISERROR('Fehler aufgetreten', 16, 1);
-- THROW (modern, seit SQL Server 2012)
;THROW 50000, 'Fehler aufgetreten', 1;
Der Parser von SQL Server erwartet, dass jedes Statement abgeschlossen ist. Steht THROW nach einem DEALLOCATE (das kein Semikolon hat), denkt der Parser: „Das THROW gehört noch zum DEALLOCATE dazu“ – und das ergibt keinen Sinn.
Ein führendes Semikolon sagt: „Hier ist ein harter Trennpunkt, das vorherige Statement ist zu Ende.“ – und plötzlich passt alles.
;THROW schreiben – dann ersparst Du Dir die Fehlersuche. Unabhängig davon, ob vorher ein Semikolon steht oder nicht.
CATCH-Block mit THROW aus – inklusive Cursor-Aufräumung.
CREATE PROC [dbo].[_01a_GetPropertiesForAllSQLEntries]
AS
SET NOCOUNT ON;
DECLARE @ManagedEntityRowId BIGINT
DECLARE db_cursor CURSOR FOR
SELECT ManagedEntityRowId FROM [dbo].[SQLServer]
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @ManagedEntityRowId
BEGIN TRY
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC ReadProperties @ManagedEntityRowId, 'SQLServer'
FETCH NEXT FROM db_cursor INTO @ManagedEntityRowId
END
END TRY
BEGIN CATCH
IF CURSOR_STATUS('local', 'db_cursor') >= 0
BEGIN
CLOSE db_cursor
DEALLOCATE db_cursor
END
;THROW -- ✅ Das führende Semikolon macht den Unterschied
END CATCH
CLOSE db_cursor
DEALLOCATE db_cursor
GO
CLOSE, DEALLOCATE oder SET ein Semikolon – das ist ANSI-Standard und beugt solchen Problemen vor.
Aber mindestens gilt: ;THROW im CATCH ist ein absolutes Muss.
THROW kann auch außerhalb von CATCH verwendet werden – aber auch dort lauern Syntaxregeln.
-- Außerhalb von CATCH: THROW benötigt Parameter ;THROW 50000, 'Benutzerdefinierter Fehler', 1; -- Das geht nicht (keine Parameter): ;THROW; -- ❌ Fehler: Falsche Anzahl von Parametern
Zwei häufige Fehlerquellen:
- THROW ohne Parameter außerhalb von CATCH → funktioniert nicht (nur innerhalb von CATCH darf
THROW;allein stehen, um die originale Fehlermeldung weiterzuleiten). - Vergessenes Semikolon vor THROW → Syntaxfehler.
THROW akzeptiert entweder ;THROW (im CATCH, um die Exception erneut zu werfen) oder ;THROW error_number, message, state. Aber immer mit semantischem Trennzeichen davor.
THROW-Syntaxproblem stolperst.
- Regel 1: Jeder
CATCH-Block, derTHROWenthält, schreibt;THROW– nichtTHROW. - Regel 2: Trenne nach Möglichkeit jedes T-SQL-Statement mit einem Semikolon ab (ANSI-Standard).
- Regel 3: Wenn der Fehler auftritt: Setz ein Semikolon vor
THROWund alles wird gut.
-- Gute Angewohnheit: Jedes Statement mit Semikolon beenden DECLARE @i INT = 0; SELECT @i = 1; BEGIN TRY PRINT 'Hallo'; END TRY BEGIN CATCH ;THROW; -- Sicherheits-Semikolon END CATCH
THROW ist der strenge Lehrer, der Dir zeigt, warum sie wichtig sind.
📌 Fazit für Deine tägliche Arbeit
Das THROW-Semikolon-Problem ist eine der unscheinbarsten, aber hartnäckigsten Stolperfallen in T-SQL. Es kostet Dich vielleicht 20 Minuten Debugging – bis Du die Lösung kennst. Danach wirst Du automatisch ;THROW schreiben, ohne nachzudenken.
✨ Pro-Tipp: Nutze in Deinen SQL-Skripten und Prozeduren konsequent Semikolons als Terminatoren. Dann passiert Dir das Problem nie wieder – und Dein Code ist zukunftssicher (z.B. für SQL Server 2022 und die kommenden Versionen).