Sie sind auf Seite 1von 62

Aplicaciones de Base de Datos

ADMINISTRACIN DE POSTGRES-SQL MEDIANTE CONSOLA


POSTGRES tiene un programa (psql) que sirve para gestionar la base datos por lnea de comandos.

El directorio puede variar, por ejemplo, puede estar localizado en la raz del disco (C:), o en cualquier
otro lugar donde podamos haber instalado POSTGRES SQL. Para acceder a la consola de
POSTGRES SQL en Windows tendremos que estar situados dentro de ese directorio.

Para el efecto utilizaremos el PostgrSQL 9.1 (x86) el cual al ser instalado se ubica en:
C:\Program Files (x86)\PostgreSQL\9.1\bin>_

o tambin: C:\Program Files\PostgreSQL\9.1\bin>_

Esto depender de la plataforma y de la instalacin, postgres en Windows posee una consola y un


gestor grfico para administrar las bases de datos:

En Linux, por supuesto, tambin se puede acceder a PostgreSQL por lnea de comandos.
Posiblemente desde cualquier directorio podamos acceder a la consola de Postgres, sin necesidad de
situarse en el directorio donde est instalado.

CONECTAR CON EL SERVIDOR POSGRESQL

Lo primero que tendremos que hacer es conectar con el sistema gestor de Postgres. Para ello,
simplemente tenemos que escribir el comando "psql" e indicarle unas opciones de conexin.
% psql

Con el "%" expresamos el principio o el shell de la lnea de comandos. Ese principio es el


promptuario que tengamos en nuestra consola de Linux o MsDOS, que puede ser algo como
(C:\Program Files (x86)\PostgreSQL\9.1\bin>). El carcter "%", por tanto, no tenemos que escribirlo.

Con esa sentencia se conecta uno con la base de datos con los parmetros por defecto. Es decir, al
servidor local, con usuario y password.

Lo ms normal es que tengamos que indicar algn otro dato para conectar con la base de datos, como
el usuario, la clave o la direccin del servidor con el que queremos conectar. La sintaxis sera la
siguiente:

1 Ing. Gabriel Demera Ureta MgSc.


Aplicaciones de Base de Datos

psql -U usuario -d base_datos -p Puerto -h IP_servidor -f


archivo_esquema

psql -U postgres -d generalizacion -p 5432 -h 192.168.0.111

Si deseamos conectarnos a la base de datos en local y con nombre de usuario postgres tendramos que
escribir:
% psql -U postgres

Lo primero que nos preguntar ser el password para el usuario postgres. Una vez introducida la
clave, ya estaremos dentro de la lnea de comandos de PostgreSQL. Con ello el prompt cambiar a
algo como esto:
postgres=#

DENTRO DE LA CONSOLA DE PostgreSQL


Una vez dentro, tendremos a nuestra disposicin todas las sentencias de PostgreSQL para el trabajo
con la base de datos y el lenguaje SQL.

Lo ms normal es que necesites conectarte con una base de datos en concreto, de entre todas las que
puedes tener creadas en tu servidor PostgreSQL. Eso se hace con el comando \c, seguido del nombre
de la base de datos que deseas conectar.
postgres=# \c mibasedatos;
mibasedatos =#

Esto nos conectara con la base de datos llamada "mibasedatos".

ATENCIN: Hay que fijarse que todas las sentencias dentro de la lnea de comandos de PostgreSQL
acaban en ";" a excepcin \caracter. Si no colocamos el punto y coma, lo ms seguro es que NO se
ejecute el comando y nos vuelva a salir el prompt para que sigamos introduciendo el comando. Si lo
que queramos era ejecutar la sentencia que habamos escrito antes, con simplemente entrar el ";"
ser suficiente. Es decir, no debemos escribir de nuevo la sentencia entera, slo el ";" y volver a
apretar "enter".

Si queremos ver una lista de las bases de datos alojadas en nuestro servidor podemos escribir el
comando \l. As:
postgres=# \l

Con esto nos mostrara una lista de las bases de datos de nuestro servidor. Algo como esto:
postgres=# \l

2 Ing. Gabriel Demera Ureta MgSc.


Aplicaciones de Base de Datos

Si queremos crear una base datos, podremos hacerlo con el comando "create database" seguido del
nombre de la nueva base de datos.
postgres=# create database miprueba;

Si queremos luego usar esa base de datos escribiramos:


postgres=# \c miprueba;

Lgicamente, esta base de datos recin creada estar vaca, pero si estuviramos usando una base de
datos ya creada y queremos ver las tablas que tiene escribiramos el comando "\dt".
postgres=# \dt Lista solo tablas
postgres=# \d Lista tablas y vistas
Si no hay tablas, nos dir algo como " No se encontraron relaciones.", pero si tenemos varias tablas
dadas de alta en la base de datos que estamos usando, nos saldr una lista de ellas:
miprueba=# \dt;

Ahora, si deseamos obtener informacin sobre una tabla, para saber qu campos tiene y de qu tipo,
podremos utilizar el comando \d seguido del nombre de la tabla.

miprueba=# \d estudiantes;

Tambin es posible utilizar:


miprueba=# \d+ estudiantes;

En este apartado se resumen las principales sentencias SQL que pueden ser utilizadas en el gestor de
base de datos PostgreSQL.

PARA SALIR DE LA LNEA DE COMANDOS DE POSTGRESQL


Una vez hemos terminado de trabajar con PostgreSQL, si queremos cerrar la conexin con el
servidor, simplemente escribimos \q desde el promptuario:
miprueba=# \q

CREACIN DE TABLAS

Una tabla es utilizada para organizar y presentar informacin. Las tablas se componen de filas y
columnas de celdas que se pueden rellenar con informacin, las tablas se componen de dos
estructuras:

Registro: se la podra definir como una fila que contiene datos de los mismos
tipos que las dems filas. Ejemplo: en una tabla que tiene columnas como
nombres y direcciones, cada fila contendr un nombre y una direccin.
Campo: es cada una de las columnas que forman la tabla. Contienen datos de
tipo diferente a los de otros campos. En el ejemplo anterior, un campo contendr
un tipo de datos nico, como una direccin, o un nmero de telfono, un nombre,
etc.
3 Ing. Gabriel Demera Ureta MgSc.
Aplicaciones de Base de Datos

Cada tabla creada debe tener un nombre nico en la cada Base de Datos, hacindola accesible
mediante su nombre o su seudnimo (Alias). Las tablas son los objetos principales de bases de datos
que se utilizan para guardar gran cantidad de datos.

TIPOS DE DATOS DE POSTGRESQL

Despus de la fase de diseo de una base de datos, en necesario crear las tablas correspondientes
dentro de la base de datos. Para cada campo o columna de cada una de las tablas, es necesario
determinar el tipo de datos que contiene, para de esa forma ajustar el diseo de la base de datos, y
conseguir un almacenamiento ptimo con la menor utilizacin de espacio. Los tipos de datos que
puede haber en un campo, se pueden agrupar en tres grandes grupos:

1.- TIPOS NUMRICOS:


NOMBRE ALIAS DESCRIPCION
bigint int8 entero con signo de ocho bytes
bigserial serial8 entero autoincremental de ocho bytes
bit [ (n) ] cadena de bits de longitud fija
bit varying [(n)] varbit cadena de bits de longitud variable
boolean bool Booleano lgico (verdadero/falso)
box rectngulo en un plano
bytea datos binarios ("arreglo de bytes")
character varying [(n)] varchar[(n)] cadena de caracteres de longitud variable
character [ (n) ] char [(n)] cadena de caracteres de longitud fija
cidr direccin de red IPv4 o IPv6
circle circulo en un plano
date fecha de calendario (ao, mes, da)
nmero de punto flotante de precisin doble
double precision float8
(8 bytes)
inet direccin de equipo de IPv4 o IPv6
integer int, int4 entero con signo de cuatro bytes
interval [fields] [(p)] lapso de tiempo
line linea infinita en un plano
lseg segmento de linea en un plano
macaddr Direccin MAC (Media Access Control)
money importe monetario
numeric [(p,s)] decimal[(p,s)] numrico exacto de precisin seleccionable
path camino geomtrico en un plano
point punto geomtrico en un plano
polygon camino cerrado geomtrico en un plano
nmero de punto flotante de precisin simple
real float4
(4 bytes)
smallint int2 entero con signo de dos bytes
serial serial4 entero autoincremental de cuatro bytes
text cadena de caracteres de longitud variable
time [(p)][without time
zone]
hora del da (sin zona horaria)
time [(p)]with time zone timetz gora del da, incluyendo zona horaria
4 Ing. Gabriel Demera Ureta MgSc.
Aplicaciones de Base de Datos

timestamp [(p)][without
time zone]
fecha y hora (sin zona horaria)
timestamp [(p)] with
time zone
timestamptz fecha y hora, incluyendo zona horaria
tsquery consulta de bsqueda de texto
tsvector documento de bsqueda de texto
instantnea de ID de transaccin a nivel de
txid_snapshot
usuario
uuid identificador universalmente nico
xml datos XML
Compatibilidad: Los siguientes tipos de datos son especificados por SQL: bigint, bit, bit
varying, boolean, char, character varying, character, varchar, date, double precision,
integer, interval, numeric, decimal, real, smallint, time (con o sin zona horaria), timestamp
(con o sin zona horaria), xml.

Cada tipo de datos tiene una representacin externa determinada por sus funciones de entrada y
salida. Muchos de los tipos de datos incorporados tienen formatos externos obvios. Sin embargo,
varios tipos o son nicos de PostgreSQL, como los caminos geomtricos, o tienen varios formatos
posibles, como los tipos de fecha y hora. Algunas de las funciones de entrada y salida no son
invertibles, por ej., el resultado de una funcin de salida podra perder exactitud cuando se compara
con la entrada original.

TIPOS FECHA:

Postgresql soporta un conjunto completo de tipos SQL de datos de fecha y de hora, demostrado en la
siguiente tabla:

Table 8-9. Tipos de Fecha/tiempo

Nombre Tamao Descripcin Valor bajo Valor alto Resolucin


timestamp [ (p) ] 1 microsegundo /
8 bytes Fecha y hora 4713 BC 5874897 AD
[ sin zona horaria ] 14 dgitos
timestamp [ (p) ] Fecha y hora con 1 microsegundos /
8 bytes 4713 BC 5874897 AD
con zona horaria zona horaria 14 dgitos
-178000000 178000000
interval [ (p) ] 12 bytes Intervalo de hora 1 microsegundo
aos aos
date 4 bytes Slo fecha 4713 BC 32767 AD 1 da
time [ (p) ] [ sin
8 bytes Slo hora del da 00:00:00.00 23:59:59.99 1 microsegundo
zona horaria]
time [ (p) ] con Horas del da con 23:59:59.99-
12 bytes 00:00:00.00+12 1 microsegundo
zona horaria zona horaria 12

Nota: Antes de la versin 7.3, el escribir solamente timestamp era equivalente a escribir
timestamp with time zone. Esto fue cambiado para compatibilidad con SQL estndar.

5 Ing. Gabriel Demera Ureta MgSc.


Aplicaciones de Base de Datos

time, timestamp, e interval aceptan un valor de presicin opcional p que especifica el nmero de
digitos fraccionales almacenados en el campo de segundos. Por defecto, no hay un valor fijo explcito
en la presicin. El rango permitido de p va desde 0 a 6 para los tipos timestamp e interval.

Nota: Cuando los valores de timestamp son almacenados como enteros de 8 bytes (es el por
defecto), la precisin de microsegundos est disponible para el rango completo de valores. Cuando
los valores timestamp son almacenados como de presicin doble de coma flotante (una opcin en
desuso en tiempo de compilacin), la presicin efectiva lmite es menor de 6. Los valores timestamp
son almacenados con los segundo antes o despus de la medianoche del 2000-01-01. Cuando los
valores timestamp son implementados usando nmeros de coma flotante, la presicin de
microsegundos es acertada para las fechas cercanas al 2000-01-01 y perder presicin para fechas
ms lejanas. Vea que utilizando tipos en coma-flotante permite un rango ms grande de valores que
pueda representar el timestamp mostrado arriba: desde 4713 A.C. hasta 5874897 D.C.

TIPOS DE CADENA:

Los tipos de datos del motor de base de datos gratuito y open source PostgreSQL de tipo carcter
son:

Nombre Descripcin
character varying(n),
De longitud variable, con lmite
varchar(n)
character(n), char(n) De longitud fija
text De longitud variable, ilimitado

La sintaxis general para crear una tabla es:


CREATE [ TEMPORARY | TEMP ] TABLE table (
column type
[ NULL | NOT NULL ] [ UNIQUE ] [ DEFAULT value ]
[column_constraint_clause | PRIMARY KEY } [ ... ] ]
[, ... ]
[, PRIMARY KEY ( column [, ...] ) ]
[, CHECK ( condition ) ]
[, table_constraint_clause ]
) [ INHERITS ( inherited_table [, ...] ) ]

Supongamos que se desea crear una tabla de nombre PRUEBA cuya clave primaria es id (campo que
identifica unvocamente a la tabla) que va incrementando su valor automticamente cada vez que
insertamos un nuevo valor en la tabla, un campo nombre que es de tipo cadena de caracteres de
como mximo 60 caracteres y un campo sexo que es de tipo cadena de caracteres:
CREATE TABLE prueba(
ID SERIAL NOT NULL PRIMARY KEY,
NOMBRE VARCHAR(60) DEFAULT NULL,
sexo VARCHAR(1)
);
Otra forma de crearla sera:
CREATE TABLE prueba2(
ID BIGSERIAL NOT NULL,
NOMBRE VARCHAR(60),
sexo VARCHAR(1),
6 Ing. Gabriel Demera Ureta MgSc.
Aplicaciones de Base de Datos

primary key(id)
);

Asumamos que necesitamos crear una tabla y despus se necesitar realizar algunos cambios:

CREATE TABLE usuario (


ID_USUARIO SERIAL PRIMARY KEY,
NOMBRE VARCHAR(50) NOT NULL,
DIRECCION VARCHAR(50) NOT NULL,
CIUDAD VARCHAR(20) NOT NULL,
EDAD INTEGER NOT NULL
);
Asumiendo que se le olvid crear un campo fecha de registro a la tabla usuario usted tendra que
utilizar el comando ALTER TABLE, por ejemplo:
ALTER TABLE usuario ADD COLUMN Fecha_Registro DATE;
\d usuario;
Para aadir un campo 'email' como un ndice del tipo nico (no puede haber dos iguales).
ALTER TABLE usuario ADD email varchar(50);
ALTER TABLE usuario ADD UNIQUE(email);
\d usuario;

Para modifica el tamao de la columna como email, se puede utilizar:


ALTER TABLE usuario ALTER COLUMN email TYPE varchar(150);
\d usuario;

Cambia el nombre de la columna 'ciudad' al nuevo nombre 'poblacion':


ALTER TABLE usuario RENAME COLUMN ciudad TO poblacion;
\d usuario;

Para cambia solo el tipo de datos de la columna 'edad' y especifica que no admite nulos:
ALTER TABLE usuario ALTER COLUMN edad TYPE decimal (6,2);
\d usuario;

Para eliminarle a una columna, la restriccin de no aceptar valores nulos


ALTER TABLE usuario ALTER COLUMN direccion DROP NOT NULL;
\d usuario;

Modificar la columna para que a partir de ahora no acepte valores nulos


ALTER TABLE usuario ALTER COLUMN email SET NOT NULL;
\d usuario;

En la tabla 'usuario' cualquiera que sea la columna que tenga 'SERIAL' empezar a autogenerarse de
forma secuencial por el gestor de PostgreSQL, s usted desea cambiar dicha secuencia de forma que
los nuevos registros comiencen a partir de '1000' o cualquier otro nmero, debemos realizar lo
siguiente:
1. Para comprobar la funcionalidad de la secuencia ingresaremos un registro y mostraremos su serie:
INSERT INTO usuario(nombre,direccion,poblacion,edad,fecha_registro,email)
VALUES(Pablo Martinez,ABC,Potoviejo,18,2014/07/10,pmartimez@utm.edu.ec);
SELECT * FROM usuario;
2. Usted debe crear un archivo de secuencia de la siguiente manera
CREATE SEQUENCE id_usuario_seq start 1000;
3. Usted debe modificar la tabla para que utilice en archivo de secuencia

7 Ing. Gabriel Demera Ureta MgSc.


Aplicaciones de Base de Datos

ALTER TABLE usuario ALTER id_usuario SET DEFAULT NEXTVAL(id_usuario_seq');


4. Una vez realizada la adaptacin usted podr insertar un nuevo registro y verificar los cambios
INSERT INTO usuario(nombre,direccion,poblacion,edad,fecha_registro,email)
VALUES(Alejandro,Limn,Potoviejo,22,2014/06/01,amontero@utm.edu.ec);
SELECT * FROM usuario;
Al aplicar la sentencia nmero 3 SELECT, notar que el primer registro ya no empezar por el ndice
1 sino que comenzar por el 1000.

S usted necesita cambiar el valor de secuencia una vez creada la secuencia, usted puede modificar el
valor de la siguiente forma:
SELECT setval('id_usuario_seq',1500,'false');
INSERT INTO usuario (nombre,direccion,poblacion,edad,fecha_registro,email)
VALUES(Ana,Forestal,Potoviejo,28,2014/06/11,abarba@utm.edu.ec);
Otra alternativa para modificar el valor inicial de secuencia podra ser:
ALTER SEQUENCE id_usuario_seq restart 2000;
INSERT INTO usuario(nombre,direccion,poblacion,edad,fecha_registro,email)
VALUES(Mara,Meja,Meja,18,2014/06/09,mperez@utm.edu.ec);
SELECT * FROM usuario;

Para eliminar la columna 'edad' de la tabla 'usuario', usted tendra que realizar lo siguiente:
ALTER TABLE usuario DROP COLUMN edad;
\d usuario;

Para eliminar varias columnas se utilizar el siguiente formato:


ALTER TABLE usuario DROP COLUMN edad , DROP COLUMN poblacion;

Renombrar la tabla
ALTER TABLE Usuario RENAME TO acceso;
\dt

8 Ing. Gabriel Demera Ureta MgSc.


Aplicaciones de Base de Datos

Para ejemplificar la creacin de una base de datos con sus respectivas tablas, tomaremos como
referencia el almacenamiento de registros datos para una unidad educativa, para el siguiente anlisis
considere que un alumno puede ser con el tiempo ser un padre de familia, o un docente de la misma
institucin:

DROP DATABASE IF EXISTS Unidad;

Create Database Unidad;

\c Unidad;

);
CREATE TYPE sex AS ENUM ('M', 'F');
CREATE TYPE ec AS ENUM ('S','C','D','V','U');

CREATE TABLE IF NOT EXISTS personas(


CREATE TABLE IF NOT EXISTS padres(
IdPersona SERIAL PRIMARY KEY,
IdPersona integer REFERENCES
ApellidoPaterno Varchar(50) NOT NULL,
personas(Idpersona),
ApellidoMaterno Varchar(50) NOT NULL,
cargasfamiliares integer,
Nombres Varchar(50) NOT NULL,
TelefonoTrabajo Varchar(15),
Direccion Varchar(150),
DireccionTrabajo varchar(100),
telefono varchar(15),
ocupacion varchar(80)
sexo sex,
);
FechaNacimiento date,
CREATE TABLE IF NOT EXISTS Estudiante(
EstadoCivil ec
IdPersona integer NOT NULL REFERENCES
);
personas(Idpersona),
IdPersonaPapa integer NOT NULL REFERENCES
CREATE TABLE IF NOT EXISTS profesores(
personas(Idpersona),
IdPersona integer REFERENCES
IdPersonaMama integer NOT NULL
personas(Idpersona),
REFERENCES personas(Idpersona),
cargo Varchar(50) NOT NULL,
Procedencia varchar(80)
Titulacion Varchar(50),
);
Fechaingreso date

9 Ing. Gabriel Demera Ureta MgSc.


PARA INGRESAR DATOS EN LAS TABLAS CREADAS:

Insert Into personas(ApellidoPaterno,ApellidoMaterno,Nombres,Direccion,telefono,sexo,FechaNacimiento,EstadoCivil)


Values ('Demera', 'Ureta', 'Gabriel', 'Cdla. Parque Forestal', '052123456','M','1974-03-18','C');
Insert Into personas(ApellidoPaterno,ApellidoMaterno,Nombres,Direccion,telefono,sexo,FechaNacimiento,EstadoCivil)
Values ('Montero', 'Zambrano','Paola', 'Cdla. Parque Forestal', '052123456','F','1979-04-23','C');
Insert Into personas(ApellidoPaterno,ApellidoMaterno,Nombres,Direccion,telefono,sexo,FechaNacimiento,EstadoCivil)
Values ('Espinoza','Alcvar', 'Elsa Argentina','Mejia', '052636111','F','1978/10/20','C');

Existe otra posibilidad de ingresar datos un poco ms cmoda:


Insert Into personas(ApellidoPaterno,ApellidoMaterno,Nombres,Direccion,telefono,sexo,FechaNacimiento,EstadoCivil)
Values ('Hidalgo', 'Villamar','Luis Ernesto','Limn', '052580113','M','1977/08/25','C'),
('Aveiga', 'Zambrano','Enma', 'Montecristi', '052636222','F','1974/06/18','C'),
('Zambrano','Franco', 'Luis Felipe','Garca Moreno y sucre','052632333','M','1976/04/10','C'),
('Lpez', 'Intriago','Blanca', 'Primero de Mayo', '052636444','F','1972/02/16','C'),
('Zedeo', 'Franco', 'Nora Alice', 'Morales y Rocafuerte', '052630555','F','1970/05/18','C'),
('Panta', 'Chica', 'Jos Vicente','Pedro Gual y morales','052580666','M','1972/10/12','C'),
('Ronquillo','Delgado','Ramn ','Av.Manab,los Mangos ','052636777','M','1974/12/30','C'),
('Vaca', 'Arteaga', 'Vctor Hugo','Av. Ajuela y morales', '052580888','M','1976/10/10','C'),
('Salazar', 'Montesinos','Claudia', 'Parroq. San Pablo', '052580999','F','1979/09/08','C'),
('Moncayo', 'Hidalgo', 'Flora', 'Cdla. Los tamarindos', '052636505','F','1979/07/28','C'),
('Garcs', 'Jorge', 'Humberto', 'Cdla. Los Bosques', '052580123','M','1980/02/20','C');

Los datos registrados pueden ser extrados de la tabla mediante el uso de la instruccin SELECT , por
ejemplo, si se necesita el listado se todas las personas con todos sus datos podramos hacerlo de la siguiente
forma:
SELECT IdPersona, ApellidoPaterno, ApellidoMaterno, Nombres, Direccion, telefono, sexo, FechaNacimiento,
EstadoCivil FROM personas;

Cuando se desea omitir el listado de todos los campos y obtener el mismo resultado usted puede hacer uso del
asterisco (*), por ejemplo:
SELECT * FROM personas;

Cuando se desea datos especficos usted puede utilizar de la lista de campos los que desee, por ejemplo, listar
los apellidos, nombres, direcciones y fechas de nacimiento de todos los ingresados:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Direccion, FechaNacimiento FROM personas;

S lo solicitado incluye la condicin de que solo sea para los de sexo femenino, se debe incluir la clusula
WHERE que permite agregar condiciones de clasificacin de datos, por ejemplo:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Direccion, FechaNacimiento
FROM personas
WHERE sexo=F;

Si necesitamos mostrar la lista con varones casados, quedara as:


SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Direccion, FechaNacimiento
FROM personas
WHERE sexo=M and EstadoCivil=C;

Si necesitamos la lista de personas mayores de 30 aos de edad, se tendra que conocer la fecha de
hoy asumamos que es 18 de agosto de 2013, si resto 30 aos quedara 1983/09/18 (este es el formato
de PostgreSQL), as que la instruccin quedara:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, telefono, sexo, FechaNacimiento
FROM personas
WHERE FechaNacimiento <1983/09/18;
Podemos cambiar los formatos de salida que se utilizan en PostgreSQL, por ejemplo, mostraremos
unidos los apellidos y el nombre, fecha de nacimiento con el formato da mes y ao, y sexo mostrar
masculino o femenino:
SELECT concat(personas.ApellidoPaterno, ' ',personas.ApellidoMaterno ,' ',personas.Nombres) As Estudiante, CASE
sexo WHEN 'F' then 'Femenino' ELSE 'Masculino' END As Sexo, to_char(FechaNacimiento, 'dd/mm/yyyy') AS
FechaNacimiento
FROM personas;

SELECT (personas.ApellidoPaterno || ' ' || personas.ApellidoMaterno || ' ' || personas.Nombres) As Estudiante, CASE
sexo WHEN 'F' then 'Femenino' ELSE 'Masculino' END As Sexo, to_char(FechaNacimiento, 'dd/mm/yyyy') AS
FechaNacimiento
FROM personas;

S se necesita ver las edades de todas las personas utilizaremos la funcin DATE_PART que
devuelve la diferencia en aos entre dos fechas, la clusula CURRENT_DATE devuelve la fecha
actual que registra el computador:
SELECT concat(personas.ApellidoPaterno, ' ',personas.ApellidoMaterno ,' ',personas.Nombres) As Nombre,
DATE_PART(year,current_date::date) - DATE_PART(year, fechanacimiento::date) as edad FROM personas;

SELECT upper(concat(personas.ApellidoPaterno, ' ',personas.ApellidoMaterno ,' ',personas.Nombres)) As Nombre,


date_part('year',age(FechaNacimiento)) as Edad FROM personas;
S necesitamos la lista ordenada por apellido paterno de forma ascendente o descendente se utilizara:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, telefono, sexo, FechaNacimiento
FROM personas ORDER BY ApellidoPaterno;

SELECT ApellidoPaterno, ApellidoMaterno, Nombres, telefono, sexo, FechaNacimiento


FROM personas ORDER BY ApellidoPaterno DESC;

Por defecto ordena ascendentemente o si prefiere puede utilizar la instruccin ASC, tambin puede
incluir sub rdenes agregando una lista separada por comas, por ejemplo:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, telefono, sexo, FechaNacimiento
FROM personas ORDER BY ApellidoPaterno ASC, ApellidoMaterno DESC;

Asumiendo que necesitamos las tres personas que tengan ms edad podramos utilizar:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, sexo, FechaNacimiento
FROM personas ORDER BY FechaNacimiento ASC LIMIT 3;

Para obtener un listado de aos de nacimiento sin que se repitan tendramos que realizar lo siguiente:
SELECT DISTINCT extract(year from FechaNacimiento) AS anio
FROM personas ORDER BY anio;

A menudo tenemos columnas que son cadenas de caracteres, y queremos buscar las cadenas que
contienen cierta palabra. Esto se realiza a travs de un nuevo tipo de condicin:
Nombre_de_columna LIKE cadena_de_caracteres.
Con LIKE puede usar los siguientes dos caracteres comodines en el patrn:
Carcter Descricin
% Coincidencia de cualquier nmero de caracteres, incluso cero caracteres
_ Coincide exactamente un carcter

Listar todas las personas cuyo nombre empieza con la letra E


SELECT ApellidoPaterno, ApellidoMaterno, Nombres, sexo, FechaNacimiento
FROM personas
WHERE Nombres LIKE E%;
Listar todas las personas cuya segunda letra del apellido paterno es E
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, sexo, FechaNacimiento
FROM personas
WHERE ApellidoPaterno LIKE _E%;

Listar todas las personas cuyo apellido paterno o materno es Zambrano


SELECT ApellidoPaterno, ApellidoMaterno, Nombres
FROM personas
WHERE concat(ApellidoPaterno, ' ', ApellidoMaterno ,' ', Nombres) LIKE %Zambrano%;

Otra posibilidad de obtener el mismo resultado es:


(SELECT ApellidoPaterno, ApellidoMaterno, Nombres FROM personas WHERE ApellidoPaterno= Zambrano)
UNION ALL
(SELECT ApellidoPaterno, ApellidoMaterno, Nombres FROM personas WHERE ApellidoMaterno= Zambrano);

Si se necesita listar todas las personas cuyo apellido paterno no empiece con Z entonces quedara as:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, sexo, FechaNacimiento
FROM personas
WHERE ApellidoPaterno NOT LIKE Z%;
Para testear instancias literales de un carcter comodn, preceda el carcter con el carcter de escape.
Si no especifica el carcter ESCAPE , se asume '\' .

Cadena Descricin
\% Coincide un carcter '%'
\_ Coincide un carcter '_'
Si desea filtrar registros utilizando una lista de valores o palabras puede hacer uso de la clusula IN,
por ejemplo asumamos que queremos ver la lista de personas cuyo apellido paterno es VACA,
PANTA y SALAZAR tendramos que hacer lo siguiente:

SELECT ApellidoPaterno, ApellidoMaterno, Nombres, sexo, direccion


FROM personas
WHERE ApellidoPaterno IN (Vaca, Panta , Salazar);

SELECT ApellidoPaterno, ApellidoMaterno, Nombres, sexo, direccion


FROM personas
WHERE ApellidoPaterno=Vaca OR ApellidoPaterno=Panta OR ApellidoPaterno=Salazar;

Tambin puede mostrar todos excepto los anteriores


SELECT ApellidoPaterno, ApellidoMaterno, Nombres, sexo, direccion
FROM personas
WHERE ApellidoPaterno NOT IN (Vaca, Panta , Salazar);

En algn momento necesitaremos consultas que nos devuelva totales (1 solo registro), para ello se
utilizar unas funciones estandarizadas de clculo de registros COUNT(), SUM(), AVG(), MAX(),
NIM(), entre otros.

S deseamos conocer cuntas personas tiene registrada la tabla persona:


SELECT count(ApellidoPaterno) As Total_de_Personas
FROM personas;

Tambin podemos ver el promedio de edades de todas las personas registradas


SELECT AVG(DATE_PART(year,current_date::date) - DATE_PART(year, fechanacimiento::date)) AS
Promedio_Edades
FROM personas;
SELECT AVG(DATE_PART(year, age(FechaNacimiento))) AS Promedio_Edades
FROM personas;

Existe la posibilidad de utilizar agrupamientos para que puedan existir varios totales dependiendo de
las necesidades de agrupar, para esto se utiliza la clusula GROUP BY

Para conocer cuntas personas nacieron por ao de las que se encuentran registradas en nuestra tabla
podramos realizar lo siguiente:

SELECT extract(year from FechaNacimiento), COUNT(extract(year from FechaNacimiento)) AS


N_Personas_Nacidas FROM Personas
GROUP BY extract(year from FechaNacimiento)
ORDER BY COUNT(extract(year from FechaNacimiento)) ;

Si se necesita conocer el nmero de persona clasificados por sexo:


SELECT CASE sexo WHEN 'F' then 'FEMENINO' ELSE 'MASCULINO' END As Sexo, count(*) As
Total_de_Personas
FROM personas
GROUP BY Sexo;

SELECT CASE estadocivil WHEN 'C' then 'CASADO' WHEN 'S' then 'SOLTERO' WHEN 'D' then 'DIVORCIADO'
WHEN 'V' then 'VIUDO' ELSE 'UNION LIBRE' END As Estado_Civil, count(*) As Total_de_Personas
FROM personas
GROUP BY estadocivil;
LAS SUBCONSULTAS

Una subconsulta, es una sentencia SELECT que aparece dentro de otra sentencia SELECT que
llamaremos consulta principal. Se puede encontrar en la lista de seleccin, en la clusula WHERE
o en la clusula HAVING de la consulta principal.

Una subconsulta tiene la misma sintaxis que una sentencia SELECT normal exceptuando que aparece
encerrada entre parntesis, no puede contener la clusula ORDER BY, ni puede ser la UNION de
varias sentencias SELECT, adems tiene algunas restricciones en cuanto a nmero de columnas
segn el lugar donde aparece en la consulta principal.

Cuando se ejecuta una consulta que contiene una subconsulta, la subconsulta se ejecuta por cada
fila de la consulta principal.

Se aconseja no utilizar campos calculados en las subconsultas, ralentizan la consulta.

Las consultas que utilizan subconsultas suelen ser ms fciles de interpretar por el usuario.

Para realizar las siguientes prcticas agregaremos ms registros a las tablas Personas y Profesores:
INSERT INTO Personas
(ApellidoPaterno,ApellidoMaterno,Nombres,Direccion,telefono,sexo,FechaNacimiento,EstadoCivil)
VALUES ('Falcones','Canchingre','ngela', 'Cdla. Los tamarindos', '052636456','F','1982/06/18','C'),
('Mora', 'Hidalgo', 'Octavio', 'Cdla. Ceibos del Norte','052360789','M','1970/05/08','C'),
('Delgado', 'Ramirez', 'Maricela', 'Cdla. Ceibos del Norte','054511133','F','1996/08/12','C'),
('Zambrano','Delgado', 'Javier', 'Cdla. Los Bosques', '052456123','M','1984-05-28','D'),
('Cardenas','Flores', 'Ana Mara', 'Eloy Alfaro y Plaza', '052100456','F','1991-03-18','D'),
('Basurto', 'Cedeo', 'Dolores', 'Cdla. Los Mangos', '052390987','F','1971/04/01','C'),
('Zambrano','Lpez', 'Jos', 'parroq. San Placido', '052111654','M','1973/03/30','C'),
('Montesdeoca','Ureta','Elena ', 'Cdla. Forestal', '052222321','F','1974/01/25','C'),
('Faras', 'Salazar', 'Joel', 'Cdla. Terra Nostra', '052333254','M','1979/08/13','C'),
('Delgado', 'Manuel', 'Benedicto', 'Cdla. Los Bosques', '052444157','M','1979/09/23','C'),
('Navarrete','Ormaza', 'Yolanda', 'Cdla. Los tamarindos', '052534876','F','1981/01/10','C'),
('Giler', 'Meja', 'Scrates', 'Cdla. Ceibos del Norte','052778654','M','1985/03/18','C'),
('Mendieta','Vera', 'Juan Carlos','No Registrada', '052580505','M','1974/05/18','C'),
('Brines', 'Zambrano','Gema', '25 de Diciembre', '052654987','F','1980/04/14','S'),
('Moya', 'Loor', 'Fernando', 'Morales', '052654987','M','1982/09/28','S'),
('Arias', 'De la Cruz','Ivan', 'Ramos y Duarte', '321654987','M','1990/08/25','V'),
('Andrade', 'Castro', 'Viviana ', 'San Placido', '052222233','F','2000/03/01','S'),
('Benitez', 'Sabando', 'Carmen', 'Calderon', '053333233','F','2001/06/30','S'),
('Burbano', 'Vera', 'Jos ', 'Rio Chico', '054444233','M','1995/02/17','S'),
('Zambrano','Cardenas', 'Mara Jos','Cdla. Bosques', '054561233','F','1999/06/10','S'),
('Zambrano','Cardenas','Eduardo', 'Rio Chico', '051111233','M','1995/03/01','S'),
('Zambrano','Falcones','Paola', 'Los tamarindos', '054871233','F','2000/03/18','S'),
('Demera', 'Montero', 'Alejandro', ' Cdla Parque Forestal', '055551233','M','2001/01/20','S'),
('Mora', 'Delgado', 'Miguel ngel','18 de octubre', '056666233','M','2002/03/15','S'),
('Zambrano','Bazurto', 'Leonardo', 'Los Mangos', '057771233','M','2000/08/11','S'),
('Zambrano','Bazurto', 'Enrique ', 'Los Tamarindos', '058888233','M','2002/11/11','S'),
('Faras', 'Montesdeoca','Francisco','Los Bosques', '059999233','M','1996/03/19','S'),
('Delgado','Navarrete','Carlos Luis','San Placido', '050001233','M','2001/12/31','S'),
('Giler', 'Briones', 'LilY Anabel', 'Cdla Forestal', '051112222','F','1990/03/21','S'),
('Mendieta','Andrade', 'Marcos', 'Cdla Primero de Mayo', '051114444','M','1993/10/10','S'),
('Moya', 'Aveiga', 'Antonio', 'Parroquia Calderon', '051115555','M','2000/05/25','S'),
('Arias', 'Benitez', 'John Jairo', 'Va a Rio Chico', '051116666','M','2002/07/30','S'),
('Burbano', 'Moncayo', 'Pedro Andrs','Floron 1', '051117777','M','1998/01/17','S'),
('Demera', 'Montero','Mara Gabriela',' Cdla Parque Forestal','051118888','F','1995/05/09','S'),
('Mora', 'Delgado', 'Virginia Yessenia','Parr. Rio Chico','051119999','F','2001/06/04','S'),
('Zambrano','Falcones','Jos Daniel','San Alejo', '051111000','M','1992/07/15','S'),
('Moya', 'Aveiga', 'David Fabian','18 de octubre', '051111545','M','2000/09/21','S'),
('Giler', 'Briones', 'Fabricio', 'San Placido', '051111129','M','1994/11/12','S'),
('Mendieta','Andrade','Lourdes', 'Km1 va a rocafuerte', '051119876','F','2002/11/03','S'),
('Faras', 'Montesdeoca', 'Junior Jos','Los Angeles', '051115433','M','1998/12/18','S');

INSERT INTO Profesores (IdPersona, cargo, Titulacion, Fechaingreso)


VALUES (1, 'Profesor', 'Ingeniero en Sistemas', '2005-10-23'),
(2, 'Inspector', 'Ldca en Educacin bsica', '2005-10-23'),
(3, 'Profesor', 'Lcda. En Literatura', '2002/01/10'),
(4, 'Profesor', 'Ingeniero Industrial', '2002/05/15'),
(5, 'Profesor', 'Lcda. En Cultura Fsica', '2000/05/20'),
(6, 'Profesor', 'Lcdo. En Historia y Geografa','2000/04/10'),
(7, 'Profesor', 'Economista', '2001/09/08'),
(8, 'Profesor', 'Lcda. Ciencias Matemticas', '2001/04/18'),
(9, 'Profesor', 'Lcdo. En Idiomas', '2003/08/29'),
(10,'Profesor', 'Lcdo. En Psicologa Clnica', '2000/05/29'),
(11,'Profesor', 'Lcdo. En Laboratorio Qumico', '2003/04/10'),
(12,'Rector', 'Lcda. En Ciencias Matemticas','1999/03/10'),
(13,'Profesor', 'Lcda. En Educacin Bsica', '1999/10/15'),
(14,'Vicerector','ingeniero Civil', '1999/07/25');
INSERT INTO padres(IdPersona,cargasfamiliares,TelefonoTrabajo,DireccionTrabajo,ocupacion)
VALUES (1, 2,'052000111','Av. Urbina y Che Guevara','Profesor'),
(2, 1,'052345678','Alajuela y Quito', 'Profesora'),
(16,2,'052176892','Manta', 'Abogado'),
(17,3,'052987654','Av. Manab y America', 'Comerciante'),
(18,2,'052670158','Charapot', 'Agricultor'),
(19,4,'052182637','Km 1 Via a Manta', 'Secretaria'),
(6, 2,'052123123','Alajuela y Quito', 'Profesor'),
(15,2,'052123321','Morales y Rocafuerte', 'Diseadora de carteles'),
(20,3,'052987654','Amrica y Urbina', 'Foto Copiador'),
(21,3,'052987654','Amrica y Urbina', 'Foto Copiador'),
(22,4,'', 'Cdla. Parque Forestal', 'Ama de Casa'),
(23,4,'', 'Los Almendros', 'Jardinero'),
(24,2,'052111999','Km1 via a crucita', 'Maquinista'),
(25,2,'052222333','Km1 via a crucita', 'Policia'),
(26,3,'052098765','Coop. Portoviejo', 'Chofer'),
(28,3,'052654876','Via a Crucita altura de gasolinera Univ.','Comerciante'),
(27,2,'', 'Manta', 'Capitan de Barco'),
(31,2,'052564876','San Placido', 'Ama de Casa'),
(29,1,'', 'Ciudad de Portoviejo', 'Taxista'),
(5, 1,'052345678','Alajuela y Quito', 'Profesora'),
(30,3,'052630123','Av. Universitaria y Che Guevara','Ingeniero Civil'),
(32,3,'052987396','18 de Octubre y Pedro Gual','Recepcionista'),
(33,2,'052198823','Amrica y Urbina N1432', 'Electricista'),
(13,2,'052345678','Alajuela y Quito', 'Profesora');

INSERT INTO Estudiante(IdPersona,IdPersonaPapa,IdPersonaMama,Procedencia)


VALUES (37,1,2,'Escuela 12 de Marzo'),
(50,6,15,'Unidad Educativa Arco Iris'),
(36,6,15,'Unidad Educativa Arco Iris'),
(49,16,17,'Escuela 12 de Marzo'),
(38,16,17,'Escuela 12 de Marzo'),
(35,18,19,'Unidad Edutativa Manta'),
(34,18,19,'Unidad Edutativa Manta'),
(39,21,20,'Escuela Naval'),
(40,21,20,'Escuela Naval'),
(41,23,22,'Unidad Educativa Arco Iris'),
(54,23,22,'Unidad Educativa Arco Iris'),
(42,24,25,'Escuela Reales Tamarindos'),
(43,26,28,'Escuela 12 de Marzo'),
(52,26,28,'Escuela 12 de Marzo'),
(53,27,31,'Escuela Naval'),
(44,27,31,'Escuela Naval'),
(45,29,5,'Unidad Edutativa Manta'),
(51,29,5,'Unidad Edutativa Manta'),
(46,30,32,'Escuela Reales Tamarindos'),
(47,33,13,'Escuela Reales Tamarindos'),
(48,1,2,'Escuela 12 de Marzo');

Para mostrar el listado de personas que son autoridades en la institucin se lo realizara as:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres
FROM personas
WHERE IdPersona IN (SELECT IdPersona FROM Profesores WHERE cargo <>Profesor);

Para mostrar el nombre y apellidos del Rector de la institucin se lo realizara as:


SELECT ApellidoPaterno, ApellidoMaterno, Nombres
FROM personas
WHERE IdPersona = (SELECT IdPersona FROM Profesores WHERE cargo=Rector);

Para mostrar lo nombres y apellidos de los profesores que son padres de familia en la institucin se lo
realizara as:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres
FROM personas
WHERE IdPersona IN (SELECT IdPersona FROM Padres WHERE ocupacion like Profe%);

Si necesita mostrar la lista de estudiantes cuyas madres sean profesoras de la institucin quedara as:
SELECT ApellidoPaterno, ApellidoMaterno, Nombres
FROM personas
WHERE IdPersona IN (SELECT IdPersona FROM Estudiante WHERE IdPersonaMama IN (SELECT idpersona
FROM Profesores)) ORDER BY ApellidoPaterno;

Las subconsultas permiten comparar, desde la consulta principal con datos extrados desde la misma
u otras tablas, pero no se pueden mostrar los campos de las subconsulta con los campos de la
consulta principal.

CONSULTAS MULTI-TABLAS
Hasta ahora todas las consultas que hemos usado se refieren a mostrar datos de slo una tabla, pero
tambin es posible hacer consultas usando varias tablas en la misma sentencia SELECT.

Este proceso permite realizar dos operaciones de lgebra relacional: el producto cartesiano y la
composicin.

Producto cartesiano.- Este es un operador binario, se aplica a dos relaciones y el


resultado es otra relacin. El resultado es una relacin que contendr todas las
combinaciones de las tuplas de los dos operandos.

Esto es: si partimos de dos relaciones, R y S, cuyos grados son n y m, y cuyas cardinalidades a y b, la
relacin producto tendr todos los atributos presentes en ambas relaciones, por lo tanto, el grado ser
n+m. Adems la cardinalidad ser el producto de a y b.
Para ver un ejemplo usaremos dos tablas inventadas al efecto:

tabla1(id, nombre, apellido)


tabla2(id, nmero)
tabla1
id nombre apellido
15 Fulginio Liepez
26 Cascanio Suanchiez

tabla2
id nmero
15 12345678
26 21222112
15 66525425

El resultado del producto cartesiano de tabla1 y tabla2: tabla1 x tabla2 es:

tabla1 x tabla2
id nombre apellido id nmero
15 Fulginio Liepez 15 12345678
26 Cascanio Suanchiez 15 12345678
15 Fulginio Liepez 26 21222112
26 Cascanio Suanchiez 26 21222112
15 Fulginio Liepez 15 66525425
26 Cascanio Suanchiez 15 66525425

Podemos ver que el grado resultante es 3+2=5, y la cardinalidad 2*3 = 6.

Composicin (Join).- Una composicin (Join en ingls) es una restriccin del producto
cartesiano, en la relacin de salida slo se incluyen las tuplas que cumplan una
determinada condicin.

La condicin que se usa ms frecuentemente es la igualdad entre dos atributos, uno de cada tabla.

<relacin1>[<condicin>]<relacin2>

Veamos un ejemplo. Partimos de dos relaciones:

tabla1(id, nombre, apellido)


tabla2(id, nmero)
tabla1
id nombre apellido
15 Fulginio Liepez
26 Cascanio Suanchiez

tabla2
id nmero
15 12345678
26 21222112
15 66525425

La composicin de estas dos tablas, para una condicin en que 'id' sea igual en ambas sera:

tabla1[tabla1.id = tabla2.id]tabla2
id nombre apellido t2.id nmero
15 Fulginio Liepez 15 12345678
26 Cascanio Suanchiez 26 21222112
15 Fulginio Liepez 15 66525425

Para aplicar el producto cartesiano en consultas multi-tablas crearemos otras entidades a nuestra base
de datos UNIDAD:

CREATE TABLE IF NOT EXISTS PeriodosLectivos(


IdPeriodoLectivo SERIAL,
FechaInicio date,
FechaFinal date,
Nombre varchar(30),
PRIMARY KEY(IdPeriodoLectivo)
);
CREATE TABLE IF NOT EXISTS Especialidades(
IdEspecialidad SERIAL PRIMARY KEY,
NombreEspecialidad varchar(50)
);
CREATE TABLE IF NOT EXISTS Cursos(
IdCurso SERIAL PRIMARY KEY,
Curso varchar(30)
);
CREATE TABLE IF NOT EXISTS Paralelos(
IdParalelo SERIAL PRIMARY KEY,
Paralelo varchar(30)
);
CREATE TABLE IF NOT EXISTS Matriculas(
IdMatricula SERIAL PRIMARY KEY,
IdPersonaEstudiante integer NOT NULL REFERENCES personas(Idpersona),
IdPeriodoLectivo integer NOT NULL REFERENCES periodosLectivos(IdperiodoLectivo),
IdEspecialidad integer NOT NULL REFERENCES Especialidades(IdEspecialidad),
IdCurso integer NOT NULL REFERENCES Cursos(IdCurso),
IdParalelo integer NOT NULL REFERENCES paralelos(Idparalelo),
IdPersonaRepresentante integer NOT NULL REFERENCES personas(IdPersona),
Folder varchar(80)
);
INSERT INTO PeriodosLectivos(FechaInicio,FechaFinal,Nombre)
VALUES ('2012-03-15','2013-02-15','PERIODO 2012 - 2013'),
('2013-03-15','2014-02-15','PERIODO 2013 - 2014');
INSERT INTO Especialidades(NombreEspecialidad)
VALUES ('Educacion Bsica'),
('Bachillerato en Ciencias'),
('Bachillerato tcnico');
INSERT INTO Cursos(Curso) VALUES
('Primero'), ('Segundo'), ('Tercero'), ('Cuarto'), ('Quinto'), ('Sexto'), ('Septimo');
INSERT INTO Paralelos(Paralelo) VALUES ('A'), ('B'), ('C'), ('D');

INSERT INTO
Matriculas(IdPersonaEstudiante,IdPeriodoLectivo,IdEspecialidad,IdCurso,IdParalelo,IdPersonaRepresentante,Folder)
VALUES (46,2,1,7,1,30,'Archivador A 25'),
(47,2,1,7,1,33,'Archivador A 26'),
(42,2,1,7,1,24,'Archivador A 25'),
(37,2,1,7,1,1, 'Archivador A 26'),
(48,2,1,6,1,2 ,'Archivador A 27'),
(41,2,1,7,1,22,'Archivador A 27'),
(54,2,1,6,1,23,'Archivador A 28'),
(43,2,1,7,1,26,'Archivador A 28'),
(52,2,1,6,1,26,'Archivador A 29'),
(44,2,1,7,1,27,'Archivador A 29'),
(53,2,1,6,1,27,'Archivador A 30'),
(38,2,1,7,1,16,'Archivador A 30'),
(49,2,1,7,1,16,'Archivador A 31'),
(45,2,1,6,1,29,'Archivador A 31'),
(51,2,1,6,1,29,'Archivador A 32'),
(35,2,1,6,1,19,'Archivador A 32'),
(40,2,1,6,1,20,'Archivador A 33'),
(39,2,1,7,1,20,'Archivador A 33'),
(36,2,1,6,1,15,'Archivador A 34'),
(34,2,1,7,1,19,'Archivador A 34');

EJEMPLOS CON PRODUCTO CARTESIANO


S Aplicamos producto cartesiano a las tablas cursos y paralelos de nuestra base de datos la
instruccin sera:
SELECT * FROM Cursos, paralelos;
El resultado sera, que por cada registro de la tabla cursos se combinan con todos los registros de la
tabla paralelos, para el ejemplo anterior resultara si necesitramos todas las combinaciones posibles
entre dos tablas pero es necesario utilizar condiciones para ciertas necesidades de filtracin.

(Aplicando producto cartesiano con dos tablas) Si se necesita conocer la lista de profesores con sus
datos personales tendramos que hacer lo siguiente:
SELECT concat(ApellidoPaterno, , ApellidoMaterno, ,Nombres) AS Personas, cargo, titulacion
FROM Personas, Profesores
WHERE Personas.IdPersona=Profesores.IdPersona;

(Aplicando producto cartesiano con tres tablas) S necesitamos el listado de estudiantes matriculados
con sus respectivos representantes, tendramos:
SELECT concat(personas.ApellidoPaterno, ,
personas.ApellidoMaterno, , personas.Nombres) As
Estudiantes, Matriculas.IdMatricula As Matricula,
concat(personas_1.ApellidoPaterno, ,
personas_1.ApellidoMaterno, , personas_1.Nombres) As
Representante
FROM Personas AS personas_1, Personas, Matriculas
WHERE
personas.IdPersona = matriculas.IdPersonaEstudiante AND
personas_1.IdPersona = matriculas.IdPersonaRepresentante;

Cuando se utiliza dos veces la misma tabla, en este


caso es obligatorio definir al menos un alias de
tabla.

(Aplicando producto cartesiano con cuatro tablas) S necesitamos el listado de estudiantes


matriculados de sexto ao de bsica con sus respectivos representantes, tendramos:

SELECT concat(personas.ApellidoPaterno, , personas.ApellidoMaterno, ,


personas.Nombres) As Estudiantes, Matriculas.IdMatricula As Matricula,
concat(personas_1.ApellidoPaterno, , personas_1.ApellidoMaterno, ,
personas_1.Nombres) As Representante
FROM Personas AS personas_1, Personas, Matriculas, Cursos
WHERE
personas.IdPersona = matriculas.IdPersonaEstudiante AND personas_1.IdPersona =
matriculas.IdPersonaRepresentante AND Cursos.IdCurso = matriculas.IdCurso AND
Cursos.Curso='Sexto';

El INNER JOIN es otro tipo de composicin de tablas, permite emparejar filas de distintas tablas de
forma ms eficiente que con el producto cartesiano cuando una de las columnas de emparejamiento
est indexada. Ya que en vez de hacer el producto cartesiano completo y luego seleccionar la filas
que cumplen la condicin de emparejamiento, para cada fila de una de las tablas busca directamente
en la otra tabla las filas que cumplen la condicin, con lo cual se emparejan slo las filas que luego
aparecen en el resultado.

La sintaxis es la siguiente:

tabla1 y tabla2 son especificaciones de tabla (nombre de tabla con alias o no, nombre de consulta
guardada), de las tablas cuyos registros se van a combinar.

col1, col2 son las columnas de emparejamiento.


Observar que dentro de la clusula ON los nombres de columna deben ser nombres cualificados
(llevan delante el nombre de la tabla y un punto).

Las columnas de emparejamiento deben contener la misma clase de datos, las dos de tipo texto, de
tipo fecha etc... los campos numricos deben ser de tipos similares. Por ejemplo, se puede combinar
campos AutoNumrico y Long puesto que son tipos similares, sin embargo, no se puede combinar
campos de tipo Simple y Doble. Adems las columnas no pueden ser de tipo Memo ni OLE.

comp representa cualquier operador de comparacin ( =, <, >, <=, >=, o <> ) y se utiliza para
establecer la condicin de emparejamiento.

Se pueden definir varias condiciones de emparejamiento unidas por los operadores AND y OR
poniendo cada condicin entre parntesis.

Ejemplo:
Si necesitamos ver el listado de profesores, tendramos:
SELECT personas.ApellidoPaterno, personas.ApellidoMaterno, personas.Nombres, profesores.cargo,
profesores.Titulacion
FROM personas INNER JOIN profesores ON personas.IdPersona = profesores.IdPersona;

Se pueden combinar ms de dos tablas, en este caso hay que sustituir en la sintaxis una tabla por un
INNER JOIN completo.

Por ejemplo, s necesitamos el listado de todos los estudiantes matriculados con sus respectivos
representantes, tendramos:

SELECT personas.ApellidoPaterno, personas.ApellidoMaterno, personas.Nombres, matriculas.IdMatricula,


personas_1.ApellidoPaterno, personas_1.ApellidoMaterno, personas_1.Nombres, personas_1.Nombres
FROM personas AS personas_1 INNER JOIN (personas INNER JOIN matriculas ON personas.IdPersona =
matriculas.IdPersonaEstudiante) ON personas_1.IdPersona = matriculas.IdPersonaRepresentante;

Considerando el ejemplo desarrollado con producto cartesiano, s necesitamos el listado de


estudiantes matriculados de sexto ao de bsica con sus respectivos representantes, tendramos:

SELECT personas.ApellidoPaterno, personas.ApellidoMaterno, personas.Nombres, matriculas.IdMatricula,


personas_1.ApellidoPaterno, personas_1.ApellidoMaterno, personas_1.Nombres, personas_1.Nombres, cursos.Curso
FROM cursos INNER JOIN (personas AS personas_1 INNER JOIN (personas INNER JOIN matriculas ON
personas.IdPersona = matriculas.IdPersonaEstudiante) ON personas_1.IdPersona = matriculas.IdPersonaRepresentante)
ON cursos.IdCurso = matriculas.IdCurso
WHERE cursos.Curso='Sexto';
VISTAS EN POSTGRESQL

Las vistas tienen la misma estructura que una tabla: filas y columnas. La nica diferencia es que slo
se almacena de ellas la definicin, no los datos. Los datos que se recuperan mediante una consulta a
una vista se presentarn igual que los de una tabla. De hecho, si no se sabe que se est trabajando con
una vista, nada hace suponer que es as. Al igual que sucede con una tabla, se pueden insertar,
actualizar, borrar y seleccionar datos en una vista. Aunque siempre es posible seleccionar datos de
una vista, en algunas condiciones existen restricciones para realizar el resto de las operaciones sobre
vistas.
Una vista se especifica a travs de una expresin de consulta (una sentencia SELECT) que la calcula
y que puede realizarse sobre una o ms tablas. Sobre un conjunto de tablas relacionales se puede
trabajar con un nmero cualquiera de vistas.

La mayora de los SGBD soportan la creacin y manipulacin de vistas. Las vistas se crean cuando
se necesitan hacer varias sentencias para devolver una tabla final.

CREANDO UNA VISTA: Se emplea la sentencia CREATE VIEW, que incluye una
subconsulta (subquery) para determinar los datos a ser mostrados a travs de la vista.
Sintaxis:
CREATE [OR REPLACE] VIEW <vista>
[(<alias>[, <alias>] )]
AS <subconsulta>;
Dnde: OR REPLACE Se utiliza por si la vista ya estuviera creada anteriormente. En ese caso, la
sustituye por la nueva definicin. Por ejemplo si necesitamos crear una vista que muestra el listado de
profesores:
CREATE VIEW V_Lista_Profesores AS
SELECT ApellidoPaterno, ApellidoMaterno,Nombres, Titulacion
FROM profesores INNER JOIN personas ON profesores.IdPersona = personas.IdPersona
WHERE profesores.cargo Like 'Prof%'
ORDER BY ApellidoPaterno;

Si necesita chequear la creacin de la vista, utilice el comando \dv, para verificar el contenido de la
vista utilice (\d+ V_lista_Profesores;), para ver la vista ejecutada utilice el comando (SELECT *
FROM v_lista_profesores;), asumiendo que la vista tiene fallas, lo ms recomendable es volver a
ejecutar la vista utilizando la sintaxis OR REPLACE, por ejemplo:

CREATE OR REPLACE VIEW V_Lista_Profesores AS


SELECT ApellidoPaterno, ApellidoMaterno,Nombres, Titulacion
FROM profesores, personas
WHERE profesores.IdPersona = personas.IdPersona AND profesores.cargo Like 'prof%'
ORDER BY ApellidoPaterno;

Observe la codificacin de la vista y verificar los cambios.

VISUALIZAR LA ESTRUCTURA DE UNA VISTA:


\d+ <vista>;
Dnde: <vista> Es el nombre de la vista.
Listar las vistas existentes: SELECT * FROM USER_VIEWS;

Indicaciones y restricciones de uso:


- La subconsulta puede contener una sentencia SELECT de sintaxis compleja, incluyendo
combinaciones (JOIN), agrupamientos (GROUP BY), y subconsultas internas.

ELIMINANDO UNA VISTA


Cuando ya no se va a emplear ms, una vista puede ser eliminada del esquema de la base de datos
mediante la siguiente orden:
DROP VIEW <vista>;
Dnde: <vista> Es el nombre de la vista.
Ejemplo:
DROP VIEW EmpDepVentas;
Una vez desarrollada la vista, se la define como una tabla temporal, s usted utiliza el comando
SHOW TABLES; podr observarla como si se tratara de una tabla adicional, de hecho se puede
aplicar condiciones y relaciones sobre ellas, por ejemplo si necesitara clasificar la lista de estudiantes
por cursos y paralelos, tendramos:
#Vista que muestra el listado de estudiantes
CREATE VIEW V_Lista_Estudiantes AS
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Curso, Paralelo
FROM personas INNER JOIN (paralelos INNER JOIN (cursos INNER JOIN matriculas ON cursos.IdCurso =
matriculas.IdCurso)
ON paralelos.IdParalelo = matriculas.IdParalelo) ON personas.IdPersona = matriculas.IdPersonaEstudiante
ORDER BY ApellidoPaterno, ApellidoMaterno;

Para aplicar una condicin a la vista como si se tratara de una tabla se lo realiza de la siguiente
manera:
SELECT * FROM V_lista_Estudiantes WHERE curso='Septimo' AND paralelo=A;

Es importante entender que los campos a utilizar en la comparacin deben estar en el listado de la
vista.

El siguiente ejemplo se creara 2 vistas para ser utilizadas en una relacin, el resultado consiste en
mostrar la lista de estudiantes cuyos padres sean profesores:

CREATE VIEW V_DatosEstudiantes AS


SELECT idpersonapapa, concat(apellidopaterno,' ',apellidomaterno,' ',nombres) AS Estudiante
FROM Estudiante, Personas
WHERE Personas.idpersona=Estudiante.idpersona;

CREATE VIEW V_DatosProfesores AS


SELECT personas.IdPersona, concat(ApellidoPaterno, , ApellidoMaterno, ,Nombres) AS Profesor
FROM profesores, personas
WHERE profesores.IdPersona = personas.IdPersona AND profesores.cargo Like 'Prof%';

CREATE VIEW V_ProfesoresHijos AS


SELECT profesor, estudiante
FROM V_DatosProfesores,V_DatosEstudiantes
WHERE idpersona=idpersonapapa;

SELECT * FROM V_profesoreshijos;


USUARIOS Y PRIVILEGIOS
Crear un Usuario.- Es recomendable que todos los usuarios tengan claves de acceso, de lo contrario
tendrn dificultades para acceder al gestor:
CREATE USER fci WITH PASSWORD 123';

Si queremos probar en acceso con el usuario fci, el gestor le permitir acceder siempre y cuando
especifique la base de datos.
\q
C:\Program Files (x86)\PostgreSQL\9.1\bin> psql -U fci postgres

Los usuarios con accesos limitados tienen el siguiente promptuario (postgres=>), usted podr aplicar
comando de navegacin pero no podr crear ni modificar los datos de las diferentes bases de datos.
S queremos asignarle privilegios al usuario debemos entrar a la base de datos para poderlos aplicar,
para el ejemplo ingresaremos a la base de datos unidad con el usuario postgres:
C:\Program Files (x86)\PostgreSQL\9.1\bin> psql -U postgres unidad
unidad=# GRANT SELECT ON personas TO fci;

Otra forma de crear usuarios es mediante la siguiente instruccin:


CREATE ROLE fci2 WITH PASSWORD 123';
La diferencia es que el usuario fci2 no tendr permiso de conexin, esto se debe a que un rol puede
ser pensado como un usuario o un grupo de usuarios, Los roles se guardan en una tabla de catlogo
del sistema PostGreSQL llamada pg_roles, si quiere ver el listado de roles y usuarios creados aplique
la siguiente orden SELECT rolname FROM pg_roles; o aplicar la orden \dg o tambin \du.

Para crear el usuario fc2 con permiso de conexin se lo realizara de la siguiente forma:
CREATE ROLE fci2 WITH PASSWORD 123' LOGIN;

Para eliminar un usuario o un rol se aplica de igual forma apara ambos de la siguiente forma:
DROP ROLE fci2;
DROP USER fci2;

El manejo de roles en PostgreSQL permite diferentes configuraciones, entre ellas estn:


SUPERUSER/NOSUPERUSER. Puede crear y destruir objetos, asignar roles, iniciar replicas. Le est
permitido todo, por eso debe asignarse con cuidado.
CREATEDB/NOCREATEDB. Permite crear bases de datos.
CREATEROLE/NOCREATEROLE. Permite crear roles.
CREATEUSER/NOCREATEUSER. Permite crear usuarios.
LOGIN/NOLOGIN. Este atributo hace la diferencia entre un rol y usuario. Ya que el usuario tiene
permisos para acceder a la base de datos a traves de un cliente.
PASSWORD. Permite alterar la contrasea.
VALID UNTIL. Expiracin de usuarios.

Por ejemplo el siguiente usuario podr crear bases de datos, roles e iniciar replicaciones pero no
podr conectarse al servidor:
CREATE ROLE fci3 CREATEDB CREATEROLE REPLICATION;
\du
PRIVILEGIOS DE LOS OBJETOS EN UNA BASE DE DATOS

Cuando se crean objetos en una base de datos, a estos se les asigna un propietario, este propietario es
el nico que tiene control total sobre el objeto creado, es el nico que puede modificarlo y destruirlo
a gusto propio, es decir puede determinar qu hacer con el objeto y adems, puede asignar privilegios
a los diferentes roles sobre ese objeto.

Para asignar privilegios se usa el comando GRANT que habilita los privilegios en el objeto.
El comando REVOKE, quita los permisos sobre ese objeto.

Por ejemplo para permitir al rol profesor tener privilegios de consulta sobre la tabla Personas, se
puede ejecutar la siguiente sentencia:
GRANT SELECT ON Personas TO profesor;

Para quitar el privilegio de consultar la tabla en el rol profesor se ejecuta lo siguiente:


REVOKE UPDATE ON Personas TO profesor;

Existen varios tipos de privilegios que en s son los comandos que ejecutan una accin sobre el
objeto, la siguiente es una lista de los diferentes tipos de privilegios.

Tipos de privilegios:
SELECT Acceso a todas las columnas de una tabla/vista especfica.
INSERT Inserta datos en todas las columnas de una tabla especfica.
UPDATE Actualiza todas las columnas de una tabla especfica.
DELETE Elimina filas de una tabla especfica.
RULE Define las reglas de la tabla o vista.
ALL Otorga todos los privilegios.

TRUNCATE, REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORAR, EXECUTE, USAGE

La palabra clave ALL se usa para hacer referencia a todos los privilegios.
Cuando se hace referencia al usuario PUBLIC se hace referencia a todos los usuarios.

Si queremos asignar todos los privilegios al rol profesor sobre la tabla PAERSONAS se ejecuta lo
siguiente:
GRANT ALL ON Personas TO profesor;

Al igual si queremos que todos los usuarios tengan acceso a todos los privilegios de la tabla
PERSONAS, se ejecuta lo siguiente:
GRANT ALL ON Personas TO PUBLIC;

EJERCICIOS DE ADMINISTRACIN DE USUARIOS

Para este ejemplo crearemos un Rol, que agrupe todos los usuarios y no tenga ningn privilegio:
CREATE ROLE Autoridades NOLOGIN;

Ahora crearemos un usuario diferente para cada base de datos con privilegios para insertar/modificar:
CREATE USER Rector IN ROLE autoridades LOGIN ENCRYPTED PASSWORD '123';
CREATE USER Vicerector LOGIN ENCRYPTED PASSWORD '123';
CREATE USER administrador IN ROLE autoridades LOGIN ENCRYPTED PASSWORD
'123';

Note que el usuario Vicerector no se le agrego al rol de autoridades, para solucionar esto usted puede
aplicar la siguiente instruccin:
ALTER GROUP autoridades ADD USER vicerector;

Se crear una base de datos y aplicaremos un propietario a la misma:


CREATE DATABASE bdcolegio OWNER rector;
\c bdcolegio;

Ahora crearemos una tabla ejemplo:


CREATE TABLE tabla1 (id serial, nombre character varying(10));
\l

Como ejemplo ahora le quitaremos todos los privilegios sobre la tabla: tabla1 para los usuarios
rector y vicerrector:
REVOKE ALL ON tabla1 FROM rector;
REVOKE ALL ON tabla1 FROM vicerector;
Nota: Considere que se han quitado los privilegios sobre la table ms no sobre la base de datos

Los privilegios pueden agregarlos o quitarlos segn su administracin, ahora se otorgar privilegios de
consulta sobre la tabla tabla1 para el usuario rector
GRANT SELECT ON tabla1 TO rector;

S ejecutamos la instruccin: SELECT * FROM tabla1; de seguro no tendr problemas pero si intenta
insertar un registro como: INSERT INTO tabla1 values (1,Juan); tendr problemas porque no tiene
asignado el privilegio.

Como ejemplo otorgaremos privilegios para insertar datos sobre la tabla tabla1 al usuario
vicerector (requiere privilegios sobre la secuencia de la tabla)
GRANT INSERT ON tabla1 TO vicerector;
GRANT UPDATE ON tabla1_id_seq TO vicerector;

Una vez accedido al servidor como usuario vicerector usted podr ejecutar sin problemas: INSERT
INTO tabla1 values (1,Juan); pero no podr ver los datos ingresados porque el usuario no tiene
asignado el privilegio SELECT.

Para poder actualizar/eliminar un registro, se requiere tener privilegios de seleccin (requiere


privilegios sobre la secuencias de la tabla), podemos realizarlo de dos formas: individual o colectiva
S es invividual:
GRANT UPDATE ON tabla1 TO vicerector;
GRANT DELETE ON tabla1 TO vicerector;

S es de manera colectiva, se lo debe aplicar al rol:


GRANT SELECT ON tabla1 TO autoridades;
GRANT UPDATE ON tabla1 TO autoridades;
GRANT DELETE ON tabla1 TO autoridades;

OTROS COMANDOS TILES:


Listando todos los usuarios
\du
SELECT * FROM pg_user ;

Cambiando el Password de un Usuario.


ALTER USER fci with password abc;

Cambiando el nombre de un usuario


ALTER USER fci RENAME TO facultad;

Borrando Usuarios
drop user pilar;
Cambiando el propietario de una base de datos
ALTER DATABASE dbname OWNER TO newowner;

Asignando privilegios a un ROL


GRANT privilegio ON tabla TO rol;

Quitando privilegios a un ROL


REVOKE privilegio ON tabla FROM rol;

Si deseamos eliminar un usuario debemos ejecutar el siguiente comando:

DROP USER quinto;

El permiso de super usuario es el ms alto, con este usuario se podrn administrar todos los objetos
del motor de base de datos, para asignar este privilegio a un rol lo hacemos con el siguiente
comando:

ALTER ROLE quinto WITH SUPERUSER;

Para cambiar la contrasea de un usuario es necesario ejecutar el siguiente comando:


ALTER ROLE quinto WITH PASSWORD 'nuevaClave';

Para ver el listado de usuarios:

SELECT rolname FROM pg_roles;


Cuando recin hemos creado un usuario y queremos darle permisos a una base de datos existente,
podemos utilizar el siguiente comando:

GRANT ALL PRIVILEGES ON DATABASE BD TO usuario;


PROCEDIMIENTOS ALMACENADOS
En PostgreSql a diferencia de otros motores de bases de datos, no existe una distincin explicita entre
una funcin y un procedimiento almacenado. En PostgreSql solo existen funciones, claro que estas
pueden ser usadas a modo de una funcin o de un procedimiento almacenado. Adems de esta
diferencia con otros motores de bases de datos, es importante mencionar que PostgreSql nos ofrece
ms de un lenguaje para crear nuestros procedimientos almacenados, pudiendo elegir entre los
siguientes lenguajes:

PL/PgSQL, C, C++, Java PL/Java web, PL/Perl, plPHP, PL/Python, PL/Ruby, PL/sh, PL/Tcl,
PL/Scheme.
El lenguaje de procedimientos PL/pgSQL por ser el que se dispone. PL/pgSQL es muy parecido al
lenguaje PL/SQL utilizado por Oracle que es considerado por muchos, como uno de los mejores
lenguajes de procedimientos que se usar en PostgreSQL, es fcil de aprender, potente y siempre est
disponible.

Los objetivos de PL/pgSQL cuando se cre fueron:

Poder ser usado para crear funciones y disparadores (triggers)


Aadir estructuras de control al lenguaje SQL

Poder realizar clculos complejos

Heredar todos los tipos, funciones y operadores definidos por el usuario

Poder ser definido como un lenguaje "de confianza"

Fcil de usar

PL/pgSQL es un lenguaje estructurado en bloques. Como mnimo tendremos un bloque principal en


nuestro procedimiento almacenado y dentro de este podremos tener subbloques. Un bloque se define
de la siguiente manera Todo lo que est entre corchetes [] es opcional:

[ << etiqueta >> ]


[ DECLARE
declaraciones de variables ]
BEGIN
codigo
END [ etiqueta ];

Podemos definir e instalar un procedimiento en PL/pgSQL de la siguiente manera:

CREATE [ OR REPLACE ] FUNCTION


nombre_funcion([ [ argmodo ] [ argnombre ] argtipo [, ...] ])
RETURNS tipo AS $$
[ DECLARE ]
[ declaraciones de variables ]
BEGIN
Lneas de instrucciones;
END;
$$ LANGUAGE plpgsql
| IMMUTABLE | STABLE | VOLATILE
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
| COST execution_cost
| ROWS result_rows
| SET configuration_parameter { TO value | = value | FROM CURRENT }
;

Todas las opciones despus de "LANGUAGE plpgsql" tienen unos valores por defecto que
simplifican mucho la definicin de un procedimiento.

argmodo: El modo de un argumento puede ser IN, OUT, or INOUT. Por defecto se usa IN si no se
define.

argtipo: Los tipos que podemos utilizar son todos los disponibles en PostgreSQL y todos los
definidos por el usuario

declaraciones de variables: Las declaraciones de variables se pueden realizar de la siguiente manera


($n = orden de declaracin del argumento.):

nombre_variable ALIAS FOR $n;


nombre_variable [ CONSTANT ] tipo [ NOT NULL ] [ { DEFAULT | := } expresion ];

cantidad integer DEFAULT 32;


url varchar := 'http://mysite.com';
user_id CONSTANT integer := 10;
Lneas de instrucciones: en este artculo no tenemos espacio para ver cmo podemos escribir la parte
de cdigo de un procedimiento, pero se trata de ubicar el bloque de contenido lgico de la
codificacin que realizar diferentes tipos de procesos de control.

IMMUTABLE | STABLE | VOLATILE:

IMMUTABLE: Indica que la funcin no puede alterar a la base de datos y que siempre devolver el
mismo resultado, dados los mismos valores como argumentos. Este tipo de funciones no pueden
realizar consultas en la base de datos.

STABLE: Indica que la funcin no puede alterar a la base de datos y que siempre devolver el
mismo resultado en una consulta individual de una tabla, dados los mismos valores como
argumentos. El resultado podra cambiar entre sentencias SQL.

VOLATILE: Indica que la funcin puede devolver diferentes valores, incluso dentro de una consulta
individual de una tabla (valor por defecto)

CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT:


CALLED ON NULL INPUT: Indica que la funcin se ejecutar aunque algunos de los argumentos
sean NULL. El usuario tiene la responsabilidad de comprobar si algn argumento es NULL cuando
sea necesario tener esto en cuenta.(valor por defecto)

RETURNS NULL ON NULL INPUT / STRICT: Indican que la funcin no se ejecutar y


devolver el valor NULL si alguno de los argumentos es NULL.

SECURITY INVOKER | SECURITY DEFINER:

SECURITY INVOKER: Indica que la funcin se ejecutar con los privilegios del usuario que la
ejecuta (valor por defecto)

SECURITY DEFINER: Indica que la funcin se ejecutar con los privilegios del usuario que la
creo.

El resto de opciones son avanzadas y podr leer sobre ellas en la documentacin oficial de
PostgreSQL.

Vamos a ver unos cuantos ejemplos que nos aclaren un poco cmo definir, instalar y usar un
procedimiento almacenado en PL/pgSQL (estos ejemplos han sido comprobados en postgreSQL.

Creamos una base de datos para utilizarla con nuestros ejemplos:

postgres=# CREATE DATABASE practica;


postgres=# \c practica

Lo primero que tenemos que hacer es instalar el lenguaje plpgsql si no lo tenemos instalado.

CREATE PROCEDURAL LANGUAGE plpgsql;

Si queremos que cualquier usuario con acceso a la base de datos pueda usarlo sin tener que ser el
administrador postgres, tendremos que utilizar TRUSTED con el comando anterior.

CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql;

A continuacin creamos nuestro primer procedimiento. (Podemos copiar y pegar en el cliente psql,
escribirlo a mano usar el editor interno en psql (\e)):

CREATE OR REPLACE FUNCTION ejemplo() RETURNS integer AS $$


BEGIN
RETURN 104;
END;
$$ LANGUAGE plpgsql;

Este procedimiento se puede usar de la siguiente manera:


practica=# SELECT ejemplo();

Ahora definimos la funcin con un argumento:

CREATE OR REPLACE FUNCTION ejemplo(integer) RETURNS integer AS $$


BEGIN
RETURN $1;
END;
$$ LANGUAGE plpgsql;

Este procedimiento se podra haber escrito tambin de las siguientes maneras:

CREATE OR REPLACE FUNCTION ejemplo(numero integer) RETURNS integer AS $$


BEGIN
RETURN numero;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION ejemplo(integer) RETURNS integer AS $$


DECLARE
numero ALIAS FOR $1;
BEGIN
RETURN numero;
END;
$$ LANGUAGE plpgsql;

Este procedimiento se puede usar de la siguiente manera:

practica=# SELECT ejemplo(104);


Vamos a empezar a complicar un poco las cosas usando dos argumentos y definiendo algunas
variables:

CREATE OR REPLACE FUNCTION ejemplo(integer, integer) RETURNS integer AS $$


DECLARE
numero1 ALIAS FOR $1;
numero2 ALIAS FOR $2;

constante CONSTANT integer := 100;


resultado integer;
BEGIN
resultado := (numero1 * numero2) + constante;
RETURN resultado;
END;
$$ LANGUAGE plpgsql;

Este procedimiento se puede usar de la siguiente manera:

practica=# SELECT ejemplo(2,2);

SENTENCIAS DE CONTROL

SENTENCIA ( IF ... THEN) En PL/SQL solo disponemos de la estructura condicional IF. Su sintaxis
se muestra a continuacin:

IF expression THEN
statements
[ELSE
statements]
END IF

IF (expresion) THEN
-- Instrucciones
ELSIF (expresion) THEN
-- Instrucciones
ELSE
-- Instrucciones
END IF;

expression debe devolver un valor que al menos pueda ser adaptado en un tipo booleano, considere
los siguientes ejemplos:
CREATE OR REPLACE FUNCTION ejemplo_txt(integer, integer) RETURNS text AS $$
DECLARE
numero1 ALIAS FOR $1;
numero2 ALIAS FOR $2;
constante CONSTANT integer := 100;
resultado INTEGER;
resultado_txt TEXT DEFAULT 'El resultado es 104';
BEGIN
resultado := (numero1 * numero2) + constante;
IF resultado <> 104 THEN
resultado_txt := 'El resultado NO es 104';
END IF;

RETURN resultado_txt;
END;
$$ LANGUAGE plpgsql;

Este procedimiento se puede usar de la siguiente manera:

practica=# SELECT ejemplo_txt(2,2);


ejemplo_txt
---------------------
El resultado es 104
practica=# SELECT ejemplo_txt(2,3);
ejemplo_txt
------------------------
El resultado NO es 104
(1 row)

CREATE OR REPLACE FUNCTION cadena_mas_larga(text, text) RETURNS int4 AS '


DECLARE
in_uno ALIAS FOR $1;
in_dos ALIAS FOR $2;
lon_uno int4;
lon_dos int4;
result int4;
BEGIN
lon_uno := (SELECT LENGTH(in_uno));
lon_dos := (SELECT LENGTH(in_dos));
IF lon_uno > lon_dos THEN
RETURN lon_uno;
ELSE
RETURN lon_dos;
END IF;
END;
'LANGUAGE 'plpgsql';
Para probarlo:
SELECT cadena_mas_larga('Hola Mundo','Hola Universidad Tcnica de Manab');
Podramos seguir modificando y complicando nuestro ejemplo, pero como introduccin es suficiente
para tener una idea de cmo funciona.

Solo queda decir que en la definicin de un procedimiento no solo se tiene en cuenta el nombre del
mismo para diferenciarlo de otros, los argumentos de la funcin tambin se tienen en cuenta:
ejemplo(), ejemplo(integer), ejemplo(integer, integer) y ejemplo(text) son todos procedimientos
diferentes, aunque se llamen igual.

En psql existe un comando muy bueno que nos ensea como una funcin est definida en la base de
datos.

practica=# \x
Expanded display is on.

practica=# \df+ ejemplo


List of functions
-[ RECORD 1 ]-------+----------------------
Schema | public
Name | ejemplo
Result data type | integer
Argument data types |
Volatility | volatile
Owner | postgres
Language | plpgsql
Source code |
: BEGIN
: RETURN 104;
: END;
:
Description |
-[ RECORD 2 ]-------+----------------------
Schema | public
Name | ejemplo
Result data type | integer
Argument data types | integer
Volatility | volatile
Owner | postgres
Language | plpgsql
Source code |
: DECLARE
: numero ALIAS FOR $1;
: BEGIN
: RETURN numero;
: END;
Description |
-[ RECORD 3 ]-------+-----------------------------------------------
Schema | public
Name | ejemplo
Result data type | integer
Argument data types | integer, integer
Volatility | volatile
Owner | postgres
Language | plpgsql
Source code |
: DECLARE
: numero1 ALIAS FOR $1;
: numero2 ALIAS FOR $2;
: constante CONSTANT integer := 100;
: resultado integer;
: BEGIN
: resultado := (numero1 * numero2) + constante;
: RETURN resultado;
: END;
Description |

practica=# \df+ ejemplo_txt


List of functions

-[ RECORD 1 ]-------+----------------------------------------------------
Schema | public
Name | ejemplo_txt
Result data type | text
Argument data types | integer, integer
Volatility | volatile
Owner | postgres
Language | plpgsql
Source code |
: DECLARE
: numero1 ALIAS FOR $1;
: numero2 ALIAS FOR $2;
: constante CONSTANT integer := 100;
: resultado INTEGER;
: resultado_txt TEXT DEFAULT 'El resultado es 104';
: BEGIN
: resultado := (numero1 * numero2) + constante;
: IF resultado <> 104 THEN
: resultado_txt := 'El resultado NO es 104';
: END IF;
: RETURN resultado_txt;
: END;
:
Description |

ASIGNACIN

Una asignacin de un valor a una variable o campo de fila o de registro se escribe:

identifier := expression;
Si el tipo de dato resultante de la expresin no coincide con el tipo de dato de las variables, o la
variable tienen un tamao o precisin conocido (como char(29)), el resultado ser amoldado
implcitamente por el intrprete de bytecode de PL/pgSQL, usando los tipos de las variables para las
funciones de entrada y los tipos resultantes en las funciones de salida. Ntese que esto puede
potencialmente producir errores de ejecucin generados por los tipos de las funciones de entrada.

Una asignacin de una seleccin completa en un registro o fila puede hacerse del siguiente modo:

SELECT expressions INTO target FROM ...;

target puede ser un registro, una variable de fila o una lista separada por comas
de variables y campo de registros o filas.

Si una fila o una lista de variables se usan como objetivo, los valores seleccionados han de coincidir
exactamente con la estructura de los objetivos o se producir un error de ejecucin. La palabra clave
FROM puede preceder a cualquier calificador vlido, agrupacin, ordenacin, etc. que pueda pasarse
a una sentencia SELECT.

Existe una variable especial llamada FOUND de tipo booleano, que puede usarse inmediatamente
despus de SELECT INTO para comprobar si una asignacin ha tenido xito.

SELECT * INTO myrec FROM EMP WHERE empname = myname;


IF NOT FOUND THEN
RAISE EXCEPTION ''empleado % no encontrado'', myname;
END IF;

Si la seleccin devuelve mltiples filas, solo la primera se mueve a los campos


objetivo. todas las dems se descartan.

LLAMADAS A OTRA FUNCIN


Todas las funciones definidas en una base de datos Postgres devuelven un valor. Por lo tanto, la
forma normal de llamar a una funcin es ejecutar una consulta SELECT o realizar una asignacin
(que d lugar a un SELECT interno de PL/pgSQL). Pero hay casos en que no interesa saber los
resultados de las funciones.

PERFORM query

Esto ejecuta 'SELECT query' en el gestor SPI, y descarta el resultado. Los


identificadores como variables locales son de todos modos sustituidos en los
parmetros.

Volviendo de la funcin

RETURN expression

La funcin termina y el valor de expression se devolver al ejecutor superior. El


valor devuelto por una funcin no puede quedar solo en definicin. Si el control
alcanza el fin del bloque de mayor nivel de la funcin sin encontrar una sentencia
RETURN, ocurrir un error de ejecucin.

Las expresiones resultantes sern amoldadas automticamente en los tipos devueltos por la funcin,
tal como se ha descrito en el caso de las asignaciones.

ABORTANDO LA EJECUCIN Y MENSAJES


Como se ha indicado en los ejemplos anteriores, hay una sentencia RAISE que puede
enviar mensajes al sistema de registro de Postgres.

###################### ATENCION WARNING ACHTUNG


#####################
Aqu puede haber una errata! Comparada con el original
RAISE level
for'' [, identifier [...]];
#####################################################
################

Dentro del formato, "%" se usa como situacin para los subsecuentes identificadores,
separados por comas. Los posibles niveles son DEBUG (suprimido en las bases de datos
de produccin), NOTICE (escribe en el registro de la base de datos y lo enva a la
aplicacin del cliente) y EXCEPTION (escribe en el registro de la base de datos y aborta
la transaccin).

CREATE FUNCTION algunafuncion() RETURNS INTEGER AS '


DECLARE
cantidad INTEGER := 30;
BEGIN
RAISE NOTICE ''La cantidad aqu es %'',cantidad; -- La cantidad aqu es 30
cantidad := 50;
-- Crea un subbloque
DECLARE
cantidad INTEGER := 80;
BEGIN
RAISE NOTICE ''La cantidad aqu es %'',cantidad; -- La cantidad aqu es 80
END;
RAISE NOTICE ''La cantidad aqu es %'',cantidad; -- La cantidad aqu es 50
RETURN cantidad;
END;
' LANGUAGE 'plpgsql';

BUCLES.- En PL/SQL tenemos a nuestra disposicin los siguientes iteradores o bucles:

LOOP
WHILE
FOR

El bucle LOOP, se repite tantas veces como sea necesario hasta que se fuerza su salida con la
instruccin EXIT. Su sintaxis es la siguiente

LOOP
-- Instrucciones
IF (expresion) THEN
-- Instrucciones
EXIT;
END IF;
END LOOP;

El siguiente ejemplo acumula 10 veces un nombre y despus lo retorna:

CREATE OR REPLACE FUNCTION ejemplo_loop()RETURNS text AS $$


DECLARE
x integer DEFAULT 1;
acumulador text default listo:;
BEGIN
LOOP
acumulador:= acumulador || Gabriel || x || ,;
If x>=10 THEN exit; END IF;
x:=x+1;
END LOOP;
RETURN acumulador;
end; $$
LANGUAGE plpgsql;

En el siguiente ejemplo se utiliza las diferentes formas de utilizar RAISE:

CREATE OR REPLACE FUNCTION ejemplo_loop() RETURNS text AS $$


DECLARE
x integer DEFAULT 1;
acumulador text default listo:;
BEGIN
LOOP
--RAISE EXCEPTION % Gabriel,x;
RAISE NOTICE % Gabriel,x;
acumulador:= acumulador || Gabriel || x || ,;
If x>=10 THEN exit; END IF;
x:=x+1;
END LOOP;
RETURN acumulador;
end; $$
LANGUAGE plpgsql;

Para probarlo:
SELECT ejemplo_loop();

El bucle WHILE, se repite mientras que se cumpla expresion.


WHILE (expresion) LOOP
-- Instrucciones
END LOOP;

El siguiente ejemplo muestra el nmero de veces que se repite un carcter en un texto:

CREATE OR REPLACE FUNCTION cuenta_caracter(text,text) RETURNS INT4 AS '


DECLARE
intext ALIAS FOR $1;
inchar ALIAS FOR $2;
lon int4;
resultado int4;
i int4;
tmp char;
BEGIN
lon:= length(intext)+1;
i:=1;
resultado:=0;
WHILE i <= lon LOOP
tmp := substr(intext,i,1);
IF tmp = inchar THEN
resultado := resultado +1;
END IF;
i:=i+1;
END LOOP;
RETURN resultado;
END' LANGUAGE 'plpgsql';

Para ejecutarlo:
SELECT cuenta_caracter('Todo nos es lisito pero no todo nos conviene','o');

CREATE OR REPLACE FUNCTION factorial(n int) RETURNS int8 AS $$


DECLARE
f int8;
counter integer;
BEGIN
f:=1;
counter := n;
WHILE counter > 1 LOOP
f := f * counter;
counter := counter - 1;
END LOOP;
RETURN f;
END;
$$ LANGUAGE 'plpgsql';
Para ejecutarlo:
SELECT factorial(6);

El bucle FOR, se repite tanta veces como le indiquemos en los identificadores inicio y final.
FOR contador IN [REVERSE] inicio..final LOOP
-- Instrucciones
END LOOP;
En el caso de especificar REVERSE el bucle se recorre en sentido inverso. Aqu algunos modelos
de cmo utilizar el bucle FOR:

FOR i IN 1..10 LOOP


--Generar los siguientes valores: 1,2,3,4,5,6,7,8,9,10 dentro del bucle
END LOOP;

FOR i IN REVERSE 10..1 LOOP


-- Generar los siguientes valores: 10,9,8,7,6,5,4,3,2,1 dentro del bucle
END LOOP;

FOR i IN REVERSE 10..1 BY 2 LOOP


-- Generar los siguientes valores: 10,8,6,4,2 dentro del bucle
END LOOP;

Veamos el siguiente ejemplo:


CREATE OR REPLACE FUNCTION ejemplo_for()RETURNS text AS $$
DECLARE
x integer DEFAULT 1;
acumulador text default listo:;
BEGIN
FOR x IN REVERSE 10..1 BY 2 LOOP
acumulador:= acumulador || Gabriel || x || ,;
END LOOP;
RETURN acumulador;
end;
$$ LANGUAGE plpgsql;

Para ver resultados:


SELECT ejemplo_for();

Ejemplos de utilizacin de procedimientos almacenados:


CREATE OR REPLACE FUNCTION unir(text, text) RETURNS text AS $BODY$
DECLARE
t text;
BEGIN
IF character_length($1) > 0 THEN
IF character_length($2) > 0 THEN
t = $1 ||, || $2;
else
t = $1;
end if;
ELSE
t = $2;
END IF;
RETURN t;
END; $BODY$
LANGUAGE plpgsql VOLATILE;

SELECT unir(apellidopaterno,nombres) from personas;

El siguiente ejemplo permite numerar cualquier reporte:

CREATE OR REPLACE FUNCTION FilaNumerada() RETURNS integer AS $$


BEGIN
EXECUTE 'CREATE TEMP SEQUENCE "'||current_timestamp||'"';
RETURN nextval('"'||current_timestamp||'"');
EXCEPTION WHEN duplicate_table THEN
RETURN nextval ('"'||current_timestamp||'"');
END
$$ LANGUAGE 'plpgsql';

SELECT FilaNumerada(), unir(apellidopaterno,nombres) from personas;

Cuando se desea que una funcin devuelva un grupo de datos debe definirse la misma con la
instruccin SETOF definiendo un tipo de datos. Veamos los siguientes ejemplos:

CREATE FUNCTION ExtraePersona(int)RETURNS setof Personas AS


SELECT * FROM Personas WHERE idPersona = $1;
LANGUAGE SQL;

Para ejecutar la function:

SELECT * FROM ExtraePersona(5);

Tipos Fila (Row)


nombre nombretabla%ROWTYPE;
Una variable de un tipo compuesto es denominada variable de fila (row-type variable). Una variable
de este tipo puede almacenar una fila completa del resultado de una consulta SELECT o FOR,
mientras que la columna de dicha consulta coincida con el tipo declarado para la variable. Los
campos individuales del valor de la fila son accedidos usando la tpica notacin de puntos, por
ejemplo variablefila.campo.

En la actualidad, una variable de tipo fila slo puede ser declarada usando la notacin %ROWTYPE;
aunque uno podra esperar que un nombre pblico de nombre de tabla funcionada como tipo de
declaracin, sta no sera aceptada dentro de funciones PL/pgSQL.

Los parmetros para una funcin pueden ser tipos compuestos (filas completas de tablas). En ese
caso, el correspondiente identificador $n ser una variable tipo fila, y los campos podrn ser
accedidos, por ejemplo $1.nombrecampo.

Slo los atributos de una tabla definidos por el usuario son accesibles en una variable tipo fila, y no
OID u otros atributos de sistema (porque la fila podra venir de una vista). Los campos del tipo fila
heredan el tamao del campo de la tabla as como la precisin para tipos de datos, tales como
char(n).

CREATE OR REPLACE FUNCTION mostrar_datos() RETURNS SETOF personas AS $$


DECLARE
resultadoSQL personas%rowtype;
BEGIN
FOR resultadoSQL in EXECUTE 'SELECT * from personas' LOOP
RETURN NEXT resultadoSQL;
END LOOP;
END;
$$ LANGUAGE plpgsql;

SELECT * from mostrar_datos();


RECORDS
nombre RECORD;
Las variables de tipo registro (record) son similares a las tipo fila, pero no tienen una estructura
predefinida. Ellas la toman de la actual estructura de la fila que tienen asignada durante un comando
SELECT o FOR. La subestructura de una variable tipo registro puede variar cada vez que se le asigne
un valor. Una consecuencia de esto es que hasta que a una variable tipo registro se le asigne valor por
vez primera, sta no tendr subestructura, y cualquier intento de acceder a un campo en ella
provocar un error en tiempo de ejecucin.

Advierta que RECORD no es un verdadero tipo de datos, slo un almacenador.

CREATE OR REPLACE FUNCTION mostrar_datos2() RETURNS SETOF record AS $$


DECLARE
resultadoSQL record;
BEGIN
FOR resultadoSQL in EXECUTE 'SELECT Idpersona, apellidopaterno,
apellidomaterno,nombres FROM personas' LOOP
RETURN NEXT resultadoSQL;
END LOOP;
END;
$$ LANGUAGE plpgsql;

SELECT * from mostrar_datos2() as Personas(a integer,b varchar(50),c varchar(50), d


varchar(50));

ATRIBUTOS

Usando los atributos %TYPE y %ROWTYPE, puede declarar variables con el mismo tipo de datos o
estructura que otro elemento de la base de datos (por ejemplo: un campo de tabla).

variable%TYPE
%TYPE proporciona el tipo de datos de una variable o de una columna de base de datos. Puede usar
esto para declarar variables que almacenen valores de base de datos. Por ejemplo, digamos que tiene
una columna llamada user_id en su tabla usuarios. Para declarar una variable con el mismo tipo de
datos que usuarios.user_id usted escribira:

Id usuarios.user_id%TYPE;

Usando %TYPE no necesita conocer el tipo de datos de la estructura a la que est referenciando, y lo
ms importante, si el tipo de datos del elemento referenciado cambia en el futuro (por ejemplo: usted
cambia su definicin de tabla para user_id de INTEGER a REAL), no necesitar cambiar su
definicin de funcin.

tabla%ROWTYPE
%ROWTYPE proporciona el tipo de datos compuesto correspondiente a toda la fila de la tabla
especificada. La tabla debe ser una tabla existente o un nombre de vista de la base de datos.

DECLARE
users_rec usuarios%ROWTYPE;
user_id usuarios.user_id%TYPE;
BEGIN
user_id := users_rec.user_id;
...

CREATE OR REPLACE FUNCTION Total_profesores_x_sexo(s sex)RETURNS INTEGER AS


$$
DECLARE
NUMORDEN INTEGER;
FILA_ITEM Personas%ROWTYPE;
BEGIN
NUMORDEN:=0;
FOR FILA_ITEM IN SELECT personas.idpersona FROM personas INNER JOIN
profesores ON personas.IdPersona = profesores.IdPersona WHERE personas.sexo=
s LOOP
NUMORDEN:=NUMORDEN+1;
END LOOP;
RETURN NUMORDEN;
END;
$$LANGUAGE 'plpgsql';

SELECT Total_profesores_x_sexo (M);

Para agregar datos mediante un procedimiento almacenado en postgres sera de la siguiente forma:

CREATE OR REPLACE FUNCTION AgregaDatosPersonales (IN ApPat varchar(50),IN ApMat


varchar(50),IN Nomb varchar(50),IN Direc varchar(150),IN fono varchar(15),IN sx sex,IN FechaN
Date,IN EstCivil ec) RETURNS VOID AS $$
BEGIN
INSERT INTO personas
(ApellidoPaterno,ApellidoMaterno,Nombres,Direccion,telefono,sexo,FechaNacimiento,Esta
doCivil) VALUES (ApPat,ApMat,Nomb,Direc,fono,sx,FechaN,EstCivil);
END; $$
LANGUAGE 'plpgsql';

Para probar el ejemplo se escribe la orden:


SELECT AgregaDatosPersonales ('Faras','Pincay','Marcos Javier','Playa Prieta Calle
Principal','0997123456','M','1998-11-20','U');
En el siguiente ejemplo se crear un procedimiento almacenado para obtener el IDPersona pasando
loa apellidos y el nombre:
CREATE OR REPLACE FUNCTION BuscaId(OUT IdBuscar integer, IN ApPat varchar(50), IN
ApMat varchar(50), IN Nomb varchar(50)) RETURNS INTEGER AS $$
BEGIN
SELECT IdPersona INTO IdBuscar FROM Personas
WHERE personas.ApellidoPaterno || ' '|| personas.ApellidoMaterno ||' ' || personas.Nombres =
ApPat || ' ' || ApMat || ' ' || Nomb;
END; $$
LANGUAGE 'plpgsql';

En el siguiente ejemplo se crear un procedimiento almacenado para guardar datos de un profesor, el


mismo utiliza la funcin BuscaId:

CREATE OR REPLACE FUNCTION AgregaProfesores (ApPat varchar(50),ApMat


varchar(50),Nomb varchar(50),Direc varchar(150),fono varchar(15),sx sex, FechaN Date, EstCivil
ec,cargo Varchar(50), Titulacion Varchar(50), Fechaingreso date) RETURNS VOID AS $$
DECLARE
id INTEGER;
BEGIN
PERFORM AgregaDatosPersonales(ApPat,ApMat,Nomb,Direc,fono,sx,FechaN,EstCivil);
id:=buscaid(ApPat,ApMat,Nomb);
INSERT INTO Profesores(IdPersona, cargo, Titulacion, Fechaingreso) VALUES (Id, cargo,
Titulacion, Fechaingreso);
END; $$
LANGUAGE 'plpgsql';
Para probar el ejemplo se escribe la orden:
SELECT AgregaProfesores ('Mero','Casanova','Boris Mareano','Calderon, diagonal al
colegio','097654321','M','1999-06-11','C','Profesor','Ingeniero Civil','2009-01-05');

En el siguiente ejemplo se crear un procedimiento almacenado para guardar datos de un padre de


familia, el mismo utiliza una alternativa a la funcin BuscaId:
CREATE OR REPLACE FUNCTION AgregaPadres (ApPat varchar(50),ApMat varchar(50),Nomb
varchar(50),Direc varchar(150),fono varchar(15),sx sex, FechaN Date, EstCivil ec,cargasf
INTEGER, fonoTrabajo Varchar(15), DirecTrabajo varchar(100), ocupacion varchar(80)) RETURNS
VOID AS $$
DECLARE
Id INTEGER;
BEGIN
PERFORM AgregaDatosPersonales(ApPat,ApMat,Nomb,Direc,fono,sx,FechaN,EstCivil);
SELECT MAX(IdPersona) INTO Id FROM Personas;
INSERT INTO Padres(IdPersona, cargasfamiliares, TelefonoTrabajo, DireccionTrabajo,
ocupacion)
VALUES (Id, cargasf, fonoTrabajo, DirecTrabajo, ocupacion);
END; $$
LANGUAGE 'plpgsql';

Para probar el ejemplo se escribe la orden:


SELECT AgregaPadres ('Mendieta','Alvarado','Carmen Alina','Cdla PortoNorte casa
16','052987654','F','1979-12-02','C',3,'053789456','Montecristi, Asamblea','Asistente contable');
En el siguiente ejemplo se crear un procedimiento almacenado para guardar datos de estudiantes:
CREATE OR REPLACE FUNCTION AgregaEstudiantes (ApPat varchar(50),ApMat
varchar(50),Nomb varchar(50), Direc varchar(150), fono varchar(15),sx sex,FechaN Date, EstCivil
ec, ApPatPP varchar(50),ApMatPP varchar(50),NombPP varchar(50), ApPatMM
varchar(50),ApMatMM varchar(50),NombMM varchar(50), Proce varchar(80)) RETURNS VOID AS
$$
DECLARE
IdEst INTEGER;
IdPapa INTEGER;
IdMama INTEGER;
BEGIN
IdPapa:=BuscaId(ApPatPP,ApMatPP,NombPP);
IdMama:=BuscaId(ApPatMM,ApMatMM,NombMM);
PERFORM AgregaDatosPersonales(ApPat,ApMat,Nomb,Direc,fono,sx,FechaN,EstCivil);
IdEst:=BuscaId(ApPat,ApMat,Nomb);
INSERT INTO Estudiante(IdPersona, IdPersonaPapa, IdPersonaMama, Procedencia)
VALUES (IdEst, IdPapa, IdMama, Proce);
END; $$
LANGUAGE 'plpgsql';

Para probar el ejemplo se escribe la orden:


SELECT AgregaEstudiantes('Faras','Mendieta','Andrea Patricia','Playa Prieta calle
Principal','0998444333','F','2002-10-10','S','Faras','Pincay','Marcos
Javier','Mendieta','Alvarado','Carmen Alina','Escuela 12 de Mayo');

CREATE OR REPLACE FUNCTION elimina_persona(INT) RETURNS BOOL AS '


BEGIN
DELETE FROM personas WHERE idpersona = $1;
IF FOUND THEN
RETURN TRUE;
END IF;
RETURN FALSE;
END; ' LANGUAGE plpgsql;

SELECT AgregaDatosPersonales ('Pueblo','Pueblo','Juan','En algn lugar','052765431','M','1998-


11-20','S');
SELECT * FROM personas;
SELECT * FROM elimina_persona(buscaid('Pueblo','Pueblo','Juan'));
Otra alternativa de uso es: SELECT * FROM elimina_persona(58);
SELECT * FROM personas;
TRANSACCIONES

Uno de los puntos ms importantes en un motor de base de datos es proporcionar los mecanismos
adecuados para manejar la concurrencia, es decir, como asegurar la integridad de los datos y la
correctitud de las operaciones realizadas cuando existen mltiples personas intentando acceder a la
misma informacin.

Para ejemplificar el concepto, usemos un ejemplo cotidiano. Los cajeros automticos (Redbanc /
ATM) realizan descuentos del saldo de la cuenta corriente o de ahorro cuando se obtiene dinero de
ellos. Supongamos que en un momento determinado existe un usuario sacando dinero y
simultneamente se esta realizando un cobro electrnico sobre la misma cuenta. El mecanismo
seria: Cuanto dinero hay en la cuenta?; Del saldo descuente esta cantidad de dinero.

Si esta operacin puede ser realizada EXACTAMENTE al mismo tiempo, entonces se obtendr el
resultado de la tabla anterior. As es necesario proveer mecanismos de bloqueo temporal para
asegurar que solo una instancia tenga acceso a los datos concurrentemente (simultneamente).

Una transaccin es una operacin que se realiza por completo, de forma atmica. En caso de fallar
algo, los cambios se revierten y todo vuelve al estado anterior. Postgres sigue el estndar SQL para la
sintaxis de transacciones:

SELECT * from cursos;

SELECT * from paralelos;

BEGIN WORK;

INSERT INTO Cursos(Curso) VALUES ( Octavo);

INSERT INTO Paralelos(Paralelo) VALUES (E);

COMMIT;

SELECT * from cursos;

SELECT * from paralelos;

Cada transaccin comienza con el comando BEGIN WORK, aunque WORK esopcional. Al
terminar el trabajo se debe invocar al comando COMMIT para indicar que la transaccin ha
concluido. En cualquier punto de la transaccin se puede invocar a ROLLBACK, comando que
deshace todos los cambios realizados en la base de datos, dejndola en el estado previo al inicio de la
transaccin.

BEGIN WORK;

INSERT INTO Cursos(Curso) VALUES ( Mantenimiento);

SELECT * from cursos;

ROLLBACK;

SELECT * from cursos;

En el caso de que un comando SQL falle, Postgres ignorar las siguientes sentencias hasta el fin de la
transaccin, la cual se indica con COMMIT o ROLLBACK. Las transacciones en Postgres pueden
ser grabadas en un punto intermedio, de manera que pueda re-ejecutar o deshacer solo una porcin de
la transaccin. Para esto se utiliza SAVEPOINT.

BEGIN WORK;

INSERT INTO especialidades (nombreespecialidad) VALUES (Ciencias internacionales);

SELECT * from Especialidades;

SAVEPOINT s1;

INSERT INTO especialidades (nombreespecialidad) VALUES (Computacin);

SELECT * from Especialidades;

ROLLBACK to savepoint s1;

SELECT * from Especialidades;

INSERT INTO especialidades (nombreespecialidad) VALUES (Comercio);

COMMIT;

SELECT * from Especialidades;

CURSORES EN POSTGRES

Para el manejo de grandes cantidades de datos tanto en PostgreSQL como en otras bases de datos
relacionales existe el concepto de cursors (cursores) los cuales representan un resultset (conjunto de
datos) que son asociados a una variable, una variable de tipo cursor. Esta variable representa un
apuntador hacia una tabla virtual representada por una consulta y su respectivo comando SELECT
asociado.
La diferencia entre un comando SELECT no asociado a un cursor y uno asociado, es que en el
primero la consulta regresar todos los registros a la vez y si queremos limitar la cantidad de registros
para procesar debemos correr la consulta nuevamente agregando WHERE, BETWEEN o cualquier
otra instruccin para filtrar los resultados. En el caso del comando asociado a un cursor este nos
permite desplazarnos y limitar la cantidad de registros para procesar dentro del resultset sin necesidad
de un nuevo comando SELECT.

Para mostrar la diferencia entre una consulta sin cursor y una consulta asociada a un cursor,
ejecutamos la siguiente consulta.

SELECT apellidopaterno, apellidomaterno, nombres, direccion, fechanacimiento FROM


personas;

Esta consulta nos devuelve el resultado acostumbrado y que ya se ha tratado en captulos anteriores
en el presente manual.

SELECT apellidopaterno, apellidomaterno, nombres, direccion, fechanacimiento FROM


personas;

apellidopaterno | apellidomaterno | nombres | direccion |


fechanacimiento

-----------------------+------------------------+---------------------+-------------------------------+-----------------

Demera | Ureta | Gabriel | Cdla. Parque Forestal | 1974-


03-18

Montero | Zambrano | Paola | Cdla. Parque Forestal | 1979-04-


23

Espinoza | Alcvar | Elsa Argentina | Mejia | 1978-


10-20

Hidalgo | Villamar | Luis Ernesto | Limn | 1977-


08-25

Aveiga | Zambrano | Enma | Montecristi | 1974-


06-18

Zambrano | Franco | Luis Felipe | Garca Moreno y sucre | 1976-04-


10

Lpez | Intriago | Blanca | Primero de Mayo | 1972-


02-16

Zedeo | Franco | Nora Alice | Morales y Rocafuerte | 1970-05-


18

Panta | Chica | Jos Vicente | Pedro Gual y morales | 1972-


10-12
Ronquillo | Delgado | Ramn | Av.Manab,los Mangos | 1974-12-
30

Vaca | Arteaga | Vctor Hugo | Av. Ajuela y morales | 1976-


10-10

Salazar | Montesinos | Claudia | Parroq. San Pablo | 1979-


09-08

Ahora mostramos los comandos que pueden utilizarse al asociar una consulta a un cursor. Para el
trabajo con cursores es necesario que estos se encuentren dentro del mbito de una TRANSACCIN.

BEGIN;

Declaramos el cursor como una variable de tipo cursor y le asociamos una consulta SQL.

DECLARE micursor CURSOR FOR SELECT * FROM Personas;

Ahora podemos navegar entre los registros del resultset, con el comando FETCH, de este comando la
sintaxis es:

FETCH [FORWARD | BACKWARD | ALL | NEXT]

A continuacin unos ejemplos de su utilizacin:


Obtenemos un par de los primeros registros:
FETCH 2 FROM micursor;
Ahora muestraremos los siguientes 4 registros
FETCH 4 FROM micursor;
S queremos retroceder 3 registros
FETCH BACKWARD 3 FROM micursor;
Avanzaremos 6 registros
FETCH FORWARD 6 FROM micursor;
Para obtener el anterior registro
FETCH PRIOR FROM MiCursor;
Para obtener el proximo registro
FETCH NEXT FROM MiCursor;
Para obtener la ubicacin del registro sin avanzar o retroceder se utiliza:
FETCH RELATIVE 0 FROM MiCursor;
Tambin podemos avanzar de forma negativa con FORWARD -[n] lo que es equivalente a
BACKWARD [n].
FETCH FORWARD -10 FROM MiCursor;
Obtenemos todos los registros del cursor:
FETCH ALL FROM micursor;
Por ltimo cerramos el cursor y confirmamos (o abortamos) la transaccin.
CLOSE micursor;
COMMIT;
Ejercicio: El siguiente ejemplo aplica una de las mltiples actividades que se pueden ejercer a un
registro determinado, supongamos que deseamos actualizar la direccin de una persona, aplicamos
los siguientes pasos:
1. Iniciamos la transaccin:
BEGIN;
2. Creamos el cursor y lo llenamos de datos:

DECLARE listapersonas CURSOR FOR SELECT * FROM Personas;

3. Nos ubicamos sobre el registro que se desea manipular, para el este caso se trata del primero:

FETCH NEXT FROM listapersonas;

4. Aplicamos la actualizacin, indicando que se trata del posesionado:


UPDATE personas SET direccion = Guayaquil WHERE CURRENT OF listapersonas;
5. Verificamos los cambios
SELECT * FROM personas Personas WHERE idpersona=1;
6. Una vez verificado los cambios usted decidir si los aplica o no
COMMIT; s desea aplicar los cambios o ROLLBACK; para no aplicarlos

DECLARANDO VARIABLES CURSOR

Todo el acceso a cursores en PL/pgSQL va a travs de variables cursor, las cuales son siempre del
tipo de datos especial refcursor. Una forma de crear una variable tipo cursor es declararla como de
tipo refcursor. Otra forma es usar la sintaxis de declaracin de cursor, la cual en general es:

nombre CURSOR [ ( argumentos ) ] FOR select_query ;

(NOTA: FOR puede ser reemplazado por IS para compatibilidad con Oracle)

Los argumentos, si los hay, son pares de tipos de datos name separados por comas que definen
nombres a ser reemplazados por valores de parmetros en la consulta dada. Los actuales valores a
sustituir para estos nombres sern especificados ms tarde, cuando el cursor es abierto.

Algunos ejemplos:

DECLARE
curs1 refcursor;
curs2 CURSOR FOR SELECT * from tenk1;
curs3 CURSOR (key int) IS SELECT * from tenk1 where unique1 = key;

Estas tres variables tienen el tipo de datos refcursor, pero la primera puede ser usada con cualquier
consulta, mientras que la segunda tiene una consulta completamente especificada para trabajar con
ella, y la ltima tiene una consulta parametrizada (key ser reemplazado por un valor de parmetro
entero cuando el cursor es abierto). La variable curs1 ser obviada, ya que no est asignada a ninguna
consulta en particular.

ABRIENDO CURSORES

Antes de que un cursor pueda ser utilizado para retornar filas, ste debe ser abierto (esta es la accin
equivalente al comando SQL DECLARE CURSOR). PL/pgSQL tiene cuatro formas para el
estamento OPEN, dos de las cuales usan variables cursor no asignadas y las otras dos usan variables
cursor asignadas.

OPEN FOR SELECT


OPEN unbound-cursor FOR SELECT ...;
La variable cursor es abierta y se le pasa la consulta especificada para ejecutar. El cursor no puede
ser abierto an, y debe haber sido declarado como cursor no asignado (esto es, una simple variable
refcursor). La consulta SELECT es tratada de la misma forma que otros estamentos SELECT en
PL/pgSQL: los nombres de variables PL/pgSQL son sustituidos, y el plan de consulta es almacenado
para su posible reutilizacin.

OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;

OPEN FOR EXECUTE


OPEN unbound-cursor FOR EXECUTE query-string;
La variable cursor es abierta y se le pasa la consulta especificada para ser ejecutada. El cursor no
puede ser abierto an, y debe haber sido decalrado como cursor no asignado (esto es, una simpla
variable refcursor). La consulta es especificada como una expresin de texto de la misma forma que
en el comando EXECUTE. Como es usual, esto le da flexibilidad para que la consulta pueda variar
en cada ejecucin.

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

Opening a bound cursor


OPEN bound-cursor [ ( argument_values ) ];
Esta forma de OPEN es usada para abrir una variable cursor cuya consulta le fu asignada cuando
sta fue declarada. El cursor no puede ser abierto todava. Una lista de los actuales argumentos de los
valores de las expresiones debe aparecer si y slo si el cursor fue declarado para tomar argumentos.
Estos valores sern sustituidos en la consulta. El plan de consulta para un cursor asignado siempre es
considerado como almacenable -no hay equivalencia para EXECUTE en ste caso-.

OPEN curs2;
OPEN curs3(42);

Usando Cursores
Una vez un cursor ha sido abierto, ste puede ser manipulado con los estamentos descritos aqu.

Estas manipulaciones no necesitan ocurrir en la misma funcin que abri el cursor. Puede retornar un
valor refcursor de una funcin y permitir al peticionario operar con el cursor (internamente, un valor
refcursor es simplemente la cadena nombre de una Portal conteniendo la consulta activa para el
cursor. Este nombre puede ser pasado, asignado a otras variables refcursor, sin afectar al Portal).
Todos los Portales son implcitamente cerrados al final de la transaccin. Por tanto un valor refcursor
es til para referenciar un cursor abierto slo hasta el final de la transaccin.

FETCH
FETCH cursor INTO target;

FETCH retorna la siguiente fila desde el cursor a un destino, el cual puede ser una variable fila,
registro o una lista de vairbales simples, separadas por comas, tal como en un SELECT INTO. Al
igual que en un SELECT INTO, la variable especial FOUND puede ser chequeada para ver si se
obutvo o no una fila.

FETCH curs1 INTO rowvar;


FETCH curs2 INTO foo,bar,baz;

CLOSE
CLOSE cursor;
CLOSE cierra el Portal de un cursor abierto. Esto puede ser suado para liberar recursos antes del final
de una transaccin, o para liberar la variable cursor para abrirla de nuevop.

CLOSE curs1;
Retornando Cursores

Las funciones PL/pgSQL pueden retornar cursores al peticionario. Esto es usado para retornar
mltiples filas o columnas desde la funcin. La funcin abre el cursor y retorna el nombre del cursor
al peticionario. El peticionario entonces puede obtener (con FETCH) filas desde el cursor. El cursor
puede ser cerrado por el remitente, o ser cerrado automticamente cuando termine la transaccin.

El nombre del cursor retornado por la funcin puede ser especificado por el peticionario o generado
automticamente. El siguiente ejemplo muestra cmo un nombre de cursor puede ser proporcionado
por el peticionario:

CREATE OR REPLACE FUNCTION periodos(refcursor) RETURNS refcursor AS '


BEGIN
OPEN $1 FOR SELECT nombre FROM periodosLectivos;
RETURN $1;
END; '
LANGUAGE 'plpgsql';

BEGIN;
SELECT periodos('listaperiodos');
FETCH ALL IN listaperiodos;
COMMIT;

El siguiente ejemplo utiliza una vista como referencia para ser utilizada en el cursor:
CREATE OR REPLACE VIEW V_Lista_Profesores AS
SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Titulacion
FROM profesores, personas
WHERE profesores.IdPersona = personas.IdPersona AND profesores.cargo Like 'Prof%'
ORDER BY ApellidoPaterno;

CREATE OR REPLACE FUNCTION profes(refcursor) RETURNS refcursor AS '


BEGIN
OPEN $1 FOR SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Titulacion FROM
V_Lista_Profesores;
RETURN $1;
END; '
LANGUAGE 'plpgsql';

BEGIN;
SELECT profes('listaprofes');
FETCH 2 FROM listaprofes;
FETCH 5 FROM listaprofes;
FETCH BACKWARD 3 FROM listaprofes;
FETCH ALL IN listaprofes;
COMMIT;

El siguiente ejemplo usa generacin automtica de nombre de cursor:

CREATE VIEW V_Lista_Estudiantes AS


SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Curso, Paralelo
FROM personas INNER JOIN (paralelos INNER JOIN (cursos INNER JOIN matriculas ON
cursos.IdCurso = matriculas.IdCurso) ON paralelos.IdParalelo = matriculas.IdParalelo) ON
personas.IdPersona = matriculas.IdPersonaEstudiante ORDER BY ApellidoPaterno,
ApellidoMaterno;

CREATE OR REPLACE FUNCTION listado() RETURNS refcursor AS '


DECLARE
cur_eje refcursor;
BEGIN
OPEN cur_eje FOR SELECT ApellidoPaterno, ApellidoMaterno, Nombres, Curso, Paralelo
FROM V_Lista_Estudiantes;
RETURN cur_eje;
END; '
LANGUAGE 'plpgsql';

El siguiente ejemplo usa el cursor de forma referencial, para poder utilizarlo usted debe tomar el
nombre que le da como referencia <unnamed portal 1> que le da como resultado al ejecutar la funcin:

BEGIN;
SELECT listado();

listado
--------------------
<unnamed portal 1>
(1 fila)

FETCH ALL IN "<unnamed portal 1>";


COMMIT;

Ejemplo utilizando una funcin estandar para devover datos desde 2 tablas:
CREATE OR REPLACE FUNCTION curso_paralelo(refcursor, refcursor) RETURNS SETOF
refcursor AS $$
BEGIN
OPEN $1 FOR SELECT * FROM Cursos;
RETURN NEXT $1;
OPEN $2 FOR SELECT * FROM paralelos;
RETURN NEXT $2;
END;
$$ LANGUAGE plpgsql;

BEGIN;
SELECT * FROM curso_paralelo('a', 'b');
FETCH ALL FROM a;
FETCH ALL FROM b;
COMMIT;

Se podra realizar un ejemplo utilizando una funcin que aplique filtrados mediante un argumento:
CREATE OR REPLACE FUNCTION personasxiniciales(refcursor,text) RETURNS refcursor
AS $$
BEGIN
OPEN $1 FOR SELECT * FROM personas WHERE apellidopaterno LIKE $2 || '%';
RETURN $1;
END; $$ LANGUAGE 'plpgsql' VOLATILE;

BEGIN;
SELECT personasxiniciales('lista','M');
FETCH ALL IN lista;
COMMIT;
TRIGGERS (Disparadores)

Un trigger es una accin que se lanza cuando se inserta, elimina o actualiza una o varios registros de
una tabla. En PL/pgSQL, los triggers son funciones sin argumentos en las cuales se crean las
siguientes variables:

NEW: Es un Record con los datos del registro que se est insertando (actualizando).

OLD: Datos del registro que se est eliminando (o actualizando).

TG_OP: Operacin que se est realizando, puede ser INSERT, UPDATE, DELETE, o
TRUNCATE.

Para desarrollar un trigger se tienes que hacer dos cosas: Crear una funcion para el trigger y despus
instalar el trigger en una/varias tablas.

Para probar el funcionamiento de un trigger crearemos una tabla con las siguientes caractersticas:

CREATE TABLE numeros(

numero bigint NOT NULL,

cuadrado bigint,

cubo bigint,

raiz2 real,

raiz3 real,

PRIMARY KEY (numero)

);

Una vez creada la tabla crearemos una funcin que llenar los datos calculado, esto se activar al
momento ingresar un nmero a la tabla NUMEROS:

CREATE OR REPLACE FUNCTION rellenar_datos() RETURNS TRIGGER AS $$

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 NEW;

END; $$ LANGUAGE plpgsql;

Cuando ya se tiene la tabla y la funcin, procedemos a crear un trigger que se activar antes de
insertar o actualizar un registro de la tabla:

CREATE TRIGGER rellenar_datos BEFORE INSERT OR UPDATE ON numeros


FOR EACH ROW

EXECUTE PROCEDURE rellenar_datos();

Ahora para probar su funcionamiento solo basta con insertar un registro a la tabla:

SELECT * from numeros;

INSERT INTO numeros (numero) VALUES (2);

SELECT * from numeros;

INSERT INTO numeros (numero) VALUES (3);

UPDATE numeros SET numero = 4 WHERE numero = 3;

SELECT * from numeros;

Que pasara si necesitamos proteger los registros y evitar la eliminacin, para lograrlo tendramos que
realizar esto:

CREATE OR REPLACE FUNCTION proteger_datos() RETURNS TRIGGER AS $$


BEGIN

RETURN NULL;

END; $$ LANGUAGE plpgsql;

sta funcin retornar cancelacin cada vez que sea ejecutada, por lo que se aplicara a un trigger
acorde a la necesidad, por ejemplo:

CREATE TRIGGER proteger_datos BEFORE DELETE ON numeros FOR EACH


ROW

EXECUTE PROCEDURE proteger_datos();

Para probar su funcionamiento ejecutamos la siguiente orden de eliminacin y notar que no se podr
eliminar registros en sta tabla:

DELETE FROM numeros WHERE numero=2;

SELECT * FROM numeros;

Aplicando ejemplos con la base de datos UNIDAD, crearemos una funcin que valida el ingreso de
datos sobre la tabla PERSONAS:

CREATE OR REPLACE FUNCTION valida_personas() RETURNS TRIGGER AS $$

BEGIN

IF LENGTH(TRIM(NEW.apellidoPaterno))>0 THEN

NEW.ApellidoPaterno= UPPER(NEW.ApellidoPaterno);

ELSE

NEW.ApellidoPaterno=No Registrado;

END IF;

IF LENGTH(TRIM(NEW.apellidoMaterno))>0 THEN

NEW.ApellidoMaterno= UPPER(NEW.ApellidoMaterno);

ELSE
NEW.ApellidoMaterno=No Registrado;

END IF;

IF LENGTH(TRIM(NEW.Nombres))>0 THEN

NEW.Nombres= UPPER(NEW.Nombres);

ELSE

NEW.Nombres=No Registrado;

END IF;

IF LENGTH(TRIM(NEW.Direccion))>0 THEN

NEW.Direccion= UPPER(NEW.Direccion);

ELSE

NEW.Direccion=No Registrado;

END IF;

IF LENGTH(TRIM(NEW.Telefono))=0 THEN

NEW.Telefono=No Registrado;

END IF;

IF NEW.sexo<>'M' Or NEW.Sexo<>'F' THEN

NEW.sexo=M;

END IF;

IF NEW.estadocivil<>'S' and NEW.EstadoCivil<>'C' and NEW.EstadoCivil<>'D'


and NEW.EstadoCivil<>'V' and NEW.EstadoCivil<>'U' THEN

NEW.EstadoCivil='S';

END IF;

RETURN NEW;

END; $$ LANGUAGE plpgsql;

CREATE TRIGGER chequea_datos BEFORE INSERT ON personas FOR EACH


ROW
EXECUTE PROCEDURE valida_personas ();

Al momento de probar la validez de un ingreso tendramos que probarlo de la siguiente forma:

INSERT INTO personas (ApellidoPaterno, ApellidoMaterno, Nombres, Direccion,


telefono, sexo, FechaNacimiento, EstadoCivil) VALUES ('Perero', '', 'Xavier',
'Miami', '','M','1994-03-18','C');

SELECT * FROM personas;

Una caracterstica especial que se le puede aplicar a una base de datos, es la de registrar las
responsabilidades sobre quin agreg, actualiz o elimin datos en una o varias tablas de la base de
datos, a este control se le denomina auditora de registros, para lograrlo se crear una tabla que
registre los movimientos de gestin que los usuarios realizan sobre la base de datos, la tabla podra
quedar de la siguiente forma:

CREATE TABLE AuditoriaUsuarios(

id Serial NOT NULL PRIMARY KEY,

Fecha timestamp,

Usuario varchar(40),

Proceso varchar(20),

Datos varchar(255) NOT NULL

);

La funcin AUDITORIA utiliza una variable especial para trabajar con trigger con el nombre TG_OP,
esta permite reconocer la accin que se esta ejecutando, la funcin utiliza esta cualidad para definir
que datos se registran en la tabla AudtoriaUsuario cuando se eliminan datos, actualizan o se
agregan nuevos registros:

CREATE OR REPLACE FUNCTION auditotia() RETURNS TRIGGER AS $$

DECLARE

contenido Varchar(255);

BEGIN
IF (TG_OP = 'DELETE') THEN

contenido:= OLD.IdPersona || ' ' || OLD.ApellidoPaterno || ' ' || OLD.ApellidoMaterno || ' ' ||
OLD.Nombres;

INSERT INTO auditoriausuarios(Fecha,Usuario,Proceso,Datos) VALUES (now(), user, 'Eliminado',


contenido);

RETURN OLD;

ELSIF (TG_OP = 'UPDATE') THEN

contenido:=CONCAT(OLD.ApellidoPaterno,' por ',NEW.ApellidoPaterno,', ',OLD.ApellidoMaterno,'


por ', NEW.ApellidoMaterno,', ',OLD.Nombres,' por ',NEW.Nombres);

contenido:=CONCAT(contenido,', ', OLD.Direccion,' por ',NEW.Direccion,', ',OLD.Telefono,' por ',


NEW.Telefono, ', ',OLD.Sexo,' por ',NEW.Sexo, ', ',OLD.EstadoCivil,' por ',NEW. EstadoCivil);

contenido:=CONCAT(contenido,', ', OLD.FechaNacimiento,' por ',NEW.FechaNacimiento);

INSERT INTO auditoriausuarios(Fecha,Usuario,Proceso,Datos) VALUES (now(), user,


'Actualizado', contenido);

RETURN NEW;

ELSIF (TG_OP = 'INSERT') THEN

contenido:=NEW.IdPersona || ' ' || NEW.ApellidoPaterno || ' ' || NEW.ApellidoMaterno || ' ' ||


NEW.Nombres;

INSERT INTO auditoriausuarios(Fecha,Usuario,Proceso,Datos) VALUES (now(), user, 'Agregado',


contenido);

RETURN NEW;

END IF;

END; $$ LANGUAGE plpgsql;

Definida la funcin creamos el trigger para que se active la funcin AUDITORIA despus de insertar
nuevos registros, actualizar o eliminar datos sobre la tabla Personas.

CREATE TRIGGER control AFTER INSERT OR UPDATE OR DELETE ON


personas FOR EACH ROW EXECUTE PROCEDURE auditotia();
Para que este proceso quede claro aplicaremos las tres formas de activar la funcin AUDITORIA,
primero agregamos un nuevo registro:

INSERT INTO personas (ApellidoPaterno, ApellidoMaterno, Nombres, Direccion,


telefono, sexo, FechaNacimiento, EstadoCivil) VALUES ('Ponce', 'Ponce', 'Cristina',
'Junin', '','F','1999-03-18','S');

Verificamos que paso en la tabla auditoriausuario:

SELECT * FROM auditoriausuarios;

Despus actualizamos el nuevo registro:

UPDATE personas SET ApellidoMaterno='Vera', Direccion='Calceta',


telefono='052177882' Where idpersona=76;

Verificamos: SELECT * FROM auditoriausuarios;

Por ltimo eliminamos el nuevo registro:

DELETE FROM personas WHERE idpersona=76;

Verificamos: SELECT * FROM auditoriausuarios;

VARIABLES ESPECIALES EN PL/PGSQL


Cuando una funcin escrita en PL/pgSQL es llamada por un disparador tenemos ciertas variables
especiales disponibles en dicha funcin. Estas variables son las siguientes:

NEW
Tipo de dato RECORD; Variable que contiene la nueva fila de la tabla para las operaciones
INSERT/UPDATE en disparadores del tipo row-level. Esta variable es NULL en disparadores del
tipo statement-level.
OLD
Tipo de dato RECORD; Variable que contiene la antigua fila de la tabla para las operaciones
UPDATE/DELETE en disparadores del tipo row-level. Esta variable es NULL en disparadores del
tipo statement-level.

TG_NAME
Tipo de dato name; variable que contiene el nombre del disparador que est usando la funcin
actualmente.

TG_WHEN
Tipo de dato text; una cadena de texto con el valor BEFORE o AFTER dependiendo de como el
disparador que est usando la funcin actualmente ha sido definido

TG_LEVEL
Tipo de dato text; una cadena de texto con el valor ROW o STATEMENT dependiendo de como el
disparador que est usando la funcin actualmente ha sido definido

TG_OP
Tipo de dato text; una cadena de texto con el valor INSERT, UPDATE o DELETE dependiendo de la
operacin que ha activado el disparador que est usando la funcin actualmente.

TG_RELID
Tipo de dato oid; el identificador de objeto de la tabla que ha activado el disparador que est usando
la funcin actualmente.

TG_RELNAME
Tipo de dato name; el nombre de la tabla que ha activado el disparador que est usando la funcin
actualmente. Esta variable es obsoleta y puede desaparacer en el futuro. Usar TG_TABLE_NAME.

TG_TABLE_NAME
Tipo de dato name; el nombre de la tabla que ha activado el disparador que est usando la funcin
actualmente.

TG_TABLE_SCHEMA
Tipo de dato name; el nombre de la schema de la tabla que ha activado el disparador que est usando
la funcin actualmente.

TG_NARGS
Tipo de dato integer; el nmero de argumentos dados al procedimiento en la sentencia CREATE
TRIGGER.

TG_ARGV[]
Tipo de dato text array; los argumentos de la sentencia CREATE TRIGGER. El ndice empieza a
contar desde 0. Indices invlidos (menores que 0 mayores/iguales que tg_nargs) resultan en valores
nulos.

Das könnte Ihnen auch gefallen