Sobre @@error, @@rowcount y porqué tener cuidado al utilizarlas juntas

6 10 2007

La manera de manejar los errores en sql server al estilo de la versión 2000 (o < ) es con @@error, que guarda el número de error que se produjo o 0 si no hubo ninguno; y en todas las versiones se utiliza @@rowcount para averiguar la cantidad de filas afectadas por una sentencia. Hay que tener en cuenta algunos detalles para evitar problemas con estas dos variables.

Ambas variables tienen el valor correspondiente luego de cada sentencia, pero este valor cambia en ambas al ejecutar otra, cualquiera que esta sea. Por ejemplo:

INSERT NOMBRES (NOMBRE, APELLIDO) VALUES ('MORCILLO','LOPEZ')
IF @@ERROR <> 0 THEN RETURN @@ERROR

Da como resultado 0 para @@error por mas que la inserción falle, debido a que luego de la sentencia IF se limpia el contenido de @@error. Una manera correcta de manejar esto sería:

DECLARE @@CODIGO_ERROR INT
INSERT NOMBRES (NOMBRE, APELLIDO) VALUES ('MORCILLO','LOPEZ')
SET @@CODIGO_ERROR = @@ERROR
IF @@CODIGO_ERROR <> 0 THEN RETURN @@CODIGO_ERROR

Garantizando así que el error retornado es correcto.

Sobre @@rowcount hay que tener las mismas precauciones, o sea, guardar en una variable el resultado siempre que lo necesitemos para algo.

Ahora ¿como hacer para utilizar ambas variables sin perder ninguna? La solución es asignar ambas en una sola sentencia:

DECLARE @@CODIGO_ERROR INT
DECLARE @@RCOUNT INT
INSERT NOMBRES (NOMBRE, APELLIDO) VALUES ('MORCILLO','LOPEZ')
SELECT @@CODIGO_ERROR = @@ERROR, @@RCOUNT = @@ROWCOUNT
IF @@CODIGO_ERROR <> 0 THEN RETURN @@CODIGO_ERROR
IF @@RCOUNT...

La sentencia Select es una sola y asigna las dos variables.

Sobre error handling en sql server, hay un artículo (en inglés) de Erland Sommarskog que recomiendo para tener una idea completa del tema. (así como todos los artículo de Erland, que son algo así como “la verdad” de cada tema de sql sobre el que publica)

Por último, me gusta ser cuidadoso el escribir sql, tabulaciones, alias legibles, etc. Por este mismo motivo me gusta poner las sentencias de error handling en una sola línea: (el ejemplo con rollback de la transacción)

SET @@CODIGO_ERROR = @@ERROR /**/ IF @@CODIGO_ERROR <> 0 THEN /**/
BEGIN /**/ ROLLBACK TRAN /**/ RETURN @@CODIGO_ERROR /**/ END

Cuestión de gustos…

Anuncios