Quando si verifica l'errore, la transazione viene annullata automaticamente e il batch corrente viene interrotto.
Tuttavia, l'esecuzione continua nel batch successivo. Quindi tutte le cose nei batch dopo che l'errore viene eseguito. E poi, quando controlli la presenza di errori in un secondo momento, provi a eseguire il rollback di una transazione già sottoposta a rollback.
Inoltre, per interrompere l'intero script, non solo il batch corrente, dovresti usare:
raiserror('Error description here', 20, -1) with log
Vedi la mia risposta qui per i dettagli su quello.
Quindi devi controllare @error
dopo ogni batch, penso che qualcosa del genere dovrebbe funzionare:
BEGIN TRANSACTION
GO
ALTER Stuff
GO
if @@error != 0 raiserror('Script failed', 20, -1) with log
GO
CREATE New Stuff
GO
if @@error != 0 raiserror('Script failed', 20, -1) with log
GO
DROP Old Stuff
GO
if @@error != 0 raiserror('Script failed', 20, -1) with log
GO
PRINT 'No Errors ... Committing changes'
COMMIT TRANSACTION