Ejemplos

Anuncio
14/12/2010
PG/PLSQL
Miguel Ángel Manso
ETSI en Topografía, Geodesia y
Cartografía - UPM
Índice
• Estructura PL/PGSQL
• Declaraciones, Alias para parámetros en
funciones
• Datos de tipo tabla, Type & RowType
• Sentencias, estructuras de control
• Reporte de errores, cursores
• Triggers
1
14/12/2010
Estructura PL/PGSQL
CREATE OR REPLACE PROCEDURE [esquema].nombre-procedimiento(nombre-parámetro {IN, OUT, IN OUT}
tipo de dato, ..) {IS, AS}
Declaración de variables;
Declaración de constantes;
Declaración de cursores;
BEGIN
Cuerpo del subprograma PL/SQL;
EXCEPTION
Bloque de excepciones PL/SQL;
END;
CREATE OR REPLACE FUNCTION [esquema].nombre-funcion(nombre-parámetro {IN, OUT, IN OUT} tipo-dedato, ..) RETURN tipo-de-dato {IS, AS}
Declaración de variables;
Declaración de constantes;
Declaración de cursores;
BEGIN
Cuerpo del subprograma PL/SQL;
EXCEPTION
Bloque de excepciones PL/SQL;
END;
Declaraciones
• Sintaxis general:
name [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } expression
];
• Ejemplos:
user_id integer;
quantity numeric(5);
url varchar;
myrow tablename%ROWTYPE;
myfield tablename.columnname%TYPE;
arow RECORD;
 Registro
 Tipo col.
 Registro
quantity INTEGER DEFAULT 32;
url varchar := ”http://mysite.com”;
user_id CONSTANT INTEGER := 10;
2
14/12/2010
Alias para parámetros de funciones
name ALIAS FOR $n;
Ejemplo:
CREATE FUNCTION sales_tax(REAL) RETURNS REAL AS ’
DECLARE
subtotal ALIAS FOR $1;
BEGIN
return subtotal * 0.06;
END;
’ LANGUAGE ’plpgsql’;
CREATE FUNCTION instr(VARCHAR, INTEGER) RETURNS INTEGER AS ’
DECLARE
v_string ALIAS FOR $1;
index ALIAS FOR $2;
BEGIN
Datos de tipo Tabla
name tablename%ROWTYPE;
-- Variable de tipo complejo (registro)
-- Se usa name.fieldName
CREATE FUNCTION use_two_tables(tablename) RETURNS TEXT AS ’
DECLARE
in_t ALIAS FOR $1;
use_t table2name%ROWTYPE;
BEGIN
SELECT * INTO use_t FROM table2name WHERE ... ;
RETURN in_t.f1 || use_t.f3 || in_t.f5 || use_t.f7;
END;
’ LANGUAGE ’plpgsql’;
3
14/12/2010
Type & RowType
Conocer el tipo de dato de una variable Type
user_id users.user_id%TYPE;
Para crear una variable de tipo registro asociado
a las columnas de una tabla
users_rec users%ROWTYPE;
Sentencias
Asignación: <Variable> := <valor>;
user_id := 20;
tax := subtotal * 0.06;
SELECT INTO target select_expressions FROM ...;
SELECT INTO Result * FROM EMP WHERE empname = myname;
IF NOT FOUND THEN
RAISE EXCEPTION ”El empleado % no existe “, myname;
END IF;
Ejecución sin resultados: PERFORM query;
PERFORM create_mv(”cs_session_page_requests_mv”, my_query);
4
14/12/2010
Sentencias
No hacer nada: Null;
Ejecución dinámica: EXECUTE texto-comando;
EXECUTE ”UPDATE tabla SET ”
|| quote_ident(nombreCampo)
|| ” = ”
|| quote_literal(NuevoValor)
|| ” WHERE ...”;
Obtener resultado de la última ejecución:
GET DIAGNOSTICS variable = item [ , ... ] ;
Ejemplos:
GET DIAGNOSTICS Variable_int = ROW_COUNT; -- Cantidad de filas
GET DIAGNOSTICS estado = FOUND; -- True/False último resultado
Estructuras de control
• Retorno de resultados:
– Return expresión;
• Condicionales:
IF ... THEN
IF ... THEN ... ELSE
IF ... THEN ... ELSE IF
IF ... THEN ... ELSIF ... THEN ... ELSE
IF ... THEN ... ELSEIF ... THEN ... ELSE
5
14/12/2010
Bucles
Bucles simples:
[<<label>>]
LOOP
sentencias
EXIT [ label ] [ WHEN expresion ];
END LOOP;
Ejemplos:
LOOP
-- algunos cálculos
IF count > 0 THEN
EXIT; -- exit loop
END IF;
END LOOP;
LOOP
-- otros cálculos
EXIT WHEN count > 0;
END LOOP;
Bucle While
While
[<<label>>]
WHILE expresión LOOP
sentencias
END LOOP;
Ejemplos
WHILE amount_owed > 0 AND
gift_certificate_balance > 0 LOOP
-- algunos cálculos
END LOOP;
WHILE NOT expresión_booleana
LOOP
-- algunos cálculos
END LOOP;
6
14/12/2010
Bucle For
For
[<<label>>]
FOR nombre IN [ REVERSE ]
expresión .. expresión LOOP
sentencias
END LOOP;
Ejemplos
FOR i IN 1..10 LOOP
-- algunas expresiones
RAISE NOTICE ”i is %”,i;
END LOOP;
FOR i IN REVERSE 10..1
LOOP
-- algunas expresiones
END LOOP;
Iterar sobre resultados
Iterar sobre resultados
[<<etiqueta>>]
FOR fila IN consulta LOOP
sentencias
END LOOP;
Ejemplo
CREATE FUNCTION cs_refresh_mviews () RETURNS INTEGER AS ’
DECLARE
mviews RECORD;
BEGIN
PERFORM cs_log(”Actualizando las vistas...”);
FOR mviews IN SELECT * FROM vista_cs ORDER BY sort_key LOOP
-- Ahora "mviews" contiene un registro de vista_cs
PERFORM cs_log(”Actualizando las vistas…” ||
quote_ident(mviews.mv_name)
…..
END LOOP;
RETURN 1;
END;
’ LANGUAGE ’plpgsql’;
7
14/12/2010
Reportar errores
RAISE level ’format’ [, variable [...]];
Ejemplos:
RAISE NOTICE ”Invocando cs_create_job(%)”,v_job_id;
RAISE EXCEPTION ”No existe el ID --> %”,user_id;
Cursores
Declaración:
nombre CURSOR [ ( argumentos ) ] FOR|IS consulta ;
Ejemplos:
curs1 refcursor; --Es un tipo de dato genérico para cursores
curs2 CURSOR FOR SELECT * FROM tenk1;
curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE
unique1 = key;
Abrir cursor para usar:
OPEN unbound_cursor FOR SELECT ...;
OPEN unbound_cursor FOR EXECUTE query_string;
Ejemplos:
OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
8
14/12/2010
Cursores
Usar cursores:
FETCH cursor INTO target;
Cerrar cursores:
CLOSE cursor;
Retornar cursores:
CREATE TABLE prueba (columna text);
INSERT INTO prueba VALUES (’123’);
CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS ’
BEGIN
OPEN $1 FOR SELECT columna FROM prueba;
RETURN $1;
END;
’ LANGUAGE ’plpgsql’;
BEGIN;
SELECT reffunc(’funccursor’);
FETCH ALL IN funccursor;
COMMIT;
Triggers
CREATE TRIGGER --- argumentos vía TG_ARGV
Posibles argumentos:
NEW
OLD
TG_NAME
TG_WHEN
TG_LEVEL
TG_OP
TG_RELID
TG_RELNAME
TG_NARGS
TG_ARGV[]
variable con los nuevos datos
Variable con el dato antiguo
Nombre del trigger
Cuándo se dispara AFTER, BEFORE
Nivel al que afecta: fila, sentencia
Operación que dispara (INSERT, UPDATE; DELETE)
ID del objecto de la tabla que dispara el trigger
nombre de la tabla que dispara el trigger
nº de argumentos
9
14/12/2010
Mas sobre trigger
CREATE TRIGGER nombre { BEFORE | AFTER }
{ INSERT | UPDATE | DELETE [ OR ... ] } ON
tabla [ FOR [ EACH ] { ROW | STATEMENT } ]
EXECUTE PROCEDURE nombre_de_función (
argumentos )
Ejemplo trigger
1 CREATE TABLE numeros( numero bigint NOT NULL, cuadrado bigint, cubo
bigint, raiz2 real, raiz3 real, PRIMARY KEY (numero) );
2 CREATE OR REPLACE FUNCTION rellenar_datos() RETURNS TRIGGER AS
$rellenar_datos$
DECLARE
BEGIN
NEW.cuadrado := power(NEW.numero,2);
NEW.cubo := power(NEW.numero,3);
NEW.raiz2 := sqrt(NEW.numero);
NEW.raiz3 := cbrt(NEW.numero);
RETURN NULL;
END;
$rellenar_datos$ LANGUAGE plpgsql;
3 CREATE TRIGGER rellena_datos BEFORE INSERT OR UPDATE ON numeros
FOR EACH ROW EXECUTE PROCEDURE rellenar_datos();
10
14/12/2010
Ejemplo trigger
CREATE TABLE emp ( empname text, salary integer, last_date timestamp, last_user text );
CREATE FUNCTION emp_stamp () RETURNS TRIGGER AS ’
BEGIN
IF NEW.empname ISNULL THEN -- Comprueba que se proporcionan: empname y salary
RAISE EXCEPTION ”empname no puede ser NULL”;
END IF;
IF NEW.salary ISNULL THEN
RAISE EXCEPTION ”El empleado % no puede tener salario NULL”, NEW.empname;
END IF;
IF NEW.salary < 0 THEN -- El sueldo no puede ser negativo!
RAISE EXCEPTION ”El empleado % no puede tener salario negativo”, NEW.empname;
END IF;
NEW.last_date := ”now”; -- Se almacena quién y cuándo se cambiaron los datos
NEW.last_user := current_user;
RETURN NEW;
END; ’ LANGUAGE ’plpgsql’;
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
Referencias
• http://plsql-tutorial.com/index.htm
• http://www.postgresql-es.org/node/297
• Triggers: http://www.postgresql-es.org/node/301
11
Descargar