Uso algo como esto:
CREATE PROCEDURE ErrorHandlingPattern
( @intParam int
,@varcharParam varchar(10)
,@dateParam datetime
)
AS
BEGIN TRY
SET NOCOUNT ON
DECLARE @Rows int --store @@ROWCOUNT in this
,@ErrorMsg varchar(500) --temp string to build the contents of messages passed into RAISERROR calls
,@LogInfo varchar(5000) --will hold any info necessary for error debugging, append to this throughout the procedure with important info
,@TransactionCount int
SELECT @[email protected]@TRANCOUNT
,@LogInfo='@intParam=' +ISNULL(''''+CONVERT(varchar(10), @intParam )+'''','NULL')
+', @varcharParam=' +ISNULL(''''+ @varcharParam +'''','NULL')
+', @dateParam=' +ISNULL(''''+CONVERT(varchar(10), @dateParam,121 )+'''','NULL')
+'; @@TRANCOUNT=' +ISNULL(''''+CONVERT(varchar(10), @@TRANCOUNT )+'''','NULL')
--validate parameters
IF @intParam ....
BEGIN --logical error
SET @ErrorMsg='Error, invalid value for @intParam: '+ISNULL(''''+CONVERT(varchar(10),@intParam)+'''','NULL')
RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block
END
IF @TransactionCount=0 --if we are already in a transaction, no need to start another, nesting transactions +rollback=warnings about transaction count not being the same as when the procedure started.
BEGIN
BEGIN TRANSACTION
END
--do your work here....
INSERT/UPDATE/DELETE...
SELECT @[email protected]@ROWCOUNT
IF @Rows!=ExpectedValue
BEGIN --logical error
SET @ErrorMsg='Error, INSERT/UPDATE/DELETE of tableXYZ resulted in '+ISNULL(''''+CONVERT(varchar(10),@Rows)+'''','NULL')+' rows affected'
RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block
END
--append improtant info to log string
SET @LogInfo=ISNULL(@LogInfo,'')+'; INSERT/UPDATE/DELETE of tableXYZ resulted in '+ISNULL(''''+CONVERT(varchar(10),@Rows)+'''','NULL')+' rows affected'
IF @TransactionCount=0 --only end the transaction if it started here
BEGIN
COMMIT --put in try block to be able to catch any problems committing
END
END TRY
BEGIN CATCH
IF XACT_STATE()!=0 --if there is any error end the transaction ASAP
BEGIN
ROLLBACK TRANSACTION
END
--will echo back the complete original error message
DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int
SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE()
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine)
--because the transaction was ROLLBACKed this insert will be recorded in the database
INSERT INTO YourErrorLog (...) VALUES (...ISNULL(@ErrorMessage,'')+ISNULL(@LogInfo,''))
RETURN 999
END CATCH
RETURN 0
GO
Dado que solo está haciendo un lote de a batch of SELECT, INSERT
, puede simplemente eliminar el PROCEDIMIENTO DE CREACIÓN y las declaraciones de parámetros y hacer que la primera línea comience en BEGIN TRY. Además, como no está creando un procedimiento, reemplace las declaraciones RETURN con GOTO TheEnd
y agregue una etiqueta TheEnd:
en la parte inferior del script.
Eso es MUY completo, gracias. De hecho, estoy creando un procedimiento: simplifiqué un poco mi pregunta. Muy feliz con @@ ROWCOUNT y @@ TRANCOUNT que aprendí hoy. Siempre evité el proceso almacenado durante mucho tiempo, llamando en cambio bits y piezas 1 por 1 desde Access (que realmente domino). Siéntase como si ahora fuera "profesional" ;-) –