Scripts seguros: Una historia de Transacciones, Stored Procedures y GOs por Leonardo Taibo

19. marzo 2010

Cuando trabajamos con bases de datos, tarde o temprano llega la necesidad de tener que preparar scripts para actualizar el modelo de datos en el cliente, en un servidor no accesible, etc. Esto trae una carga importante de riesgos, sobre todo de pérdida de información o de dejar la base en un estado inconsistente.

Para asegurarnos de que todo quede en un estado conocido, en principio podemos abrir una transacción y poner todo el script en un bloque TRY-CATCH como este:

BEGIN TRY
    BEGIN TRANSACTION
    --
    -- Poner acá el script con los cambios de la base
    --
    -- Aceptar los cambios de la transacción
 
    COMMIT TRANSACTION
END TRY
 
BEGIN CATCH
    -- Deshacer los cambios de la transacción
    ROLLBACK TRANSACTION
    --
    -- Manejar el error o relanzarlo
    --
END CATCH

Ahora, supongamos que nuestros cambios son los siguientes:

CREATE TABLE Sucursales (
    IdAlmacen INT,
    Direccion VARCHAR(100)
)
GO
 -- Otros cambios
GO
 
DELETE Articulos
WHERE IdCategoria = 9999
GO
 
-- Cambios sensibles y peligrosos
GO
CREATE PROCEDURE HacerNegocios AS
BEGIN
    --
    -- Aca va la formula mágica de cada uno
    --
END
GO
 
-- ...mas cambios peligrosos!
GO

 

Para ponerlo dentro del bloque TRY-CATCH, la única consideración seria borrar los "GO" ya que sino la transacción y el TRY quedarían incompletos, y el script no ejecutaría correctamente.

Nota: La palabra "GO" no es parte del lenguaje TSQL sino un comando (bastante estándar) interpretado por las aplicaciones como un separador de lotes de instrucciones. Para mas información: http://msdn.microsoft.com/es-es/library/ms188037.aspx .

Con esto surge un problema, el CREATE/ALTER PROCEDURE (también aplicado a Functions y Triggers) debe ser la primera instrucción del lote debido a una restricción de sintáxis de SQL Server

Para salvar este inconveniente, una solución es ejecutar la creación del stored procedure con Dynamic SQL. Quedando asi:

EXEC(N'CREATE PROCEDURE HacerNegocios AS
BEGIN
    --
    -- aqui va la formula magica de cada uno
    --
    SELECT * FROM CC
END')

Con esto, no hay ningún problema de crear o modificar un stored procedure dentro de una transacción.

BEGIN TRY
    BEGIN TRANSACTION
    
    CREATE TABLE Sucursales (
    IdAlmacen INT,
    Direccion VARCHAR(100)
    )
 
    -- Otros cambios
 
    DELETE Articulos
    WHERE IdCategoria = 9999
 
    -- Cambios sensibles y peligrosos
 
    EXEC(N'CREATE PROCEDURE HacerNegocios AS
    BEGIN
        --
        -- aqui va la formula mágica de cada uno
        --
    END')
 
    -- ...mas cambios peligrosos!
    
    -- Aceptar los cambios de la transacción
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    -- Deshacer los cambios de la transacción
    ROLLBACK TRANSACTION
 
    --
    -- Manejar el error o relanzarlo
    --
END CATCH
 

Espero que este pequeño "truco" facilite la generación de scripts para hacer actualizaciones en las bases de datos.

SQL Server , ,

Comentarios

Mihailov
Mihailov
07/07/2010 10:49:25 #
Justo lo que estaba buscando, muchas gracias, añadir, que si dentro del procedure devuelves un valor o utilizas literales con '' para que funcione correctamente solo se tiene que poner un ' mas tanto al abrir como al cerrar ej: ''OK''.

Saludos.

Añadir comentario




  Country flag

biuquote
  • Comentario
  • Vista previa
Loading