Manual Plpgsql

download Manual Plpgsql

of 34

Transcript of Manual Plpgsql

  • 7/31/2019 Manual Plpgsql

    1/34

    Tabla de contenidos

    1. El Lenguaje Procedimental SQL - PL/pgSQL ............................................................... 1

    Visin General............................................................................................................... 1Ventajas del Uso de PL/pgSQL .......................................................................... 2Argumentos y Tipos de Datos de los Resultados Soportados ..................... 2

    Sugerencias para Desarrollar en PL/pgSQL .............................................................. 3Manejo de las Comillas ...................................................................................... 3

    La Estructura de PL/pgSQL ......................................................................................... 5Declaraciones ................................................................................................................ 6

    Aliases para los Parmetros de las Funciones ................................................ 7Copiando Tipos................................................................................................... 8Tipos Rengln...................................................................................................... 8Tipos Registro...................................................................................................... 9RENAME .................................................................................................................. 9

    Expresiones ................................................................................................................. 10Sentencias Bsicas ...................................................................................................... 11

    Asignacin ......................................................................................................... 11SELECT INTO .................................................................................................. 11Ejecucin de una Expresin o Consulta Sin Resultados ............................. 12No Hacer Absolutamente Nada ..................................................................... 13Ejecucin de Comandos Dinmicos............................................................... 13Obteniendo el Estado del Resultado.............................................................. 15

    Estructuras de Control............................................................................................... 15Regreso de una Funcin .................................................................................. 16Condicionales.................................................................................................... 17Ciclos Simples ................................................................................................... 19Ciclos a Travs de Resultados de Consultas ................................................. 20Atrapar los Errores ........................................................................................... 21

    Cursores....................................................................................................................... 22Declaracin de las Variables de Cursores ..................................................... 23Apertura de Cursores....................................................................................... 23Uso de los Cursores .......................................................................................... 24

    Errores y Mensajes ..................................................................................................... 27

    Procedimientos Desencadenantes o Disparadores (Triggers) ............................. 27

    i

  • 7/31/2019 Manual Plpgsql

    2/34

    ii

  • 7/31/2019 Manual Plpgsql

    3/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Nota: Este documento fue traducido y adaptado por Roberto Andrade Fonseca ([email protected]), tomando como base el captulo llamado PL/pgSQL - SQLProcedural Language de la documentacin de PostgreSQL, versin 8.04, en octubre de2005. Esta es una versin reducida del captulo mencionado.

    PL/pgSQL es un lenguaje procedimental cargable para el sistema de base de datosPostgreSQL. Los objetivos propuestos para PL/pgSQL consisten en crear un lenguajeprocedimental cargable que

    pueda ser usado para crear funciones y procedimientos disparadores,

    adicione estructuras de control al lenguaje SQL,

    sea capaz de realizar clculos complejos,

    herede todos los tipos, las funciones y los operadores definidos por el usuario,

    pueda ser definido como confiable (trusted) por el servidor,

    sea fcil de usar.

    Excepto por las conversiones de entrada/salida y las funciones de clculo para lostipos definidos por el usuario, todo lo que puede definirse por medio de funcionesen el lenguaje C puede definirse tambin con PL/pgSQL. Por ejemplo, es posible crearfunciones computacionales condicionales complejas que pueden ser usadas posteri-ormente para definir operadores o usarlas en expresiones asociadas a los ndices.

    Visin General

    El manejador de llamadas de PL/pgSQL analiza sintcticamente el texto del cdigofuente de la funcin y produce un rbol de instrucciones binario interno la primeravez que se llama una funcin (dentro de cada sesin). El rbol de instrucciones tra-duce completamente la estructura de los comandos PL/pgSQL, pero las expresionesindividuales SQL y los comandos SQL usados en las funciones no son traducidas deinmediato.

    Cada vez que es usado por primera vez un comando SQL en la funcin el intrpretePL/pgSQL crea un plan preparado de ejecucin (usando las funciones SPI_preparey SPI_saveplan del administrador SPI). Las visitas subsecuentes a esa expresin ocomando reutilizan el plan preparado. As, una funcin con cdigo condicional quecontiene varias sentencias para las cuales se requiere del plan de ejecucin, solamentepreparar y guardar aquellos planes que realmente sean usados durante el ciclo devida de la conexin de la base de datos. Esto puede reducir de manera importanteel tiempo total requerido para revisar y generar los planes de ejecucin para las sen-

    tencias en una funcin de PL/pgSQL. Una desventaja es que aquellos errores de uncomando o expresin especfica pueden no ser detectados hasta que esa parte de lafuncin sea alcanzada en la ejecucin.

    Una vez que PL/pgSQL haya generado un plan de ejecucin para un comando partic-ular en una funcin, ste ser reutilizado durante el ciclo de vida de la conexin dela base de datos. Generalmente esto es una ventaja para el desempeo, pero puedecausar algunos problemas si se modifica dinmicamente el esquema de la base dedatos. Por ejemplo:

    CREATE FUNCTION populate() RETURNS integer AS $$DECLARE

    1

  • 7/31/2019 Manual Plpgsql

    4/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    -- declaracionesBEGIN

    PERFORM my_function();END;$$ LANGUAGE plpgsql;

    Si ejecuta la funcin anterior, sta har referencia al OID de my_function() en el plan

    de ejecucin generado para el comando PERFORM. Ms tarde, si elimina (drop) yrecrea my_function(), entonces populate() no podr encontrar de ninguna man-era my_function(). Tendra que recrear populate(), o al menos iniciar una nuevasesin de la base de datos para que se recompile nuestra funcin. Otra manera deevitar este problema es usar CREATE OR REPLACE FUNCTION cuando se actual-ice la definicin de my_function (cuando una funcin es reemplazada, su OID nosufre cambios).

    Debido a que PL/pgSQL guarda los planes de ejecucin de esta manera, los comandosSQL que aparecen directamente en una funcin PL/pgSQL deben referirse a las mis-mas tablas y columnas en cada ejecucin; es decir, usted no puede usar un parmetrocomo el nombre de una tabla o una columna en un comando SQL. Para darle lavuelta a esta restriccin, puede construir comandos dinmicos usando la sentenciaEXECUTE de PL/pgSQL pagando el precio de generar un nuevo plan de ejecucinen cada ejecucin.

    Nota: La sentencia EXECUTE de PL/pgSQL no est relacionada con el comando SQLque es soportado por el servidor PostgreSQL. La sentencia EXECUTE del servidor nopuede usarse dentro de las funciones PL/pgSQL (y no es necesaria).

    Ventajas del Uso de PL/pgSQL

    SQL es el lenguaje que PostgreSQL y la mayora de la bases de datos relacionalesusan como lenguaje de consulta. Es portable y fcil de aprender. Pero cada sentenciaSQL debe ser ejecutada individualmente por el servidor de la base de datos.

    Esto significa que su aplicacin cliente debe enviar cada consulta al servidor de la

    base de datos, esperar a que sea procesada, recibir los resultados, hacer algunos cl-culos, y enviar despus otras consultas al servidor. Todo esto implica la comunicacinentre procesos y puede tambin implicar una sobrecarga a la red si su cliente se en-cuentra en una mquina diferente a la del servidor de la base de datos.

    Con PL/pgSQL usted puede agrupar un bloque de clculos y una serie de consultasdentro del servidor de la base de datos, obteniendo de esta manera el poder de unlenguaje procedimental y la facilidad de uso de SQL, pero ahorrando una gran can-tidad de tiempo debido a que no tiene la sobrecarga de la comunicacin completacliente/servidor. Esto puede aumentar el desempeo de una manera considerable.

    Tambin, con PL/pgSQL usted puede usar todos los tipos de datos, operadores y fun-ciones de SQL.

    Argumentos y Tipos de Datos de los Resultados Soportados

    Las funciones escritas en PL/pgSQL pueden aceptar como argumentos cualquier tipode datos escalar o matriz soportados por el servidor, y pueden regresar un resul-tado de cualquiera de esos tipos. Tambien pueden aceptar o regresar cualquier tipocompuesto (tipo rengln, row type) especificado por su nombre. Tambin es posibledeclarar una funcin de PL/pgSQL que regrese un registro (record), lo cual significaque el resultado es del tipo rengln, cuyas columnas son definidas por la especifi-cacin de la llamada a la consulta.

    Las funciones PL/pgSQL tambin pueden declararse para que acepten y regresen lostipos polimrficos anyelement y anyarray. Los tipo de datos actuales manejados por

    2

  • 7/31/2019 Manual Plpgsql

    5/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    una funcin polimrfica pueden variar de llamada en llamada. En la seccin de nom-bre Aliases para los Parmetros de las Funciones se muestra un ejemplo.

    Las funciones PL/pgSQL tambin pueden declararse para que regresen un conjunto(set), o tabla, de cualquier tipo de datos del cual puedan regresar una sola instancia.Tal funcin genera su salida ejecutando RETURN NEXT para cada elemento deseadodel conjunto de resultados.

    Finalmente, una funcin PL/pgSQL puede ser declarada para que regrese void siacaso no se utiliza el valor de retorno.

    PL/pgSQL no tiene actualmente el soporte completo para tipos dominio: trata un do-minio de la misma manera que el tipo escalar subyacente. Esto significa que las re-stricciones asociadas con el dominio no sern forzadas. Esto no es un problema paralos argumentos de las funciones, pero es un peligro si usted declara una funcinPL/pgSQL que devuelva un tipo dominio.

    Sugerencias para Desarrollar en PL/pgSQL

    Una buena manera de programar en PL/pgSQL es utilizar su editor de textos favorito

    para crear sus funciones y, en otra ventana, usar psql para cargar y probar esas fun-ciones. Si lo hace de esta manera, es una buena idea escribir la funcin usando CRE-ATE OR REPLACE FUNCTION. De esta manera usted puede recargar el archivopara actualizar la definicin de la funcin. Por ejemplo:

    CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $$....

    $$ LANGUAGE plpgsql;

    Desde psql usted puede cargar o recargar la definicin de la funcin con

    \i nombrearchivo.sql

    e inmediatamente teclear los comandos SQL necesarios para probar la funcin.Otra manera adecuada de programar en PL/pgSQL es por medio de una herramientaGUI de acceso a la base de datos, que le facilite el desarrollo de un lenguaje pro-cedimental. Un ejemplo es PgAccess, aunque existen otras. Estas herramientas sue-len ofrecer prestaciones convenientes para escapar las comillas sencillas y facilitar larecreacin y depuracin de las funciones.

    Manejo de las Comillas

    El cdigo de una funcin PL/pgSQL se especifica en CREATE FUNCTION como unacadena literal. Si usted escribe la cadena literal de la manera comn, con comillassencillas como delimitadores, entonces cada comilla sencilla dentro del cuerpo dela funcin debe ser duplicada; de igual manera cualquier diagonal inversa debe ser

    duplicada. La duplicacin de las comillas es, por lo menos, tedioso, y en los casoscomplejos el cdigo se vuelve incomprensible, debido a que se pueden necesitar me-dia docena o ms de comillas sencillas contiguas. Es recomendable que mejor escribael cuerpo de la funcin como una cadena literal dollar-quoted. Con el estilo dollar-quoting usted nunca necesitar duplicar las comillas, en cambio deber cuidar el usode un delimitador dollar-quoting diferente para cada nivel de anidamiento que nece-site. Por ejemplo, usted debe escribir el comando CREATE FUNCTION como

    CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $PROC$....

    $PROC$ LANGUAGE plpgsql;

    3

  • 7/31/2019 Manual Plpgsql

    6/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Dentro de ste, usted puede usar comillas para las cadenas literales simples en loscomandos SQL y $$ para delimitar fragmentos de comandos SQL que est ensam-

    blando para crear cadenas ms largas. Si necesita incluir en su texto $$, puede usar$Q$ y as consecutivamente.

    La siguiente tabla le muestra lo que debe hacer cuando escriba comillas sin delimitarsu cadena con $$. Puede serle til cuando traduzca sus funciones hechas con cdigo

    en el que no se usaba $$ y para hacer ms claro el cdigo.

    1 comilla

    Para iniciar y finalizar el cuerpo de la funcin, por ejemplo:

    CREATE FUNCTION foo() RETURNS integer AS ....

    LANGUAGE plpgsql;

    En cualquier lugar dentro del cuerpo de la funcin delimitada por una comilla,las comillas deben aparecer en pares.

    2 comillas

    Para cadenas literales dentro del cuerpo de la funcin, por ejemplo:

    a_output := Blah;SELECT * FROM users WHERE f_name=foobar;

    Usando la tcnica de $$, usted debera escribir

    a_output := Blah;SELECT * FROM users WHERE f_name=foobar;

    que es exactamente lo que el analizador de PL/pgSQL vera en ambos casos.

    4 comillas

    Cuando requiera una comilla sencilla en una cadena constante dentro del cuerpode la funcin, por ejemplo;

    a_output := a_output || AND name LIKE foobar AND xyz

    El valor realmente concatenado a a_output sera: AND name LIKE foobarAND xyz.

    Usando la tcnica de $$, usted escribira

    a_output := a_output || $$ AND name LIKE foobar AND xyz$$

    teniendo cuidado de que cualquiera de los delimitadores estilo dlar alrededorde esta cadena no sea ciertamente $$.

    6 comillas

    Cuando una comillas sencilla en una cadena dentro del cuerpo de la funcin seaadyacente al final de la cadena constante, por ejemplo:

    a_output := a_output || AND name LIKE foobar

    El valor concatenado a a_output sera entonces: AND name LIKE foobar.

    Con el estilo dlar se transformara en:

    a_output := a_output || $$ AND name LIKE foobar$$

    4

  • 7/31/2019 Manual Plpgsql

    7/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    10 comillas

    Cuando requiera dos comillas sencillas en una cadena constante (que equivalen a8 comillas)y sta es adyacente al final de la cadena constante (2 ms). Es probableque solamente necesite esto si est escribiendo una funcin que genera otrasfunciones. Por ejemplo:

    a_output := a_output || if v_ ||

    referrer_keys.kind || like || referrer_keys.key_string || then return || referrer_keys.referrer_type|| ; end if;;

    El valor de a_output sera entonces:

    if v_... like ... then return ...; end if;

    Con el estilo dlar quedara como

    a_output := a_output || $$ if v_$$ || referrer_keys.kind ||$$ like $$ || referrer_keys.key_string || $$

    then return $$ || referrer_keys.referrer_type|| $$; end if;$$;

    en donde suponemos que solamente requerimos colocar una comilla dentro de

    a_output debido a que ser re-encomillado antes de usarse.

    Una variante es el escapar las comillas en el cuerpo de la funcin con una diagonalinvertida en lugar de duplicarlas. Con este mtodo escribira cosas como \\ enlugar de . Algunas personas consideran esta tcnica ms sencilla, pero otras no.

    La Estructura de PL/pgSQL

    PL/pgSQL es un lenguaje estructurado a base de bloques. El texto completo de ladefinicin de una funcin debe ser un bloque. Un bloque est definido como:

    [ ][ DECLARE

    declaraciones ]BEGIN

    sentencias

    END;

    Cada declaracin y cada sentencia dentro de un bloque deben terminar con puntoy coma. Un bloque que aparece dentro de otro bloque debe contar con un punto ycoma despus de END, como se muestra abajo; sin embargo, el END final que cierra elcuerpo de una funcin no requiere el punto y coma.

    Todas la palabras reservadas y los identificadores pueden escribirse en maysculas,

    minsculas o una mezcla de ellas. Los identificadores son convertidos implicitamentea minsculas, a menos que estn encerradas en comillas dobles.

    Existen dos tipos de comentarios en PL/pgSQL. Un doble guin (--) marca el iniciode un comentario que se extiende hasta el final de la lnea. Los smbolos /* marcanel inicio de un bloque de un comentario que se extiende hasta la aparicin de /*. Los

    bloques de comentarios no pueden anidarse, pero los comentarios con doble guinpueden ocultar los delimitadores de un bloque de un comentario /* y */.

    Cualquier sentencia en la seccin de sentencias de un bloque puede ser un subbloque.Los subbloques pueden usarse para agrupamientos lgicos o para hacer locales lasvariables de un grupo de sentencias.

    5

  • 7/31/2019 Manual Plpgsql

    8/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Las variables declaradas en la seccin de declaraciones que precede a un bloque soninicializadas a su valor por omisin cada vez que se entra al bloque, no solamenteuna vez por llamada a la funcin. Por ejemplo:

    CREATE FUNCTION somefunc() RETURNS integer AS $$DECLARE

    quantity integer := 30;

    BEGINRAISE NOTICE Aqu, cantidad tiene el valor de %, quantity;-- Aqu, cantidad tiene el valor de 30

    quantity := 50;---- Creamos un subbloque--DECLARE

    quantity integer := 80;BEGIN

    RAISE NOTICE Aqu, cantidad tiene el valor de %, quantity;-- Aqu, cantidad tiene el valor de 80

    END;

    RAISE NOTICE Aqu, cantidad tiene el valor de %, quantity;-- Aqu, cantidad tiene el valor de 50

    RETURN quantity;END;$$ LANGUAGE plpgsql;

    Es importante no confundir el uso de BEGIN/END para agrupar sentencias enPL/pgSQL con los comandos de la base de datos para el control de las transacciones.Los comandos BEGIN/END de PL/pgSQL se usan solamente para agrupar;no inician ni terminan una transaccin. Las funciones y los procedimientosdisparadores (trigger) siempre son ejecutados dentro de una transaccin establecidapor una consulta externa no pueden iniciar o hacer que se ejecute un commit deesa transaccin, puesto que no existe un contexto para su ejecucin. Sin embargo, un

    bloque que contenga una clasula de EXCEPTION s genera una subtransaccinque puede echarse atrs (rolled back) sin afectar la transaccin externa. Para msdetalles puede ver la seccin de nombre Atrapar los Errores.

    Declaraciones

    Todas las variables usadas en un bloque deben ser declaradas en la seccin dedeclaraciones de ese bloque. (La nica excepcin es que la variable ndice de unciclo FOR que itera sobre un rango de valores enteros es declarada automticamentecomo una variable entera).

    Las variables de PL/pgSQL pueden tener cualquier tipo de dato de SQL, tales comointeger, varchar y char.

    Estos son algunos ejemplos de la declaracin de variables:

    user_id integer;cantidad numeric(5);url varchar;myrenglon nombretabla%ROWTYPE;mycampo nombretabla.nombrecolumna%TYPE;unrenglon RECORD;

    La sintaxis general de la declaracin de una variable es:

    6

  • 7/31/2019 Manual Plpgsql

    9/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    nombre [ CONSTANT ] tipo [ NOT NULL ] [ { DEFAULT | := } expresin ];

    La clusula DEFAULT, cuando existe, especifica el valor inicial asignado a la variablecuando se ingresa al bloque. Si la clasula DEFAULT no existe entonces la variablese inicializa al valor nulo de SQL. Si se especifica NOT NULL, la asignacin de unvalor nulo dar por resultado un error en tiempo de ejecucin. Todas las variabledeclaradas como NOT NULL deben tener especificado un valor no nulo.

    El valor por omisin se evala cada vez que se entra al bloque. As, por ejemplo, elasignar now() a la variable de tipo timestamp causar que esa variable tenga la horade la llamada a la funcin actual, no la hora en que la funcin fue precompilada.

    Ejemplos:

    cantidad integer DEFAULT 32;url varchar := http://misitio.com;user_id CONSTANT integer := 10;

    Aliases para los Parmetros de las Funciones

    Los parmetros pasados a las funciones se nombran con los identificadores $1, $2,etc. Opcionalmente, se pueden declarar aliases para $n nombres de parmetros parauna mayor claridad. Tanto el alias como su identificador numrico pueden ser usadospara referirse al valor del parmetro.

    Existen dos maneras de crear un alias. La manera preferida es asignarle un nombreal parmetro en el comando CREATE FUNCTION, por ejemplo:

    CREATE FUNCTION impuesto_ventas(subtotal real) RETURNS real AS $$BEGIN

    RETURN subtotal * 0.06;END;$$ LANGUAGE plpgsql;

    La otra manera, que era la nica disponible para versiones previas a PostgreSQL 8.0,

    es el declarar explcitamente un alias, usando la sintaxis de declaracin

    nombre ALIAS FOR $n;

    El mismo ejemplo en este estilo se vera as

    CREATE FUNCTION impuesto_ventas(real) RETURNS real AS $$DECLARE

    subtotal ALIAS FOR $1;BEGIN

    RETURN subtotal * 0.06;END;$$ LANGUAGE plpgsql;

    Algunos ejemplos ms:

    CREATE FUNCTION instr(varchar, integer) RETURNS integer AS $$DECLARE

    v_string ALIAS FOR $1;index ALIAS FOR $2;

    BEGIN-- Algn procesamiento aqu

    END;$$ LANGUAGE plpgsql;

    CREATE FUNCTION concatenar_campos_seleccionados(in_t nombretabla)

    7

  • 7/31/2019 Manual Plpgsql

    10/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    RETURNS text AS $$BEGIN

    RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;END;$$ LANGUAGE plpgsql;

    Cuando el tipo regresado de una funcin PL/pgSQL se declara como de tipo polimr-fico (anyelement o anyarray), se crea un parmetro especial $0. Su tipo de dato es eltipo de dato actual regresado por la funcin, el cual deduce de los tipos de entradaactuales. Esto permite a la funcin acceder a su tipo de retorno actual como se mues-tra en la seccin de nombre Copiando Tipos. La variable $0 se inicializa a nulo y puedeser modificada por la funcin, de tal manera que pueda ser usada para almacenar elvalor de retorno si eso es lo que se desea, aunque esto no es necesario. A la variable$0 tambin se le puede dar un alias. Por ejemplo, esta funcin trabaja con cualquiertipo de dato que tenga un operador +:

    CREATE FUNCTION suma_tres_valores(v1 anyelement,v2 anyelement,v3 anyelement)

    RETURNS anyelement AS $$DECLARE

    resultado ALIAS FOR $0;BEGIN

    resultado := v1 + v2 + v3;RETURN resultado;

    END;$$ LANGUAGE plpgsql;

    Copiando Tipos

    variable%TYPE

    %TYPE proporciona el tipo de dato de una variable o de una columna de una tabla.Puede utilizarla para declarar variables que almacenarn valores de la base dedatos. Por ejemplo, supongamos que tiene una columna llamada id_usuario ensu tabla usuarios. Para declarar una variable con el mismo tipo de dato queusuarios.id_usuario usted escribira:

    id_usuario usuarios.id_usuario%TYPE;

    Al usar %TYPE no necesita conocer el tipo de dato de la estructura a la que est ha-ciendo referencia, y lo ms importante, si el tipo de dato del tem referido cambia enalgn momento en el futuro (por ejemplo: si cambia el tipo de id_usuario de integera real), usted no necesita cambiar la definicin en su funcin.

    %TYPE es particularmente til en las funciones polimrficas, puesto que los tipos dedatos necesarios para las variables internas puede cambiar de una llamada a otra.Se pueden crear variables apropiadas aplicando %TYPE a los argumentos o a los co-modines de los resultados de la funcin.

    Tipos Rengln

    nombre nombre_tabla%ROWTYPE;nombre nombre_tipo_compuesto;

    8

  • 7/31/2019 Manual Plpgsql

    11/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Una variable de un tipo compuesto se denomina una variable rengln (o tipo-renglon).Dicha variable puede almacenar un rengln completo resultado de una consulta SE-LECT o FOR, en tanto el conjunto de columnas de la consulta coincida con el tipo dela variable declarado. Los campos individuales del valor del rengln pueden acced-erse usando la notacin usual de punto, por ejemplo renglonvar.campo.

    Una variable rengln puede declararse para tener el mismo tipo que los renglones

    de una tabla o vista existente, usando la notacin nombre_tabla%ROWTYPE; o puedeser declarada dando el nombre de un tipo compuesto. (Puesto que todas las tablastiene un tipo compuesto asociado del mismo nombre, en PostgreSQL realmente noimporta si escribe %ROWTYPE o no. Pero la forma con %ROWTYPE es ms portable).

    Los parmetros de una funcin pueden ser de tipo compuesto (renglones de tablascompletos). En ese caso, el identificador correspondiente $n ser un variable rengln,y pueden seleccionarse los campos a partir de l, por ejemplo $1.id_usuario.

    En una variable tipo-rengln, solamente son accesibles las columnas definidas porel usuario, no el OID u otras columnas del sistema (debido a que el rengln podraser de una vista). Los campos del tipo rengln heredan el tamao o la precisin delcampo de la tabla para datos tales como char(n).

    Este es un ejemplo del uso de los tipos compuestos:

    CREATE FUNCTION merge_fields(t_row tablename) RETURNS text AS $$DECLARE

    t2_row table2name%ROWTYPE;BEGIN

    SELECT * INTO t2_row FROM table2name WHERE ... ;RETURN t_row.f1 || t2_row.f3 || t_row.f5 || t2_row.f7;

    END;$$ LANGUAGE plpgsql;

    SELECT merge_fields(t.*) FROM tablename t WHERE ... ;

    Tipos Registronombre RECORD;

    Las variables registro son similares a las variables tipo-rengln, pero no tienen unaestructura predefinida. Toman la estructura actual del rengln al que son asigna-dos durante un comando SELECT o FOR. La subestructura de una variable registropuede cambiar cada vez que es asignada. Una consecuencia de sto es que mientrasuna variable registro no sea asignada por primera vez, no tendr subestructura ycualquier intento de acceder a uno de sus campos generar un error en tiempo deejecucin.

    Observe que RECORD no es realmente un tipo de dato, sino un comodn. Tambindebe darse cuenta que cuando una funcin PL/pgSQL se declara para regresar untipo record, no es lo mismo que una variable registro, aunque tal variable pueda uti-

    lizar una variable registro para almacenar su resultado. En ambos casos la estructuraactual del rengln es desconocida cuando se escribe la funcin, pero para una funcinque regresa un record la estructura actual se determina cuando se analiza la consultasolicitada, mientras que una variable record puede cambiar su estructura de renglnal vuelo.

    RENAME

    RENAME nombreviejo TO nombrenuevo;

    9

  • 7/31/2019 Manual Plpgsql

    12/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    La declaracin RENAME le permite cambiar el nombre de una variable, registro orengln. Inicialmente es til si NEW u OLD deben ser referidas con otro nombre dentrode un procedimiento disparador. Vea tambin ALIAS.

    Ejemplos:

    RENAME id TO id_usuario;RENAME this_var TO esta_variable;

    Nota: RENAME parece no funcionar desde PostgreSQL 7.3. La reparacin es de baja pri-oridad puesto que ALIAS cubre la mayor parte de los usos prcticos de RENAME.

    Expresiones

    Todas las expresiones usadas en sentencias de PL/pgSQL son procesadas usando el

    ejecutor SQL regular del servidor. De hecho, una consulta comoSELECT expresin

    se ejecuta usando al administrador SPI. Antes de la evaluacin, las ocurrencias delos identificadores de variables de PL/pgSQL son reemplazados por los parmetros yel valor actual de las variables se pasa al ejecutor en el arreglo de parmetros. Estopermite que el plan de la consulta del SELECT sea preparado solamente una vez ydespus reutilizado para las evaluaciones subsecuentes.

    La evaluacin hecha por el analizador (parser) pricipal de PostgreSQL tiene algunosefectos secundarios en la interpretacin de los valores constantes. En detalle existendiferencias entre lo que hacen estas dos funciones:

    CREATE FUNCTION logfunc1(logtxt text) RETURNS timestamp AS $$

    BEGININSERT INTO logtable VALUES (logtxt, now);RETURN now;

    END;$$ LANGUAGE plpgsql;

    y

    CREATE FUNCTION logfunc2(logtxt text) RETURNS timestamp AS $$DECLARE

    curtime timestamp;BEGIN

    curtime := now;INSERT INTO logtable VALUES (logtxt, curtime);RETURN curtime;

    END;

    $$ LANGUAGE plpgsql;

    Enen casode logfunc1, el analizador principal de PostgreSQL sabe cuando prepararel plan para el INSERT, que la cadena now debe interpretarse como timestamp de-

    bido a que su columna objetivo de logtable es de ese tipo. Asi, crear una constantecon ella en este momento y su valor constante ser utilizado en todas las invocacionesde logfunc1 durante la vida de la sesin. No es necesario decir que esto no es lo queel programador deseaba hacer.

    10

  • 7/31/2019 Manual Plpgsql

    13/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    En el caso de logfunc2, el analizador principal de PostgreSQL no sabe que tipodebe tener now y entonces regresa un valor de tipo text que contiene la cadenanow. Durante la asignacin subsiguiente a la variable local curtime, el intrpretede PL/pgSQL transforma esta cadena al tipo timestamp llamando a las funcionestext_out y timestamp_in para la conversin. As, la hora y la fecha calculadas encada ejecucin es la que espera el programador.

    La naturaleza mutable de las variables registro presentan un problema en este m-bito. Cuando los campos de una variable registro son usados en expresiones o senten-cias, los tipos de datos de los campos no deben cambiar entre llamadas de una mismaexpresin, puesto que la expresin ser planeada usando los tipos de dato que estnpresentes cuando la expresin sea alcanzada por primera vez. Tenga en cuenta estoal escribir procedimientos disparadores que manejen eventos para ms de una tabla.(Cuando se necesario, puede utilizar EXECUTE para evitar este problema).

    Sentencias Bsicas

    En esta seccin y las siguientes describimos todos los tipos de sentencias que entiendeexplicitamente PL/pgSQL. Cualquier cosa que no sea reconocida como una de estostipos de sentencias se presume que es un comando SQL y se enva a la mquina

    de la base de datos principal para ejecutarse (despus de la sustitucin de cualquiervariable de PL/pgSQL usada en la sentencia). As, por ejemplo, los comandos SQLINSERT, UPDATE y DELETE pueden considerarse como sentencias de PL/pgSQL,pero no se listan aqu especficamente.

    Asignacin

    Una asignacin de una valor a una variable o campo de un rengln/registro se es-cribe como:

    identificador := expresin;

    Tal como se escribi arriba, la expresin en tal sentencia es evaluada por medio deun comando SQL SELECT enviado a la mquina de la base de datos principal. Laexpresin debe producir un valor nico.

    Si el tipo de dato del resultado de la expresin no coincide con el tipo de dato de lavariable, o la variable tiene un tamao/precisin especfico (como char(20)), el valorresultante ser convertido implcitamente por el intrprete de PL/pgSQL usando eltipo de resultado de la funcin de salida (output_function) y el tipo de variable de lafuncin de entrada (input_function). Observe que esto puede resultar potencialmenteen un error en tiempo de ejecucin generado por la funcin de entrada, si la formade la cadena del valor resultante no es aceptable para la funcin de entrada.

    Ejemplos:

    id_usuario := 20;impuesto := subtotal * 0.15;

    SELECT INTO

    El resultado de un comando SELECT que produce columnas mltiples (pero slo unrengln) puede ser asignado a una variable registro, variable tipo-rengln o una listade variables escalares. Esto se realiza con:

    SELECT INTO meta expresiones_select FROM ...;

    11

  • 7/31/2019 Manual Plpgsql

    14/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    en donde meta puede ser una variable registro, una variable rengln o una listade variables simples y campos registro/rengln separados por comas. Lasexpresiones_select y el resto del comando son iguales que en el SQL regular.

    Observe que es muy diferente de la interpretacin normal de SELECT INTO de Post-greSQL, en donde la meta INTO es una tabla recin creada. Si desea crear una tablaa partir de una resultado de un SELECT dentro de una funcin PL/pgSQL, use la

    sintaxis CREATE TABLE ... AS SELECT.Si un rengln o una lista de variables se usa como meta, los valores seleccionadosdeben coincidir exactamente con la estructura de la meta, u ocurrir un error entiempo de ejecucin. Cuando la meta es una variable registro, automticamente seconfigura siguiendo la estructura del tipo rengln de la columnas del resultado de laconsulta.

    Las sentencia SELECT es la misma que el comando SELECT normal y puede uti-lizarse con todo su poder, con la excepcin de la clasula INTO.

    La clasula INTO puede aparecer casi en cualquier lugar en la sentencia SELECT.Suele escribirse ya sea antes de SELECT como se muestra arriba o justo antes de FROM es decir, justo antes o justo despus de la lista de las expresiones_select.

    Si la consulta regresa cero renglones, se asignan valores nulos a la(s) meta(s). Si la

    consulta regresa mltiples renglones, se asigna el primer rengln a la(s) meta(s) y elresto se descarta. (Observe que el primer rengln no est bien definido a menosque haga uso de ORDER BY).

    Puede verificar la variable especial FOUND (vea la seccin de nombre Obteniendo elEstado del Resultado) despus de una sentencia SELECT INTO para determinar si laasignacin fue correcta, es decir, que la consulta regres al menos un rengln. Porejemplo:

    SELECT INTO mireg * FROM emp WHERE empnombre= minombre;IF NOT FOUND THEN

    RAISE EXCEPTION no se encontr al empleado %, minombre;END IF;

    Para probar si un resultado registro/rengln es nulo puede usar la condicional ISNULL. Sin embargo, no existe una manera de decir si han sido descartados algunosrenglones adicionales. Aqu hay un ejemplo que maneja el caso en que no se hanregresado renglones:

    DECLAREreg_usuarios RECORD;

    BEGINSELECT INTO reg_usuarios * FROM usuarios WHERE id_usuario=3;

    IF reg_usuarios.homepage IS NULL THEN-- El usuario no digit un homepage, regresar "http://"RETURN http://;

    END IF;END;

    Ejecucin de una Expresin o Consulta Sin Resultados

    En algunas ocasiones se desea evaluar un expresin o una consulta y descartar susresultados (tpicamente debido a que se est llamando a una funcin que tiene efectos

    12

  • 7/31/2019 Manual Plpgsql

    15/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    secundarios tiles, pero valores de resultados intiles). Para hacer esto en PL/pgSQLutilice la sentencia PERFORM:

    PERFORM consulta;

    Esto ejecuta la consulta y descarta el resultado. Escriba la consulta de la mismamanera en que lo hara en un comando SELECT, pero reemplace la palabra reservada

    inicial SELECT con PERFORM. Las variables PL/pgSQL sern sustitudas dentro dela consulta de la manera usual. Tambin a la variable especial FOUND se le asignar elvalor de verdadero si la consulta produce al menos un rengln o falso si no producerenglones.

    Nota: Uno esperara que un SELECT sin una clasula INTO hara lo mismo, pero hastael momento la nica manera aceptada de hacerlo es con PERFORM.

    Un ejemplo:

    PERFORM create_mv(cs_session_page_requests_mv, my_query);

    No Hacer Absolutamente Nada

    Algunas veces una sentencia comodn que no hace nada es til. Por ejemplo, puedeindicar que una rama del una cadena if/then/else se encuentra vaca deliberada-mente. Para hacer esto, use la sentencia NULL:

    NULL;

    Por ejemplo, los siguientes dos fragmentos de cdigo son equivalentes:

    BEGINy : = x / 0 ;EXCEPTION

    WHEN division_by_zero THENNULL; -- ignore el error

    END;

    BEGINy : = x / 0 ;

    EXCEPTIONWHEN division_by_zero THEN -- ignore el error

    END;

    Dejamos a su eleccin el que quiera usar.

    Nota: En el PL/SQL de Oracle las sentencias vacias no estn permitidas, as que lassentencias NULL son requeridas para situaciones como sas. PL/pgSQL permite, encambio, el escribir nada.

    13

  • 7/31/2019 Manual Plpgsql

    16/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Ejecucin de Comandos Dinmicos

    Con frecuencia tendr necesidad de generar comandos dinmicos dentro de sus fun-ciones PL/pgSQL, esto es, comandos que involucren diferentes tablas o diferentestipos, cada vez que son ejecutados. Los intentos normales de PL/pgSQL para guardarlos planes para los comandos no trabajarn es tales escenarios. Para manejar esa clasede problemas se proporcion el comando EXECUTE:

    EXECUTE cadena-de-comando;

    En donde cadena-de-comando es una expresin que da como resultado una ca-dena (de tipo text), la cual contiene el comando a ser ejecutado. Esta cadena se ali-menta, literalmente, a la mquina SQL.

    Observe en particular que no se realiza ninguna sustitucin de variables PL/pgSQL enla cadena de comando. Los valores de las variables deben ser insertados en la cadenade comando al momento de construirse.

    A diferencia de otros comandos en PL/pgSQL, un comando ejecutado por una sen-tencia EXECUTE no se prepara y guarda slo una vez durante la vida de la sesin.En cambio, el comando se prepara cada vez que se ejecuta la sentencia. La cadena decomando puede se creada dinmicamente dentro de la funcin para ejecutar acciones

    en diferentes tablas y columnas.Los resultados de un SELECT son descartados por el comando EXECUTE y el SE-LECT INTO no est soportado actualmente dentro de EXECUTE. As que no haymanera de extraer un resultado de un SELECT creado dinmicamente usando elcomando EXECUTE simple. Sin embargo, existen otras maneras de hacerlo: una im-plica el usar la forma del ciclo FOR-IN-EXECUTE descrita en la seccin de nombreCiclos a Travs de Resultados de Consultas, y la otra es utilizar un cursor con OPEN-FOR-EXECUTE, como se describe en la seccin de nombre Apertura de Cursores.

    Cuando trabaje con comandos dinmicos tendr que contender frecuentemente conel escape de las comillas sencillas. El mtodo recomendado para entrecomillar textofijo en el cuerpo de su funcin es el entrecomillar con el signo de dlares. (Si tienecdigo heredado que no use el entrecomillado con el signo de dlares, refirase ala visin general en la seccin de nombre Manejo de las Comillas, la cual de ahorrar

    algunos esfuerzos al traducir dicho cdigo a un esquema ms razonable).Los valores dinmicos que se van a insertar dentro de la consulta construda re-quieren un manejo especial, puesto que ellos mismos pueden contener comillas. Unejemplo (presupone que usted est usando entrecomillado con el signo de dlarespara toda la funcin, de tal manera que las comillas no necesitan ser dobles):

    EXECUTE UPDATE tbl SET || quote_ident(nombrecol)|| = || quote_literal(nuevovalor)|| WHERE llave= || quote_literal(llavevalor);

    Este ejemplo ilustra el uso de las funciones quote_ident(text) yquote_literal(text). Por seguridad, las variables que contienen valoresque deben ser cadenas literales en el comando construdo deben pasarse aquote_literal. Ambas siguen los pasos apropiados para regresar el texto deentrada encerrado en comillas sencillas o dobles respectivamente, con cualquiercaracter especial embebido escapado de la manera correcta.

    Observe que el entrecomillado con el smbolo de dlares es til solamente para en-trecomillar texto fijo. Sera muy mala idea el tratar de hacer el ejemplo anterior como

    EXECUTE UPDATE tbl SET || quote_ident(nombrecol)

    14

  • 7/31/2019 Manual Plpgsql

    17/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    | | = $ $ || nuevovalor|| $$ WHERE llave= || quote_literal(llavevalor);

    debido a que podra fallar si el contenido de nuevovalor contiene $$. La mismaobjecin podra aplicarse a cualquier otro delimitador del tipo dlar que usara. Asi

    que, para entrecomillar de manera segura el texto que no conozca de inicio, debe usarquote_literal.

    Obteniendo el Estado del Resultado

    Existen varias maneras para determinar el efecto de un comando. El primer mtodoconsiste en usar el comando GET DIAGNOSTICS, que tiene la forma:

    GET DIAGNOSTICS variable = item [ , . . . ] ;

    Este comando permite recuperar los indicadores del estado del sistema. Cada itemes una palabra reservada que identifica a un valor del estado que se asignar a unavariable especfica (la cual debe ser del tipo adecuado para recibirlo). Los tems de

    los estados disponibles actualmente son ROW_COUNT, la cantidad de renglones proce-sados por el ltimo comando enviado al motor SQL, y RESULT_OID, el OID del ltimorengln insertado por el comando SQL. Observe que RESULT_OID solamente es tildespus de un comando INSERT.

    Un ejemplo:

    GET DIAGNOSTICS integer_var = ROW_COUNT;

    El segundo mtodo para determinar los efectos de un comando es revisar la variableespacial llamada FOUND, la cual es de tipo boolean. FOUND es falso de entrada dentrode cualquier llamada a una funcin PL/pgSQL. Su valor se establece por cada uno delos siguientes tipos de sentencias:

    Una sentencia SELECT INTO establece FOUND como verdadero si regresa unrengln, falso si ningn rengln es regresado.

    Un comando PERFORM define a FOUND como verdadero si produce (y descarta)un rengln, falso si ningn rengln es producido.

    Las sentencias UPDATE, INSERT y DELETE definen a FOUND como verdadero sial menos se afecta un rengln, como falso si ningn rengln es afectado.

    Una sentencia FETCH define a FOUND como verdadero si regresa un rengln, comofalso si ningn rengln en regresado.

    Una sentencia FOR deja a FOUND con el valor de verdadero si itera una o ms veces,en caso contrario lo pone en falso. Esto aplica a las tres variantes de la sentenciasFOR (ciclos FOR enteros, ciclos FOR de conjuntos de registros y ciclos FOR de con-

    juntos de registros dinmicos). FOUND se establece de esta manera cuando se saledel ciclo FOR; dentro del la ejecucin del ciclo, FOUND no se modifica por la senten-cia FOR, aunque puede ser cambiado por la ejecucin de otra sentencia dentro delcuerpo del ciclo.

    FOUND es una variable local dentro de cada funcin PL/pgSQL; as que cualquier cam-bio en ella, afecta solo a la funcin actual.

    15

  • 7/31/2019 Manual Plpgsql

    18/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Estructuras de Control

    Las estructuras de control son probablemente la parte ms til (e importante) dePL/pgSQL. Con las estructuras de control de PL/pgSQL puede manipular los datos dePostgreSQL de una manera flexible y poderosa.

    Regreso de una FuncinExisten dos comandos que le permiten regresar datos desde una funcin: RETURNy RETURN NEXT.

    RETURN

    RETURN expresin;

    RETURN con una expresin termina la funcin y regresa el valor de expresin aquin la est llamando. Esta forma debe ser usada para las funciones PL/pgSQL queno regresan un conjunto.

    Cuando se regresa un tipo escalar puede usarse cualquier expresin. El resultado de

    la expresin ser transformado (cast) automticamente al tipo de retorno de la fun-cin, tal como se defini en la asignacin. Para regresar un valor compuesto (rengln)debe escribir una variable registro o rengln como la expresin.

    El valor de retorno de una funcin no puede quedarse indefinido. Si el control alcanzael final de bloque ms externo de la funcin sin encontrar una sentencia RETURN,se producir un error en tiempo de ejecucin.

    Si declar que la funcin regrese void, tambin debe proporcionar una sentencia RE-TURN, pero en este caso la expresin que sigue a RETURN ser opcional y serignorada si est presente.

    RETURN NEXT

    RETURN NEXT expresin;

    Cuando se declara que una funcin PL/pgSQL regrese SETOF alguntipo, el proced-imiento a seguir es ligeramente diferente. En este caso, los items individuales a re-tornar se especifican en comandos RETURN NEXT, y despus un comando finalRETURN sin argumentos se utiliza para indicar que la funcin ha terminado de eje-cutarse. RETURN NEXT puede usarse con tipos escalares y compuestos; en el ltimocaso, sera regresado una tabla completa de resultados.

    Las funciones que usan RETURN NEXT deben se llamadas de la siguiente manera:

    SELECT * FROM alguna_func();

    Es decir, las funciones deben se usadas como una tabla fuente en una clasula FROM.

    RETURN NEXT realmente no regresa de la funcin, simplemente almacena el valorde la expresin. Despus, contina la ejecucin de la siguiente sentencia en la funcinPL/pgSQL. Al ejecutarse los comandos sucesivos RETURN NEXT, se va armando elresultado. Un RETURN final, sin argumentos, ocasiona que el control salga de lafuncin.

    Nota: La implementacin actual de RETURN NEXT para PL/pgSQL almacena el conjuntoresultante completo antes de regresar de la funcin, como es explica arriba. Esto significaque si una funcin PL/pgSQL produce un conjunto resultante muy grande, el desempeopuede empobrecerse: los datos sern escritos en el disco para evitar el consumo dememoria, pero la funcin misma no regresar hasta que todo el conjunto resultante hayasido generado. Una versin futura de PL/pgSQL puede permitir a los usuarios el definir

    16

  • 7/31/2019 Manual Plpgsql

    19/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    funciones que regresen conjuntos que no tengan esa limitante. Por lo pronto, el mo-mento en que los datos empiezan a escribirse en el disco es controlado por la variablede configuracin work_mem. Los administradores que cuenten con suficiente memoriapara almacenar conjuntos resultantes ms grandes en la memoria, deben considerar elaumentar este parmetro.

    Condicionales

    Las sentencias IF le permiten ejecutar comandos cuando se dan ciertas condiciones.PL/pgSQL tiene cinco formas de IF:

    IF ... THEN

    IF ... THEN ... ELSE

    IF ... THEN ... ELSE IF

    IF ... THEN ... ELSIF ... THEN ... ELSE

    IF ... THEN ... ELSEIF ... THEN ... ELSE

    IF-THEN

    IF expresin-lgica THENsentencias

    END IF;

    Las sentencias IF-THEN son las formas ms simples de IF. Las sentencias entre THENy END IF sern ejecutadas si la condicin es verdadera. De otra manera, sern igno-radas.

    Ejemplo:IF v_id_usuario 0 THEN

    UPDATE usuarios SET email = v_email WHERE id_usuario= v_id_usuario;END IF;

    IF-THEN-ELSE

    IF expresin-lgica THENsentencias

    ELSEsentencias

    END IF;

    Las sentencias IF-THEN-ELSE aaden funcionalidad a IF-THEN permitindole especi-ficar un conjunto de sentencias alternativo que debe ejecutarse si la condicin pro-duce un valor de falso.

    Ejemplo:

    IF parentid IS NULL OR parentid = THEN

    RETURN fullname;ELSE

    17

  • 7/31/2019 Manual Plpgsql

    20/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    RETURN hp_true_filename(parentid) || / || fullname;END IF;

    IF v_cuenta> 0 THENINSERT INTO usuarios_cuenta(count) VALUES (v_cuenta);RETURN t;

    ELSE

    RETURN f;END IF;

    IF-THEN-ELSE IF

    Las sentencias IF pueden anidarse, como se muestra en el siguiente ejemplo:

    IF demo_renglon.sexo = m THENpretty_sex := hombre;

    ELSEIF demo_renglon.sexo = f THEN

    pretty_sex := mujer;

    END IF;END IF;

    Cuando se usa esta forma, realmente se est anidano la sentencia IF dentro de la parteELSE de la sentencia IF. As, require una sentencia END IF para cada IF anidado yuna para el padre IF-ELSE. Esto funciona, pero se vuelve tedioso cuando existenvarias alternativas por revisar. De ahi que exista la siguiente forma.

    IF-THEN-ELSIF-ELSE

    IF expresin-lgica THENsentencias

    [ ELSIF expresin-lgica THENsentencias

    [ ELSIF expresin-lgica THENsentencias

    ...]][ ELSE

    sentencias ]END IF;

    IF-THEN-ELSIF-ELSE proporciona un mtodo ms conveniente para revisar variasalternativas en una sentencia. Formalmente es equivalente a los comandos anidadosIF-THEN-ELSE-IF-THEN, pero solo se necesita un END IF.

    A continuacin en ejemplo:

    IF numero = 0 THENresultado := cero;ELSIF numero > 0 THEN

    resultado := positivo;ELSIF numero < 0 THEN

    resultado := negativo;ELSE

    -- hmm, la nica otra posibilidad que el nmero sea nuloresultad := NULL;

    END IF;

    18

  • 7/31/2019 Manual Plpgsql

    21/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    IF-THEN-ELSEIF-ELSE

    ELSEIF es un alias de ELSIF.

    Ciclos Simples

    Con las sentencia LOOP, EXIT, WHILE y FOR, usted puede hacer que en sus funcionesPL/pgSQL se repitan una serie de comandos.

    LOOP

    []LOOP

    sentencias

    END LOOP;

    LOOP define un ciclo incondicional que se repite indefinidamente hasta que encuentraalguna sentencia EXIT o RETURN. La etiqueta opcional puede usarse por las sen-tencias EXIT en los ciclos anidados para especificar que nivel de anidamiento debe

    terminarse.

    EXIT

    EXIT [ etiqueta ] [ WHEN expresin ];

    Si no se proporciona una etiqueta se termina el ciclo ms interno y se ejecuta acontinuacin la sentencia posterior a END LOOP. Si sedefineuna etiqueta, sta debeser la etiqueta del nivel actual o de algn otro ms externo del ciclo anidado o del

    bloque. Entonces, el ciclo o bloque nombrado se termina y el control contina con lasentencia posterior al END del ciclo/bloque correspondiente.

    Si WHEN est presente, la salida del ciclo ocurre solo si la condicin especificada es

    verdadera, de otra manera, el control pasa a la sentencia despus del EXIT.EXIT puede utilizarse para provocar una salida temprana de todo tipo de ciclos; noest limitado al uso de ciclos condicionales.

    Ejemplos:

    LOOP-- algun procesamientoIF count > 0 THEN

    EXIT; -- salir del cicloEND IF;

    END LOOP;

    LOOP-- algn procesamiento

    EXIT WHEN count > 0; -- mismo resultado que en el ejemplo anteriorEND LOOP;

    BEGIN-- algn procesamientoIF stocks > 100000 THEN

    EXIT; -- causa la salida del bloque BEGINEND IF;

    END;

    19

  • 7/31/2019 Manual Plpgsql

    22/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    WHILE

    []WHILE expresin LOOP

    sentencia

    END LOOP;

    La sentencia WHILE repite una secuencia de sentencias tanto como la expresin de lacondicin produzca un valor de verdadero. La condicin se revisa justo antes de cadaentrada al cuerpo del ciclo.

    Por ejemplo:

    WHILE cantidad_adeudo > 0 AND balance_certificado_regalo > 0 LOOP-- algn procesamiento

    END LOOP;

    WHILE NOT expresin_lgica LOOP-- algn procesamiento

    END LOOP;

    FOR (variante con enteros)

    []FOR nombre IN [ REVERSE ] expresin .. expresin LOOP

    sentencias

    END LOOP;

    Este forma de FOR crea un ciclo que itera sobre un rango de valores enteros. La vari-able nombre se define de manera automtica como de tipo integer y existe solo den-tro del ciclo. Las dos expresiones que generan los lmites inferior y superior del rango,son evaluados una sola vez al entrar al ciclo. El paso de la iteracin es 1 generalmente,pero es -1 cuando se especifica REVERSE.

    Algunos ejemplos de ciclos enteros FOR:

    FOR i IN 1..10 LOOP-- algn procesamiento aquRAISE NOTICE i es %, i;

    END LOOP;

    FOR i IN REVERSE 10..1 LOOP-- algn procesamiento aqu

    END LOOP;

    Si el lmite inferior es mayor que el lmite superior (o menor que, en el caso deREVERSE), el cuerpo del ciclo no se ejecuta en absoluto. No se genera un error.

    Ciclos a Travs de Resultados de Consultas

    Usando un tipo diferente de un ciclo FOR, puede iterar a lo largo de los resultados deuna consulta y manipular los datos correspondientes. La sintaxis es:

    []FOR registro_o_rengln IN consulta LOOP

    sentencias

    END LOOP;

    20

  • 7/31/2019 Manual Plpgsql

    23/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    A las variables registro o rengln les es asignado, de manera sucesiva, cada renglnresultante de la consulta (la cual debe ser un comando SELECT) y el cuerpo delciclo se ejecuta para cada rengln. He aqu un ejemplo:

    CREATE FUNCTION cs_refresca_mvistas() RETURNS integer AS $$DECLARE

    mvistas RECORD;

    BEGINPERFORM cs_log(Refrescando las vistas materializadas...);

    FOR mvistas IN SELECT * FROM cs_vistas_materializadasORDER BY llave_orden LOOP

    -- Ahora "mvistas" tiene un registro de cs_vistas_materializadas

    PERFORM cs_log(Refrescando vistas materializadas ||quote_ident(mvistas.mv_nombre) || ...);

    EXECUTE TRUNCATE TABLE || quote_ident(mvistas.mv_nombre);EXECUTE INSERT INTO ||

    quote_ident(mvistas.mv_nombre) || || mvistas.mv_consulta;END LOOP;

    PERFORM cs_log(Terminado el refresco de las vistasmaterializadas.);

    RETURN 1;END;$$ LANGUAGE plpgsql;

    Si el ciclo se termina por una sentencia EXIT, el valor del ltimo rengln asignado seencuentra accesible despus del ciclo.

    La sentencia FOR-IN-EXECUTE es otra manera de iterar sobre los renglones:

    []FOR registro_o_rengln IN EXECUTE texto_expresin LOOP

    sentencia

    END LOOP;

    Esta es similar a la forma anterior, excepto que la sentencia SELECT fuente se especi-fica como una expresion en cadena, la cual es evaluada y replaneada en cada entradaal ciclo FOR. Esto le permite al programador el seleccionar la velocidad de una con-sulta previamente planeada o la flexibilidad de una consulta dinmica, exactamentecomo una simple sentencia EXECUTE.

    Nota: El analizador de PL/pgSQL distingue actualmente las dos clases de ciclos FOR(enteros o resultados de consultas) revisando si los smbolos .. aparecen fuera de losparntesis entre IN y LOOP. Si no se observan los smbolos .. entonces se presume quees un ciclo sobre renglones. Si se escriben mal los smbolos .. llevar seguramente auna queja entre las lneas de loop variable of loop over rows must be a record or rowvariable, en lugar de un simple error de sintaxis que usted esperara obtener.

    Atrapar los Errores

    Por omisin, cualquier error que ocurra en una funcin PL/pgSQL aborta la ejecucinde la funcin, en consecuencia, tambin la transaccin que la envuelve. Usted puedeatrapar los errores y recuperarse de ellos usando un bloque BEGIN con una clusulaEXCEPTION. La sintaxis es una extensin de la sintaxis normal de un bloque BEGIN.

    [ ][ DECLARE

    declaraciones ]

    21

  • 7/31/2019 Manual Plpgsql

    24/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    BEGINsentencia

    EXCEPTIONWHEN condicin [ OR condicin ... ] THEN

    sentencias_del_manejador

    [ WHEN condicin [ OR condicin ... ] THEN

    sentencias_del_manejador

    ... ]END;

    Si no ocurre un error, esta forma de bloque simplemente ejecuta todas lassentencias, y el control pasa a la siguiente sentencia despus de END. Pero siocurre un error dentro de las sentencias, se abandona el resto del procesamiento,y el control se pasa a la lista EXCEPTION. En la lista se busca la primera condicinque coincida con el error ocurrido. Si hay una coincidencia, se ejecuta lasentencia_del_manejador correspondiente, y el control pasa a la siguientesentencia despus de END. Si no hay alguna coincidencia, el error se propaga como sila clusula EXCEPTION no estuviera ah en absoluto: el error puede ser atrapado porun bloque envolvente con EXCEPTION, o si no hay ninguno se aborta el proceso de lafuncin.

    Los nombres de las condiciones pueden ser cualquiera de los mostrados en elapndice de cdigos de error. Una nombre de categora coincide con cualquier er-ror dentro de su categora. El nombre de la condicin especial OTHERS coincide concualquier error, excepto QUERY_CANCELED. (Es posible, pero en ocasiones improba-

    ble, atrapar QUERY_CANCELED por nombre). Los nombres de las condiciones no sonsensibles a las maysculas.

    Si ocurre un error dentro de las sentencias_del_manejador, no puede ser atra-pado por esta clusula EXCEPTION, pero si se propaga. Una clusula EXCEPTION en-volvente podra atraparla.

    Cuando se atrapa un error por una clusulaEXCEPTION, las variable locales de la fun-cin PL/pgSQL se mantienen como estaban cuando ocurri el error, pero todos loscambios al estado persistente de la base de datos dentro del bloque se deshacen.

    Como ejemplo, considere este fragmento:INSERT INTO miagenda(nombre, apellido) VALUES(Joaqun, Sabina);BEGIN

    UPDATE miagenda SET nombre = Joe WHERE apellido = Sabina;x : = x + 1 ;y : = x / 0 ;

    EXCEPTIONWHEN division_by_zero THEN

    RAISE NOTICE division_by_zero atrapado;RETURN x;

    END;

    Cuando el control alcanza la asignacin a y, fallar con un error division_by_zero.Este ser atrapado por la clusula EXCEPTION. El valor regresado en la sentenciaRETURN ser el valor incrementado de x, pero los efectos del comando UPDATEhabrn sido deshechos. El comando INSERT que precede al bloque no se deshace,sin embargo, al final resulta que la base de datos contiene Joaqun Sabina, no JoeSabina.

    Sugerencia: Un bloque que contiene una clusula EXCEPTION es significativamente mscostoso, para entrar y salir, que un bloque sin ella. Por tanto, no use EXCEPTION, a menosque sea necesario.

    22

  • 7/31/2019 Manual Plpgsql

    25/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Cursores

    En lugar de ejecutar una consulta completa de inmediato, es posible definir un cur-sor que encapsule la consulta, para despus leer los resultados de la consulta recu-perando solo algunos renglones a la vez. Una razn para proceder de esta maneraes el evitar el consumo de la memoria cuando el resultado contiene una gran canti-dad de renglones. (Sin embargo, los usuarios de PL/pgSQL normalmente no tienen

    que preocuparse de esto, pues el ciclo FOR usa de manera automtica un cursor in-terno para evitar problemas con la memoria). Un uso ms interesante es el regresaruna referencia a un cursor que ha creado una funcin. Esto proporciona una maneraeficiente de regresar desde las funciones conjuntos grandes de renglones.

    Declaracin de las Variables de Cursores

    Todos los accesos a los cursores en PL/pgSQL se hacen por medio de variables decursores, las cuales son siempre del tipo de dato especial refcursor. Una manera decrear una variable de cursor es simplemente declararla como una variable de tiporefcursor. Otra manera es usar la sintaxis de declaracin de cursor, que en general es:

    nombre CURSOR [ ( argumentos ) ] FOR consulta ;

    (FOR puede se reemplazado por IS, por compatibilidad con Oracle). Losargumentos, si se especifican, son una lista separada por comas de pares nombretipo_de_dato que definen los nombres que sern reemplazados por los valores delos parmetros en la consulta especfica. Los valores actuales a sustituir por esosnombres sern especificados ms tarde, al abrirse el cursor.

    Algunos ejemplos

    DECLAREcurs1 refcursor;curs2 CURSOR FOR SELECT * FROM tenk1;

    curs3 CURSOR (key integer) IS SELECT * FROM tenk1WHERE unique1 = llave;

    Las tres variables tienen el tipo de dato refcursor, pero la primera puede usarse con

    cualquier consulta, mientras que las segunda tiene ya una consulta especfica ligadaa ella, y la ltima tiene una consulta parametrizada ligada a ella. ( llave ser reem-plazada por un parmetro con valor entero cuando el cursor se abra). Se dice que lavariable curs1 est desligada puesto que no est ligada a ninguna consulta en partic-ular.

    Apertura de Cursores

    Antes de que un cursor pueda ser usado para recuperar renglones, debe ser abierto.(Esta es la accin equivalente al comando de SQL DECLARE CURSOR). PL/pgSQLtiene tres formas de la sentencia OPEN, dos de la cuales usan variables de cursoresno ligadas, mientras que la tercera usa una variable de cursor ligada.

    OPEN FOR SELECT

    OPEN cursor_no_ligado FOR SELECT ...;

    La variable de cursor se abre y se le entrega la consulta especfica que debe ejecutar.El cursor no puede estar ya abierto, y tiene que haber sido declarado como un cur-sor no ligado (es decir, como una variable refcursor simple). La consulta SELECT estratada de la misma manera que otras sentencia SELECT en PL/pgSQL: los nombresde las variable PL/pgSQL se sustituyen y el plan de la consulta es almacenado paraun posible reuso.

    23

  • 7/31/2019 Manual Plpgsql

    26/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Un ejemplo:

    OPEN curs1 FOR SELECT * FROM foo WHERE llave= millave;

    OPEN FOR EXECUTE

    OPEN cursor_no_ligado FOR EXECUTE cadena_de_comando;

    La variable de cursor se abre y se le entrega la consulta especfica que debe ejecutar. Elcursor no puede estar ya abierto, y tiene que haber sido declarado como un cursor noligado (es decir, como una variable refcursor simple). La consulta se especfica comouna expresin de cadena de la misma manera que el comando EXECUTE. Comosiempre, esto otorga flexibilidad puesto que la consulta puede variar de una corridaa otra.

    Un ejemplo:

    OPEN curs1 FOR EXECUTE SELECT * FROM || quote_ident($1);

    Apertura de un Cursor Ligado

    OPEN cursor_ligado [ ( valores_de_argumentos ) ];

    Esta forma de OPEN se utiliza para abrir una variable de cursor cuya consulta se en-contraba ligada a ella cuando fue declarada. El cursor no puede estar ya abierto. Unalista de los valores de las expresiones de los argumentos actuales debe aparecer si ysolo si el cursor fue declarado para manejar argumentos. Esos valores sern sustitu-dos en la consulta. El plan de la consulta para un cursor ligado siempre se consideraalmacenable (cachable); para este caso no existe un equivalente de EXECUTE.

    Ejemplos:

    OPEN curs2;OPEN curs3(42);

    Uso de los Cursores

    Una vez que se ha abierto un cursor, puede ser manipulado con las sentencias de-scritas aqu.

    Estas manipulaciones no deben ocurrir en la misma funcin que abri el cursor conel cual iniciar. Usted puede regresar un valor refcursor de una funcin y permitirque quien la llam opere sobre el cursor. (Internamente, un valor refcursor es simple-mente el nombre de la cadena de un llamado portal que contiene la consulta activapara ese cursor. Este nombre puede pasar de un lado a otro, asignarse a otra variablerefcursor y dems, sin perturbar el portal).

    Todos los portales se cierran implcitamente al terminar la transaccin. Por tanto, unvalor refcursor se puede usar para referirse a un cursor abierto solo hasta el final dela transaccin.

    24

  • 7/31/2019 Manual Plpgsql

    27/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    FETCH

    FETCH cursor INTO blanco;

    FETCH recupera el siguiente rengln del cursor y lo inserta en el blanco, el cualpuede ser una variable de rengln, una variable de registro o una lista de variablessimples separadas por comas, exactamente como en SELECT INTO. De igual forma

    que con SELECT INTO, la variable especial FOUND puede ser revisada para saber sise obtuvo o no un rengln.

    Un ejemplo:

    FETCH curs1 INTO renglobvar;FETCH curs2 INTO foo, bar, baz;

    CLOSE

    CLOSE cursor;

    CLOSE cierra el portal subyacente a un cursor abierto. Esto puede utilizarse paraliberar recursos antes de que se termine la transaccin, o para liberar la variable delcursor que desea abrir de nuevo.

    Un ejemplo:

    CLOSE curs1;

    Regreso de Cursores

    Las funciones PL/pgSQL pueden regresar cursores a quien las llama. Es til para re-

    gresar varios renglones o columnas, especialmente para conjuntos de resultados muygrandes. Para hacerlo la funcin abre el cursor y regresa el nombre del cursor a quienla invoca (o simplemente abre el cursor usando un nombre de portal especificadopor o conocido por quien lo invoca). El invocante puede entonces recuperar (fetch)los renglones del cursor. El cursor puede ser cerrado por el invocante, o aquel sercerrado automticamente cuando se cierre la transaccin.

    El nombre del portal usado para un cursor puede ser especificado por el progra-mador o generado automticamente. Para especificar un nombre de un portal bastacon asignar una cadena a la variable refcursor antes de abrirlo. El valor de la cadenade la variable refcursor ser usado por OPEN como el nombre de el portal subya-cente. Sin embargo, si la variable refcursor es nula, OPEN generar de manera au-tomtica un nombre que no genere conflicto con algn portal existente, y lo asignara la variable refcursor.

    Nota: Una variable de cursor ligado se inicializa al valor de la cadena que representa sunombre, de tal manera que el nombre del portal es el mismo que el nombre de la variablede cursor, a menos que el programador lo sobreescriba por asignacin antes de abrirel cursor. Pero una variable de cursor no ligado toma inicialmente el valor por defectode nulo, as que recibir un nombre nico generado automticamente, a menos que sesobreescriba.

    El siguiente ejemplo muestra una manera de que un nombre de un cursor puede sersuministrado por el invocante:

    25

  • 7/31/2019 Manual Plpgsql

    28/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    CREATE TABLE test (col text);INSERT INTO test VALUES (123);

    CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS BEGIN

    OPEN $1 FOR SELECT col FROM test;RETURN $1;

    END; LANGUAGE plpgsql;

    BEGIN;SELECT reffunc(funccursor);FETCH ALL IN funccursor;COMMIT;

    En el siguiente ejemplo se utiliza la generacin automtica del nombre del cursor:

    CREATE FUNCTION reffunc2() RETURNS refcursor AS DECLARE

    ref refcursor;BEGIN

    OPEN ref FOR SELECT col FROM test;RETURN ref;

    END; LANGUAGE plpgsql;

    BEGIN;SELECT reffunc2();

    reffunc2--------------------

    (1 row)

    FETCH ALL IN "";COMMIT;

    El siguiente ejemplo muestra una manera de regresar varios cursores desde una solafuncin:

    CREATE FUNCTION mifunc(refcursor, refcursor) RETURNSSETOF refcursor AS $$

    BEGINOPEN $1 FOR SELECT * FROM tabla_1;RETURN NEXT $1;OPEN $2 FOR SELECT * FROM tabla_2;RETURN NEXT $2;RETURN;

    END;$$ LANGUAGE plpgsql;

    -- se require estar en una transaccin para usar los cursores.BEGIN;

    SELECT * FROM mifunc(a, b);

    FETCH ALL FROM a;FETCH ALL FROM b;COMMIT;

    26

  • 7/31/2019 Manual Plpgsql

    29/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    Errores y Mensajes

    Utilice la sentencia RAISE para reportar mensajes y levantar (raise) errores.

    RAISE nivel formato [, variable [, ...]];

    Los niveles posibles son DEBUG, LOG, INFO, NOTICE, WARNING y EXCEPTION. EXCEPTION

    levanta un error (lo cual normalmente aborta la transaccin actual); los dems nivelessolo generan mensajes de diferentes niveles de prioridad. Que los mensajes de unaprioridad particular sean reportados al cliente, escritos en la bitcora del servidor oambos, se controla por las variables de configuracin correspondientes.

    Dentro de la cadena de formato, % se reemplaza por la siguiente representacion decadena del argumento opcional. Debe escribir %% para generar una % literal. Observeque los argumentos opcionales actualmente deben ser variables simples, no expre-siones, y el formato debe ser una cadena literal simple.

    En este ejemplo, el valor de v_job_id remplazar el % en la cadena:

    RAISE NOTICE LLamando a cs_create_job(%), v_job_id;

    Este ejemplo abortar la transaccin con el mensaje de error dado:

    RAISE EXCEPTION ID no existente --> %, user_id;

    Actualmente RAISE EXCEPTION genera siempre el mismo cdigo SQLSTATE,P0001, sin importar con que mensaje se invoque. Es posible atrapar esta excepcincon EXCEPTION ... WHEN RAISE_EXCEPTION THEN ... pero no hay manera dediferenciar un RAISE de otro.

    Procedimientos Desencadenantes o Disparadores (Triggers)

    PL/pgSQL puede usarse para definir procedimientos disparadores (triggers). Un pro-cedimiento trigger se crea con el comando CREATE FUNCTION, declarndola comouna funcin sin argumentos y un tipo de retorno trigger. Observe que la funcindebe ser declarada sin argumentos, aunque espere recibir argumentos especificadosen CREATE TRIGGER los argumentos de los triggers se pasan por medio deTG_ARGV, tal como se describe adelante.

    Cuando una funcin PL/pgSQL es llamada como un trigger, se crean automtica-mente varias variables especiales en el bloque ms externo. Ellas son:

    NEW

    Tipo de dato RECORD; variable que almacena el nuevo rengln de la basede datos para las operaciones de INSERT/UPDATE para triggers a nivel derengln. Esta variable es NULL en triggers a nivel de sentencia.

    OLD

    Tipo de dato RECORD; variable que almacena el rengln viejo de la base dedatos para las operaciones de UPDATE/DELETE para triggers a nivel derengln. Esta variable es NULL en triggers a nivel de sentencia.

    TG_NAME

    Tipo de dato name; variable que contiene el nombre del trigger lanzado actual-mente.

    27

  • 7/31/2019 Manual Plpgsql

    30/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    TG_WHEN

    Tipo de dato text; una cadena con BEFORE o AFTER dependiendo de la definicindel trigger.

    TG_LEVEL

    Tipo de dato text; una cadena con ROW o STATEMENT dependiendo de la definicin

    del trigger.

    TG_OP

    Tipo de dato text; una cadena con INSERT, UPDATE o DELETE la cual informaacerca de la operacin para la que fue lanzado el trigger.

    TG_RELID

    Tipo de dato oid; el ID del objeto de la tabla que caus la invocacin del trigger.

    TG_RELNAME

    Tipo de dato name; el nombre de la tabla que caus la invocacin del trigger.

    TG_NARGS

    Tipo de dato integer; la cantidad de argumentos dados al procedimiento triggeren la sentencia CREATE TRIGGER.

    TG_ARGV[]

    Tipo de dato arreglo de text; los argumentos de la sentencia CREATE TRIG-GER. El ndice cuenta desde 0, Los ndices invlidos (menores que 0 o mayoreso iguales a tg_nargs) generan un valor nulo.

    Una funcin trigger debe regresar ya sea un NULL o un valor registro/rengln quetenga exactamente la misma estructura de la tabla para la cual se inici el trigger.

    Los triggers de nivel rengln lanzados ANTES (BEFORE) pueden regresar un nulo

    para notificar al administrador de triggers que debe saltarse el resto de la operacinpara este rengln (es decir, los triggers subsecuentes no deben dispararse, y el IN-SERT/UPDATE/DELETE no ocurre para este rengln). Si se regresa un valor nonulo entonces la operacin procede con ese valor de rengln. El regresar un valor derengln diferente del valor original de NEW altera el rengln que ser insertado o ac-tualizado (pero no tiene un efecto directo en el caso DELETE). Para alterar el renglnque se va a almacenar, es posible reemplazar valores particulares directamente enNEW y regresar el NEW modificado o construir completamente el nuevo registro que seva a regresar.

    El valor de retorno de un trigger de nivel sentencia BEFORE o AFTER o un trigger denivel rengln siempre se ignora; tambin puede ser nulo. Sin embargo, cualquiera deestos tipos de triggers pueden abortar la operacin entera al levantarse un error.

    El Ejemplo 1-1 muestra un ejemplo de un procedimiento trigger en PL/pgSQL.

    Ejemplo 1-1. Un Procedimiento Trigger PL/pgSQL

    Este ejemplo de trigger asegura que en cualquier momento en que se inserta o actu-aliza un rengln en una tabla, se estampen en el rengln el nombre del usuario y eltiempo actuales. Tambin verifica que exista el nombre del usuario y que el salariotenga un valor positivo.

    CREATE TABLE empleados (empleado_nombre text NOT NULL,salario integerultima_fecha timestamp,

    28

  • 7/31/2019 Manual Plpgsql

    31/34

  • 7/31/2019 Manual Plpgsql

    32/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    ELSIF (TG_OP = UPDATE) THENINSERT INTO empleados_audit SELECT U, now(), user,

    NEW.empleado_nombre, NEW.salario;RETURN NEW;

    ELSIF (TG_OP = INSERT) THENINSERT INTO empleados_audit SELECT I, now(), user, NEW.*;RETURN NEW;

    END IF;RETURN NULL; -- el resultado es ignorado puesto que estees un trigger AFTER

    END; language plpgsql;

    CREATE TRIGGER empleados_audit AFTER INSERT OR UPDATE ORDELETE ON empleados FOR EACH ROW EXECUTE PROCEDURE

    procesa_empleados_audit();

    Un uso de los triggers es el mantener una tabla como resumen de otra tabla. El re-sumen resultante puede usarse en lugar de la tabla original para ciertas consultas comnmente con una gran ahorro en el tiempo de ejecucin. Esta tcnica se suele usaren Data Warehousing, en donde las tablas se datos medidos u observados (llamadastablas factuales) pueden ser extremadamente grandes. El Ejemplo 1-3 muestra un

    ejemplo de un procedimiento trigger en PL/pgSQL que mantiene una tabla resumenpara una tabla factual en un data warehouse.

    Ejemplo 1-3. Un Procedimiento Trigger Para Mantener Una Tabla Resumen enPL/pgSQL

    El esquema que se detalla aqu est basado parcialmente en el ejemplo Grocery Storede The Data Warehouse Toolkit por Ralph Kimball.

    ---- Tablas principales - time dimension y sales fact.--CREATE TABLE time_dimension (

    time_key integer NOT NULL,day_of_week integer NOT NULL,

    day_of_month integer NOT NULL,month integer NOT NULL,quarter integer NOT NULL,year integer NOT NULL

    );CREATE UNIQUE INDEX time_dimension_key ON time_dimension(time_key);

    CREATE TABLE sales_fact (time_key integer NOT NULL,product_key integer NOT NULL,store_key integer NOT NULL,amount_sold numeric(12,2) NOT NULL,units_sold integer NOT NULL,amount_cost numeric(12,2) NOT NULL

    );

    CREATE INDEX sales_fact_time ON sales_fact(time_key);

    ---- Tabla resumen - sales by time.--CREATE TABLE sales_summary_bytime (

    time_key integer NOT NULL,amount_sold numeric(15,2) NOT NULL,units_sold numeric(12) NOT NULL,amount_cost numeric(15,2) NOT NULL

    );CREATE UNIQUE INDEX sales_summary_bytime_key ON

    sales_summary_bytime(time_key);

    30

  • 7/31/2019 Manual Plpgsql

    33/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    ---- Funcin y trigger para corregir la(s) columna(s)-- resumida(s) en UPDATE, INSERT, DELETE.--CREATE OR REPLACE FUNCTION maint_sales_summary_bytime()

    RETURNS TRIGGER AS $maint_sales_summary_bytime$

    DECLAREdelta_time_key integer;delta_amount_sold numeric(15,2);delta_units_sold numeric(12);delta_amount_cost numeric(15,2);

    BEGIN

    -- Calcula la(s) cantidad(es) del incremento/decremento.IF (TG_OP = DELETE) THEN

    delta_time_key = OLD.time_key;delta_amount_sold = -1 * OLD.amount_sold;delta_units_sold = -1 * OLD.units_sold;delta_amount_cost = -1 * OLD.amount_cost;

    ELSIF (TG_OP = UPDATE) THEN

    -- Prohibe las actualizacioes que cambie la time_key --- (probabablemente no muy oneroso, puesto que-- la mayora de los cambios se harn como-- DELETE + INSERT).

    IF ( OLD.time_key != NEW.time_key) THENRAISE EXCEPTION La actualizacin de time_key: % -> %

    no est permitida, OLD.time_key, NEW.time_key;END IF;

    delta_time_key = OLD.time_key;delta_amount_sold = NEW.amount_sold - OLD.amount_sold;delta_units_sold = NEW.units_sold - OLD.units_sold;delta_amount_cost = NEW.amount_cost - OLD.amount_cost;

    ELSIF (TG_OP = INSERT) THEN

    delta_time_key = NEW.time_key;delta_amount_sold = NEW.amount_sold;delta_units_sold = NEW.units_sold;delta_amount_cost = NEW.amount_cost;

    END IF;

    -- Actualiza el rengln resumen con los nuevos valores.UPDATE sales_summary_bytime

    SET amount_sold = amount_sold + delta_amount_sold,units_sold = units_sold + delta_units_sold,amount_cost = amount_cost + delta_amount_cost

    WHERE time_key = delta_time_key;

    -- No debe haber ningn rengln con este time_key-- (e.g. nuevos datos!).

    IF (NOT FOUND) THENBEGIN

    INSERT INTO sales_summary_bytime (time_key,amount_sold,units_sold,amount_cost)

    VALUES (

    31

  • 7/31/2019 Manual Plpgsql

    34/34

    Captulo 1. El Lenguaje Procedimental SQL - PL/pgSQL

    delta_time_key,delta_amount_sold,delta_units_sold,delta_amount_cost

    );EXCEPTION

    --

    -- Atrape la condicin de competencia cuando dos-- transacciones estn aadiendo datos para-- un nuevo time_key.--WHEN UNIQUE_VIOLATION THEN

    UPDATE sales_summary_bytimeSET amount_sold = amount_sold + delta_amount_sold,

    units_sold = units_sold + delta_units_sold,amount_cost = amount_cost + delta_amount_cost

    WHERE time_key = delta_time_key;

    END;END IF;RETURN NULL;

    END;

    $maint_sales_summary_bytime$ LANGUAGE plpgsql;

    CREATE TRIGGER maint_sales_summary_bytimeAFTER INSERT OR UPDATE OR DELETE ON sales_fact

    FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytime();