Generando Procedimientos Almacenados de manera automática

 

Fecha: 05/Ago/2005 (04-08-05)
Autor: Martin Luchessi

 


         Hola, mi nombre es Martín Luchessi. Soy de Rosario, Argentina y es la primera vez que escribo (o al menos, intento escribir) un artículo sobre informática, asi que por favor, ténganme paciencia. :P

         La idea de este artículo es explicar, al menos desde mi experiencia, el uso de las vistas de sistema y funciones de SQL Server, para realizar un script que genere código SQL para crear un procedimiento almacenado (desde ahora en adelante, PA) que actualice, modifique y elimine registros de una tabla dada de acuerdo a la clave de la misma.

         Si bien con SQL Server 2000 podemos generar 3 PAs que hagan las 3 consultas por separado, la idea es que este script genere UN solo PA y que realice la acción correspondiente de acuerdo a un parámetro del PA.

         Este script generará un código que se escribirá en el panel de resultados de SQL Server, el cual nosotros copiaremos luego para correrlo en una nueva consulta.

         Es decir, la idea es que el código generado sea algo asi:

 

CREATE PROCEDURE <NOMBRE_DEL_PA>

(

            @p_parametro1             TIPO_DATO,

            @p_parametro2             TIPO_DATO,

            …

            @p_tipo_accion             CHAR(1)

)

 

AS

 

            Si @tipo_accion = ‘A’ –-acción ACTUALIZAR O INSERTAR

                        si no existe un registro en la tabla indicada para la clave de la misma

                                   Ejecuto una consulta INSERT sobre la tabla

                       

                        si existe el registro

                       

                                   Ejecuto una consulta UPDATE sobre la tabla

           

            END

            IF @tipo_accion = “E” –acción ELIMINAR

                       

                        Borro los registros de la tabla.

           

            Devuelvo cantidad de registros actualizados por la consulta

 

 

         Vale la pena aclarar, que al momento de borrar registros, el script no controla (al menos esta versión no lo hace) que existan tablas relacionadas con la tabla de la cual se desea borrar registros. Es decir, si quiero borrar una persona y esta tiene números de teléfonos relacionados, si existe una restricción de clave foránea armada para la tabla de personas, con aquella que guarda los números de teléfonos, el motor de base de datos generará una excepción y no permitirá efectuar la consulta. De la misma manera, tampoco controla que, al momento de insertar un nuevo registro en la tabla, se esté ingresando datos que no existan en tablas relacionadas con ésta.

        

         Bueno, basta ya de explicaciones y pongámonos manos a la obra.

 

DECLARACIÓN DE LAS VARIABLES DE ENTRADA.

 

         En primer lugar, necesitaremos 2 variables importantes para este script. Una que contendrá el nombre de la tabla sobre la que generaremos el PA y otra  que contendrá el nombre del PA. Ésta variable en realidad puede ser obviada, ya que podemos dejar que el script se encargue de nombrar el PA. En mi caso yo elegí que si esta variable viene vacía el PA se llame “PA_ABM_NOMBRE_TABLA”, pero es algo que fácilmente pueden cambiar si no les gusta.  Ambas variables fueron declaradas como SYSNAME, ya que éste es el tipo de datos suministrado por el sistema y definido por el usuario que es funcionalmente equivalente a nvarchar(128) y que se utiliza para hacer referencia a nombres de objetos de bases de datos.

 

         A continuación escribimos dos líneas que nos permitirán asignarle valor a estas variables. Los valores van escritos entre comillas simples por ser SYSNAME un tipo de dato de texto.

 

 

DECLARE @P_NOMBRE_TABLA   SYSNAME

DECLARE @P_NOMBRE_PA                     SYSNAME

 

set @P_NOMBRE_TABLA = 'aquí va el nombre de la tabla'

set @P_NOMBRE_PA = 'aquí va el nombre del PA si quieren asignarle uno'

 

 

         Esta sección es la única parte del código que tendremos que modificar, cuando queramos generar un PA para una tabla.

 

 

DECLARACIÓN DE VARIABLES AUXILIARES

 

            Las siguientes son variables auxiliares que nos ayudarán a mantener el texto que deberá escribir el script en el panel de resultados del Analizador de Consultas de SQL Server 2000.

 

 

DECLARE @SQL_CABECERA       VARCHAR(8000)

DECLARE @dato                                    VARCHAR(8000)

DECLARE @SQL_WHERE                        VARCHAR(8000)

DECLARE @SQL_UPDATE                       VARCHAR(8000)

DECLARE @SQL_INSERT                        VARCHAR(8000)

DECLARE @SQL_VALUES                       VARCHAR(8000)

DECLARE @SQL_DELETE                        VARCHAR(8000)

 

        

         La variable @SQL_CABECERA la utilizaremos para guardar la cabecera del PA.  Es decir, toda la sección que comprende la verificación de que el PA exista en la base de datos, la eliminación y posterior creación del PA con sus parámetros.

         Las restantes variables declaradas arriba se utilizarán para armar cada consulta.

         Ahora bién. ¿Cómo sabemos que tabla hay que actualizar y bajo qué condición? ¿Cómo sabemos cuales columnas son clave de la tabla y cual no? ¿Qué tipo de dato tiene cada columna de la tabla? Todos estos datos son necesarios para actualizar una tabla, o mejor dicho, sus datos.

         Para esto, vamos a necesitar, una variable de tipo TABLE, que me permita dejar registrado todas las características de la tabla sobre la que se quiere operar. Y además, el órden en que se encuentran las columnas, para luego poder respetar los índices de la tabla.

 

DECLARE @tabla                       TABLE(orden smallint, columna SYSNAME, pk BIT, parametro varchar(25),                             tipo_dato varchar(25), largo smallint, decimales smallint)

 

 

         La columna columna, contendrá el nombre de las columnas de la tabla.

         La columna PK, nos indicará si la columna de la tabla es Primary Key o no.

         La columna parámetro, nos servirá para saber a que parámetro del PA corresponde esta columna.

         La columna tipo_dato, largo y decimales dejarán registrado que tipo de dato tiene la columna de la tabla, el largo del tipo de dato y la precisión del mismo.

         También necesitaremos declarar variables para las columnas, para utilizarlas a la hora de recorrer la VARIABLE @tabla.

 

DECLARE @orden                      SMALLINT

DECLARE @largo                       SMALLINT

DECLARE @decimales    SMALLINT

DECLARE @pk               BIT

DECLARE @parametro   VARCHAR(25)

DECLARE @columna                  SYSNAME

 

 

         Por último,esta variable @update, sirve como bandera para controlar que si la tabla es una tabla TODO-CLAVE, es decir, que todas las columnas de la tabla son clave primaria, no será necesario hacer un update de la misma. Por lo tanto, tomará valor 0 (cero) cuando no sea necesario  y 1 (uno) cuando si lo sea.

 

DECLARE @update                    BIT

 

VALIDANDO LA EXISTENCIA DE LA TABLA

 

            Antes de empezar a generar el código, sería interesante que el script controle que la tabla sobre la cual se quiere generar el PA exista.

         Si el nombre de la tabla está vacío, sería interesante imprimir un cartel insitando al programador, o usuario del script , a que escriba un nombre de una tabla, sino el script no tendría sentido.

 

            IF LEN(@p_nombre_tabla)=0

            begin

                        PRINT 'ESTAS PENSANDO EN LO QUE HACES? Y EL NOMBRE DE LA                                  TABLA? '

                        PRINT 'ADIVINO NO SOY!'

                        RETURN

            end

 

         Del mismo modo, un nombre de tabla inválido tendría el mismo efecto y podemos generar un mensaje de error de la base de datos, haciendo una consulta sobre la tabla inexistente, para obviarnos el poner un mensaje nosotros,.

 

            IF OBJECT_ID(@p_nombre_tabla) IS NULL

            begin

                        --PRINT 'LA TABLA <' + @p_nombre_tabla + '> NO EXISTE COMO                                   UN OBJETO'

                        SET @p_nombre_tabla='SELECT 1 FROM ' +  @p_nombre_tabla

                        exec(@p_nombre_tabla)

                        return

            end

        

         La función Object_ID(objeto) devolverá null si la tabla no se encuentra en la base de datos y el ID de la tabla, en caso contrario.

        

RECOLECTANDO DATOS SOBRE LA TABLA

           

Para armar este script vamos a necesitar distinguir las distintas partes del PA que queremos que arme. Para mi entender, el PA consta de 4 partes:

 

·         CABECERA

·         CONSULTA INSERT

·         CONSTULTA UPDATE

·         CONSULTA DELETE

 

En la cabecera, cómo dije anteriormente, vamos a escribir la creación del PA, con sus parámetros y los tipos de datos de los mismos. Además, vamos a agregarle valores por defecto a estos, para asi lograr que se puedan obviar ciertos parámetros cuando se quiera ejecutar el PA desde alguna aplicación. Por ejemplo, cuando se quiera hacer un DELETE los únicos parámetros que tendremos que pasarle serían aquellos que son clave de la tabla y el parámetro “@p_accion = ‘E’”.

En la consulta INSERT,  no tendremos demasiados problemas. Sólo necesitamos los nombres de las columnas y sus valores.

En cambio en las consultas UPDATE y DELETE necesitaremos armar el WHERE de la consulta, y es aquí donde viene el pequeño problema ya que necesitaremos saber cuáles columnas son PRIMARY KEY y cuales no.

Aquí haremos uso de la variable @Tabla que hemos declarado al comienzo de nuestro script para poder guardar toda la información que necesitemos sobre la tabla que estamos trabajando y así no hacer una consulta a las tablas de sistema cada vez que lo requiramos.

Para buscar información sobre las tablas haremos uso de las VISTAS DE ESQUEMA DE INFORMACIÓN de SQL Server 2000.

Estas vistas proporcionan una vista interna e independiente de las tablas del sistema de los metadatos de SQL Server. Las vistas de esquema de información permiten que las aplicaciones funcionen correctamente aunque se hayan realizado cambios significativos en las tablas del sistema. Las vistas de esquema de información que contiene SQL Server cumplen la definición del estándar SQL-92 para INFORMATION_SCHEMA.

Estas vistas se definen en un esquema especial llamado INFORMATION_SCHEMA, contenido en cada base de datos. Cada vista de INFORMATION_SCHEMA contiene metadatos para todos los objetos de datos almacenados en esa base de datos en particular. Esta tabla describe las relaciones existentes entre los nombres de SQL Server y los nombres estándar de SQL-92.

 

Vamos a utilizar las siguientes vistas:

 

·         COLUMNS

 

Contiene una fila por cada columna a la que puede tener acceso el usuario actual en la base de datos actual.

 

·         TABLE_CONSTRAINTS

 

Contiene una fila por cada restricción de tabla de la base de datos actual. Esta vista de esquema de información devuelve información acerca de los objetos sobre los que el usuario actual tiene permisos.

 

·         KEY_COLUMN_USAGE

 

Contiene una fila por cada columna, de la base de datos actual, que está restringida como clave. Esta vista de esquema de información devuelve información acerca de los objetos sobre los que el usuario actual tiene permisos.

 

De la vista COLUMNS nos interesa buscar el nombre de cada columna de la tabla (COLUMN_NAME), el tipo de dato de cada columna (DATA_TYPE), el tamaño máximo de caracteres (CHARACTER_MAXIMUM_LENGTH) en caso de tipos de dato de texto, o la precisión (NUMERIC_PRESICION) en caso de tipos de datos numéricos (en caso de datos con decimales, necesitaremos saber cuántos decimales tiene con (NUMERIC_SCALE)), y el número identificador de columna (ORDINAL_POSITION).

Las vistas KEY_COLUMN_USAGE y TABLE_CONSTRAINTS las vamos a usar para ver que columnas de la tabla son PRIMARY KEY haciendo una consulta y relacionando columnas entre las vistas.

         Así, cada dato que seleccionemos de estas vistas, lo insertaremos en la variable @tabla, de la siguiente manera:

 

 

insert into @tabla

select

            COLS.ORDINAL_POSITION,

            COLS.COLUMN_NAME,

            convert(bit,(

select  count(*)

                        from

                                   INFORMATION_SCHEMA.TABLE_CONSTRAINTS as CONST

                        JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as COL ON

                                   CONST.TABLE_SCHEMA = COL.TABLE_SCHEMA              AND

                                   CONST.TABLE_NAME = COL.TABLE_NAME                                  AND

                                   CONST.CONSTRAINT_NAME = COL.CONSTRAINT_NAME

                        where

                                   CONST.CONSTRAINT_TYPE        = 'PRIMARY KEY'                       AND

                                   CONST.CONSTRAINT_SCHEMA   = 'dbo'                         AND

                                   COL.TABLE_NAME                     = COLS.TABLE_NAME    AND

                                   COL.COLUMN_NAME                  = COLS.COLUMN_NAME

)),

            '@p_' + COLS.COLUMN_NAME,

            UPPER(COLS.DATA_TYPE),

            ISNULL(COLS.CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION),

            isnull(cols.numeric_scale,0)         

from

            INFORMATION_SCHEMA. COLUMNS  COLS  WITH (NOLOCK)

where

            COLS.TABLE_NAME = @P_NOMBRE_TABLA

order by

            cols.ordinal_position

 

 

1

2

3

 

 

 

 

 

 

 

 

 

 

 

 

 

4

5

6

 

 

 

7

 

8

 

 

         Como podemos observar, en las líneas 1 y 2, estamos usando las columnas ORDINAL_POSITION y COLUMN_NAME para guardarlas en las columnas “orden” y  “columna” de la tabla @tabla.

En la línea 3 nos vamos a detener un poco. Más arriba en este artículo, habíamos dicho que necesitábamos saber qué columnas de la tabla eran clave primaria para poder luego armar el WHERE de las consultas UPDATE y DELETE. Aquí se está realizando una subconsulta para contar todas las columnas cuyo tipo de constraint sea “PRIMARY KEY” de la tabla @P_NOMBRE_TABLA, relacionando las vistas TABLE_CONSTRAINTS y KEY_COLUMN_USAGE por medio de sus columnas TABLE_SCHEMA, CONSTRAINT_NAME y TABLE_NAME, para ver cuales son las restricciones de @P_NOMBRE_TABLA. Como sólo nos interesa la restricción PRIMARY KEY, filtramos por la columna CONSTRAINT_TYPE de la vista TABLA_CONSTRAINTS.

 

 A continuación, convertimos el valor que devuelve la subconsulta a Bit, asi podremos guardar en la columna PK de @tabla , un 1 si el COUNT es > 0, y 0 en caso contrario.

         En el renglón marcado con el número 4 estamos guardando el valor para la columna @parametro de la variable @tabla, ya con el agregado del prefijo “@p_”, que nos indicará cuál es el parámetro del PA que le corresponde a cada columna.

         En la linea 5, vamos a guardar el tipo de dato de la columna, y en las líneas 6 y 7 obtendremos el largo del tipo de dato y la precisión. Si CHARACTER_MAXIMUM_LENGHT es NULL entonces guardermos NUMERIC_PRESICION, ya que estaríamos en presencia de un tipo de dato numérico. Si NUMERIC_SCALE es NULL entonces guardaremos 0 ya que estaríamos en presencia de datos enteros, texto. Para los tipos de dato DATETIME no nos interesa tener mucho detalle en este caso.

         En las líneas 7 y 8 solamente le indicamos a la consulta en que tabla queremos que busque información y ordenamos por ORDINAL_POSITION para que busque en el orden de las columnas de la tabla.

         Veamos todo esto en un ejemplo práctico.

 

Ejemplo: PA sobre la tabla PERSONAS.

 

Supongamos una tabla PERSONAS con los siguientes atributos.

 

 

         Si hacemos una consulta sobre la variable @tabla, luego de recabar los datos, daría un resultado como este:

 

orden 

columna                                                                                                                          

pk  

parametro

tipo_dato                

largo 

Decimales

1

Cod_persona

1

@p_Cod_persona

INT

10

0

2

Nombre

0

@p_Nombre

VARCHAR

50

0

3

Apellido

0

@p_Apellido

VARCHAR

50

0

4

Tipo_doc

0

@p_Tipo_doc

SMALLINT

5

0

5

Nro_doc

0

@p_Nro_doc

VARCHAR

20

0

6

Fec_nacimiento

0

@p_Fec_nacimiento

DATETIME

23

3

 

         Cómo podemos observar, la columna Cod_persona, tiene un 1 en PK, es decir que es clave primaria. El parámetro que le corresponderá en el PA se llamará @p_Cod_persona, es de tipo INT con un largo de 10 y 0 decimales, lo cual es correcto.

Ahora, vamos a acomodar la columna tipo_dato de @tabla para que contenga el podamos tener el tamaño máximo de caracteres, o la presición del tipo de dato entre paréntesis ya que cuando tengamos que cuando tengamos que declarar los parámetros del PA los vamos a necesitar.

Para esto hacemos un cursor que recorra la tabla y actualice la columna según si tiene decimales o no, pero sólo para aquellas columnas que lo requieran.

 

DECLARE C_COLUMNAS CURSOR LOCAL  FOR

            SELECT

                        orden,

                        largo,

                        decimales

            FROM

                        @tabla

            WHERE

                        tipo_dato IN ('VARCHAR','CHAR','NVARCHAR','NCHAR','DECIMAL','NUMERIC')

OPEN C_COLUMNAS

 

FETCH NEXT FROM C_COLUMNAS INTO

            @orden,

            @largo,

            @decimales

WHILE @@FETCH_STATUS = 0

BEGIN

            IF @decimales = 0

                        UPDATE

                                   @tabla

                        SET tipo_dato = tipo_dato + '(' + CONVERT(VARCHAR, @largo) + ')'

                        WHERE

                                   orden = @orden

            ELSE

                        UPDATE

                                   @tabla

                        SET tipo_dato = tipo_dato + '(' + CONVERT(VARCHAR, @largo) + ',' + CONVERT(VARCHAR,@decimales) + ')'

                        WHERE

                                   orden = @orden

FETCH NEXT FROM C_COLUMNAS INTO

            @orden,

            @largo,

            @decimales

END

 

CLOSE C_COLUMNAS

DEALLOCATE C_COLUMNAS

 

Ahora si, si hiciéramos, otra vez, una consulta sobre @tabla nos quedaría:

orden 

columna                                                                                                                          

pk  

parametro

tipo_dato                

largo 

Decimales

1

Cod_persona

1

@p_Cod_persona

INT

10

0

2

Nombre

0

@p_Nombre

VARCHAR(50)

50

0

3

Apellido

0

@p_Apellido

VARCHAR(50)

50

0

4

Tipo_doc

0

@p_Tipo_doc

SMALLINT

5

0

5

Nro_doc

0

@p_Nro_doc

VARCHAR(20)

20

0

6

Fec_nacimiento

0

@p_Fec_nacimiento

DATETIME

23

3

 

         Una vez recolectado todos los datos y acomodados a nuestro gusto, estamos listos para armar las partes del PA.

 

LA CABECERA

 

Siguiendo con el ejemplo de la tabla PERSONAS, la cabecera del PA debería quedar algo asi:

 

IF EXISTS (SELECT name FROM  sysobjects WHERE  name = N'PA_ABM_PERSONAS'  AND type = 'P')

DROP PROCEDURE PA_ABM_PERSONAS

GO

CREATE PROCEDURE PA_ABM_PERSONAS

(

            @p_Cod_persona                      INT,

            @p_Nombre                  VARCHAR(50)= NULL ,

            @p_Apellido                  VARCHAR(50)= NULL ,

            @p_Tipo_doc                 SMALLINT= NULL ,

            @p_Nro_doc                  VARCHAR(20)= NULL ,

            @p_Fec_nacimiento                   DATETIME= NULL,

            @p_accion         CHAR(1) --A = ACTUALIZA (INSERT/UPDATE) , E = ELIMINA

)

AS

 

La primera parte de la cabecera, cómo dijimos al principio, nos servirá para eliminar el PA de la base de datos en caso de que este ya exista, y luego lo volveremos a crear.

Como podemos notar, en la segunda parte, hay columnas que tienen valores por defecto y otras que no. Este se debe, por supuesto, a que las columnas clave tienen que ser obligatorias a la hora de ejecutar las consultas. También vemos que los tipo de dato de texto tienen que ir declarados con su tamaño máximo de caracteres, al igual que los datos decimales.

 

EL CUERPO

           

            El cuerpo que queremos armar del PA debería quedar asi:

           

IF (@p_accion = 'A')

BEGIN -- SI LA ACCION ES ACTUALIZAR

            IF NOT EXISTS (

                        SELECT 1

                        FROM

                                   PERSONAS

                        WHERE

                        Cod_persona     =          @p_Cod_persona

                                   )

            INSERT INTO PERSONAS

            (

                        Cod_persona,

                        Nombre,

                        Apellido,

                        Tipo_doc,

                        Nro_doc,

                        Fec_nacimiento

            )

            VALUES

            (

                        @p_Cod_persona,

                        @p_Nombre,

                        @p_Apellido,

                        @p_Tipo_doc,

                        @p_Nro_doc,

                        @p_Fec_nacimiento

            )

            ELSE --SI EXISTE HAGO UPDATE

                       

            UPDATE PERSONAS

            SET

                        Nombre            =          @p_Nombre,

                        Apellido            =          @p_Apellido,

                        Tipo_doc           =          @p_Tipo_doc,

                        Nro_doc                        =          @p_Nro_doc,

                        Fec_nacimiento  =          @p_Fec_nacimiento

            WHERE

                        Cod_persona     =          @p_Cod_persona

END --TERMINA DE ACTUALIZAR

ELSE IF @p_accion = 'E'

           

            DELETE PERSONAS

            WHERE

                        Cod_persona     =          @p_Cod_persona

                       

RETURN @@ROWCOUNT

GO

 

         Para lograr que el script escriba esto en el panel de resultados, debemos usar el método PRINT en cada línea que queramos escribir o en las variables de texto que declaramos al comienzo de esta historia.

        

ESCRIBIENDO EL PROCEDIMIENTO ALMACENADO EN PANTALLA

 

         Para comenzar a escribir el PA, debemos, en principio, inicializar las variables.

 

/*         INCIALIZO LAS VARIABLES DEL TEXTO  */

 

IF @P_NOMBRE_PA = ''

            SET @P_NOMBRE_PA = 'PA_ABM_'+ @P_NOMBRE_TABLA

 

SET @SQL_WHERE = '    WHERE

'

SET @SQL_INSERT = '   INSERT INTO ' + @P_NOMBRE_TABLA + '

            (

'

SET @SQL_VALUES = '   VALUES

            (

'

SET @SQL_UPDATE = ' UPDATE ' + @P_NOMBRE_TABLA + '

            SET

'

SET @SQL_DELETE = '   DELETE ' + @P_NOMBRE_TABLA + '

'

           

SET @SQL_CABECERA = 'IF EXISTS (SELECT name FROM   sysobjects WHERE  name = N''' +             @P_NOMBRE_PA + '''  AND         type = ''P'')'+CHAR(13) +

            'DROP PROCEDURE ' + @P_NOMBRE_PA + CHAR(13) +

            'GO' + CHAR(13) + CHAR(13) + + CHAR(13) + CHAR(13) +

            'CREATE PROCEDURE '+ @P_NOMBRE_PA + CHAR(13) + '(' + CHAR(13)

 

         La variable @P_NOMBRE_PA la inicializamos con el nombre de la tabla más el prefijo “PA_ABM_”, sólo en caso de que no se haya ingresado un valor al correr el script.

         Una vez inicializadas las variables que vamos a utilizar, comenzamos a armar la información que estas van a contener para luego imprimirla en pantalla.

         Lo que vamos a hacer es usar un cursor para  recorrer la variable @tabla, y vamos a obtener los valores de las columnas “columna”, “parámetro” y “pk”. Además en la variable auxiliar @dato, vamos a armar la declaración de parámetros de la cabecera.

 

DECLARE C_TABLA CURSOR LOCAL FOR

            SELECT

                        '           ' +parametro + '                       ' + tipo_dato +

                        CASE pk

                                   WHEN 0 THEN '= NULL ,'

                                   ELSE ',' END + CHAR(13),

                        columna,

                        parametro,

                        pk

            FROM

                        @tabla

            ORDER BY orden

 

OPEN C_TABLA

 

FETCH NEXT FROM C_TABLA INTO

            @dato,

            @columna,

            @parametro,    

            @pk

           

 

         Por cada registro, si la columna “pk” es igual a 1, es decir, si es clave primaria vamos a armar el WHERE. Caso contrario armamos las columnas a actualizar en la consulta UPDATE. Además, como  podemos ver, vamos hacer uso de la bander @update, asignándole el valor 1 para indicar que hay , al menos una columna que no es clave, por lo tanto se tendrá que escribir la cláusula UPDATE.

         Luego armamos los valores para las variables @SQL_INSERT y @SQL_VALUES.

         Una vez que se terminó de recorrer todo el cursor, lo cerramos y liberamos la memoria.

 

 

WHILE @@FETCH_STATUS = 0

BEGIN

 

            -- SI LA COLUMNA ES CLAVE ARMO EL WHERE

            IF (@pk = 1)

                        SET @SQL_WHERE = @SQL_WHERE + '              ' + @columna + '           =             ' +                                                       @parametro + ' AND ' + CHAR(13)

            ELSE IF (@pk = 0)

                        SELECT @SQL_UPDATE = @SQL_UPDATE + '                  ' + @columna + '            =          ' + @parametro + ',' + CHAR(13)           ,

                        @update=1

 

            SET @SQL_INSERT = @SQL_INSERT + '             ' + @columna + ',' + CHAR(13)

            SET @SQL_VALUES = @SQL_VALUES  + '                       ' + @parametro +',' + CHAR(13)                    

            set @SQL_CABECERA = @SQL_CABECERA + @dato

 

FETCH NEXT FROM C_TABLA INTO

            @dato,

            @columna,

            @parametro,    

            @pk

END

 

CLOSE C_TABLA

DEALLOCATE C_TABLA

 

 

 

1

 

2

 

 

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

         Finalmente, tenemos que limpiar las variables que hemos utilizado, de las impurezas que nos dejó el concatenar los valores de la tabla. Esto depende de la cantidad de espacios y bajadas de línea que se han concatenado.

 

SET @SQL_WHERE = LEFT(@SQL_WHERE,LEN(@SQL_WHERE) -6)

SET @SQL_INSERT = LEFT(@SQL_INSERT,LEN(@SQL_INSERT)-2) + '

)'

SET @SQL_VALUES = LEFT(@SQL_VALUES,LEN(@SQL_VALUES)-2) + '

)'

SET @SQL_UPDATE = LEFT(@SQL_UPDATE,LEN(@SQL_UPDATE)-2)

 

IMPRIMIENDO LAS VARIABLES

 

            ¡Bueno! Por fin hemos llegado al final del script. Luego de dar tantas vueltas, vamos a ver los resultados, que, por lo menos en mi caso, fueron más que beneficiosos.

         Ahora lo único que resta es imprimir las variables en el panel de resultados.

 

PRINT   @SQL_CABECERA + '    @p_accion         CHAR(1) --A = ACTUALIZA (INSERT/UPDATE) , E = ELIMINA

)

AS

 

 

'

PRINT   'IF (@p_accion = ''A'')'

PRINT   'BEGIN -- SI LA ACCION ES ACTUALIZAR'

PRINT   '           IF NOT EXISTS ( '

PRINT   '                       SELECT 1 '

PRINT   '                       FROM '

PRINT   '                                   ' + @P_NOMBRE_TABLA

PRINT ' ' + @SQL_WHERE + '

                                   )'

 

PRINT @SQL_INSERT

PRINT @SQL_VALUES

 

IF @update=1

BEGIN

            PRINT ' ELSE --SI EXISTE HAGO UPDATE

                        '

            PRINT @SQL_UPDATE

            PRINT @SQL_WHERE

END

 

PRINT 'END --TERMINA DE ACTUALIZAR'

PRINT 'ELSE IF @p_accion = ''E''

            '

PRINT @SQL_DELETE

PRINT @SQL_WHERE

PRINT '            

RETURN @@ROWCOUNT '

PRINT 'GO

'

 

 

GO

 

         La disposición de espacios y bajadas de líneas se pueden ir acomodando a lo largo del armado de las variables y de la impresión final.

         Una vez que tengamos todo el script escrito en el Analizador de Consultas, resta elegir sobre que base de datos lo vamos a correr, setear la variable @P_NOMBRE_TABLA y correr el script. En el panel de resultados nos va a aparecer todo el texto del PA, lo copiamos y lo pegamos en una nueva consulta y lo corremos.

        

         Espero que les haya servido este artículo. Yo se que a mi me sirvió mucho el script para ahorrar tiempo en escribir este tipo de PA constantemente. Les adjunto el script completo , el cual pueden abrir con el Analizador de Consultas para usarlo.

 

         Agradezco a Franco Raspo, Matias Toro y Andrés Faya, quienes me motivaron y ayudaron para armar este artículo.

         Cualquier sugerencia que quieran hacer, modificaciones y/o correcciones (espero que las hagan) las pueden enviar a martinluchessi@yahoo.com.ar.

         Sobre las vistas de SQL pueden encontrar más información en:

http://siquelnet.etraducciones.com/default.aspx?Tema=MSSQL&Seccion=SQL&Articulo=005.xml

o en los libros en pantalla de SQL Server 2000.

 

         Hasta la próxima.

 

        

 


Fichero con el código de ejemplo: martinluchessi_Script_generador_codigo_SQL.zip - 2,38 KB


ir al índice