Instalación y Uso de PostgreSQL en Odoo
Instalación y Uso de PostgreSQL en Odoo
Sistemas ERP-CRM 30 h
Instalación de PostgreSQL
En la Instalación de Oddo 8 en Windows wl motor de la BD PostgreeSQL,la Base de datos
Oddo, asi como su gestor pgadmin III se instala automáticamente. Pero no será este el
gestor que usemos,Usaremos Navicat.
Todas las BD y tablas que necesita Odoo para trabajar están hechas en Postgresql, es necesario
tener conocimiento de como funciona este SGDB relaccional para comprender como Odoo
almacena los datos
Esta parte del manual brinda un concepto teórico corto, luego un problema resuelto que invito a
ejecutar, modificar y jugar con el mismo. Por último, y lo más importante, una serie de ejercicios
propuestos que nos permitirá saber si podemos aplicar el concepto propuesto.
El instalador nos guiará por una serie de pasos hasta tener ejecutando el servidor en forma local
en nuestra computadora:
120
Al final se ejecuta el programa "Stack Builder" que nos permite instalar otros complementos para
PostgreSQL, por el momento no instalaremos nada más (podemos cerrar el programa)
Junto con el servidor de base de datos PostgreSQL que acabamos de instalar necesitaríamos
instalar un gestor de bases de datos llamado Navicat
121
Nos solicita los datos de la conexión
Una vez creada la conexión a nuestro servidor postgresql, y probada la conexión nos conectamos
a el
122
Para crear una base de datos presionamos el botón derecho del mouse donde dice nueva base
de datos
123
Ahora podemos seleccionar en la ventana de la izquierda la base de datos "bd1" que acabamos
de crear:
Para poder ejecutar comandos SQL debemos de elegir bajo consultas Nueva consulta
En los próximos conceptos que veamos escribiremos los comandos SQL dentro de la ventana de
la consulta que acabamos de crear:
124
Probemos por ejemplo de ejecutar un comando SQL que crea una tabla llamada "usuarios" en la
base de datos "bd1" (tema que veremos en el próximo concepto):
Presionamos el ícono de "Ejecutar" para que se ejecute el comando SQL "create table":
125
Si es correcto el comando SQL de "create table" se nos informa que la misma fue creada, la
podemos ver abajo
126
Tipos de sentencias SQL y componentes sintácticos
En SQL tenemos bastantes sentencias que se pueden utilizar para realizar diversas tareas.
Dependiendo de las tareas, estas sentencias se pueden clasificar en tres grupos principales
(DML, DDL,DCL), aunque nos quedaría otro grupo que a mi entender no está dentro del lenguaje
SQL sino del PLSQL.
SENTENCIA DESCRIPCIÓN
Componentes sintácticos
La mayoría de sentencias SQL tienen la misma estructura.
Todas comienzan por un verbo (select, insert, update, create), a continuación le sigue una o más
clausulas que nos dicen los datos con los que vamos a operar (from, where), algunas de estas
son opcionales y otras obligatorias como es el caso del from.
127
2 - Crear una tabla (create table) DDL
Una tabla es una estructura de datos que organiza los datos en columnas y filas; cada columna es
un campo (o atributo) y cada fila, un registro. La intersección de una columna con una fila,
contiene un dato específico, un solo valor.
Nosotros trabajaremos con la base de datos llamada Temario , que ya he creado en mi equipo
Al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipo de datos
almacenarán cada uno de ellos, es decir, su estructura.
NOMBRECAMPO1 TIPODEDATO,
...
NOMBRECAMPON TIPODEDATO
);
La tabla debe ser definida con un nombre que la identifique y con el cual accederemos a ella.
Creamos una tabla llamada "usuarios" y entre paréntesis definimos los campos y sus tipos:
nombre varchar(30),
clave varchar(10)
);
Cada campo con su tipo debe separarse con comas de los siguientes, excepto el último.
Cuando se crea una tabla debemos indicar su nombre y definir al menos un campo con su tipo de
dato. En esta tabla "usuarios" definimos 2 campos:
128
nombre: que contendrá una cadena de caracteres de 30 caracteres de longitud, que almacenará
el nombre de usuario y
clave: otra cadena de caracteres de 10 de longitud, que guardará la clave de cada usuario.
Cada usuario ocupará un registro de esta tabla, con su respectivo nombre y clave.
Para nombres de tablas, se puede utilizar cualquier caracter alfabético o numérico, el primero
debe ser un caracter alfabético y no puede contener espacios en blanco.
Si intentamos crear una tabla con un nombre ya existente (existe otra tabla con ese nombre),
mostrará un mensaje indicando que ya hay un objeto llamado 'usuarios' en la base de datos y la
sentencia no se ejecutará. Para evitar problemas cuando estamos haciendo los ejercicios
verificaremos primero si ya existe una tabla con dicho nombre y procederemos a borrarla.
Para ver la estructura de una tabla consultaremos una tabla propia del PostgreSQL:
SELECT table_name,column_name,udt_name,character_maximum_length
Aparece el nombre de la tabla, los nombres de columna y el largo máximo de cada campo.:
Para eliminar una tabla usamos "drop table" junto al nombre de la tabla a eliminar:
Si intentamos eliminar una tabla que no existe, aparece un mensaje de error indicando tal
situación y la sentencia no se ejecuta, podemos escribir una variante de drop table verificando si
existe la tabla:
nombre varchar(30),
clave varchar(10)
);
129
-- Mostramos la estructura de la tabla que acabamos de crear
select table_name,column_name,udt_name,character_maximum_length
from information_schema.columns
130
3 - Insertar y recuperar registros de una tabla
(insert into - select) DML
Un registro es una fila de la tabla que contiene los datos propiamente dichos. Cada registro tiene
un dato por cada columna (campo). Nuestra tabla "usuarios" consta de 2 campos, "nombre" y
"clave".
Al ingresar los datos de cada registro debe tenerse en cuenta la cantidad y el orden de los
campos.
Usamos "insert into", luego el nombre de la tabla, detallamos los nombres de los campos entre
paréntesis y separados por comas y luego de la cláusula "values" colocamos los valores para cada
campo, también entre paréntesis y separados por comas.
Note que los datos ingresados, como corresponden a cadenas de caracteres se colocan entre
comillas simples.
Es importante ingresar los valores en el mismo orden en que se nombran los campos:
En el ejemplo anterior se nombra primero el campo "clave" y luego el campo "nombre" por eso,
los valores también se colocan en ese orden.
Si ingresamos los datos en un orden distinto al orden en que se nombraron los campos, no
aparece un mensaje de error y los datos se guardan de modo incorrecto.
En el siguiente ejemplo se colocan los valores en distinto orden en que se nombran los campos, el
valor de la clave (la cadena "Boca") se guardará en el campo "nombre" y el valor del nombre (la
cadena "Luis") en el campo "clave":
-- Creamos la tabla
nombre varchar(30),
clave varchar(10)
);
132
4 - Tipos de datos básicos
Ya explicamos que al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipo
de datos almacenará cada uno de ellos, es decir, su estructura.
El tipo de dato especifica el tipo de información que puede guardar un campo: caracteres,
números, etc.
Estos son algunos tipos de datos básicos de PostgreSQL (posteriormente veremos otros):
varchar: se usa para almacenar cadenas de caracteres. Una cadena es una secuencia de
caracteres. Se coloca entre comillas (simples); ejemplo: 'Hola', 'Juan Perez'. El tipo "varchar"
define una cadena de longitud variable en la cual determinamos el máximo de caracteres entre
paréntesis. Puede guardar hasta 10485760 caracteres. Por ejemplo, para almacenar cadenas de
hasta 30 caracteres, definimos un campo de tipo varchar(30), es decir, entre paréntesis, junto al
nombre del campo colocamos la longitud.
Si asignamos una cadena de caracteres de mayor longitud que la definida, la cadena no se carga,
aparece un mensaje indicando tal situación y la sentencia no se ejecuta (ERROR: value too long
for type character varying(30)).
Por ejemplo, si definimos un campo de tipo varchar(10) e intentamos asignarle la cadena 'Buenas
tardes', aparece un mensaje de error y la sentencia no se ejecuta.
integer: se usa para guardar valores numéricos enteros, de -2000000000 a 2000000000 aprox.
Definimos campos de este tipo cuando queremos representar, por ejemplo, cantidades.
float: se usa para almacenar valores numéricos con decimales. Se utiliza como separador el punto
(.). Definimos campos de este tipo para precios, por ejemplo.
Antes de crear una tabla debemos pensar en sus campos y optar por el tipo de dato adecuado
para cada uno de ellos.
Por ejemplo, si en un campo almacenaremos números enteros, el tipo "float" sería una mala
elección; si vamos a guardar precios, el tipo "float" es más adecuado, no así "integer" que no
tiene decimales. Otro ejemplo, si en un campo vamos a guardar un número telefónico o un
número de documento, usamos "varchar", no "integer" porque si bien son dígitos, con ellos no
realizamos operaciones matemáticas.
titulo varchar(20),
autor varchar(15),
editorial varchar(10),
133
precio float,
cantidad integer
);
select table_name,column_name,udt_name,character_maximum_length
from information_schema.columns
Hemos aprendido cómo ver todos los registros de una tabla, empleando la instrucción "select".
Podemos especificar el nombre de los campos que queremos ver separándolos por comas:
La lista de campos luego del "select" selecciona los datos correspondientes a los campos
nombrados. En el ejemplo anterior seleccionamos los campos "titulo" y "autor" de la tabla
"libros", mostrando todos los registros. Los datos aparecen ordenados según la lista de selección,
en dicha lista los nombres de los campos se separan con comas.
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
precio float,
cantidad integer
);
select table_name,column_name,udt_name,character_maximum_length
from information_schema.columns
Recordemos que en la pestaña "Data Output" se muestra el resultado del último comando
'select' ejecutado. Si queremos ver el resultado de otro 'select' debemos seleccionarlo y luego
volver a ejecutar:
137
138
6 - Recuperar algunos registros (where)
Existe una cláusula, "where" con la cual podemos especificar condiciones para una consulta
"select". Es decir, podemos recuperar algunos registros, sólo los que cumplan con ciertas
condiciones indicadas con la cláusula "where". Por ejemplo, queremos ver el usuario cuyo
nombre es "Marcelo", para ello utilizamos "where" y luego de ella, la condición:
from usuarios
where nombre='Marcelo';
from NOMBRETABLA
where CONDICION;
Para las condiciones se utilizan operadores relacionales (tema que trataremos más adelante en
detalle). El signo igual(=) es un operador relacional.
Para la siguiente selección de registros especificamos una condición que solicita los usuarios cuya
clave es igual a "River":
select nombre,clave
from usuarios
where clave='River';
Si ningún registro cumple la condición establecida con el "where", no aparecerá ningún registro.
select nombre
from usuarios
where clave='River';
En la consulta anterior solicitamos el nombre de todos los usuarios cuya clave sea igual a "River".
nombre varchar(30),
clave varchar(10)
);
select table_name,column_name,udt_name,character_maximum_length
from information_schema.columns
values ('Marcelo','Boca');
values ('JuanPerez','Juancito');
values ('Susana','River');
values ('Luis','River');
where nombre='Leonardo';
where clave='Santi';
where clave='River';
141
7 - Operadores relacionales
Los operadores relacionales (o de comparación) nos permiten comparar dos expresiones, que
pueden ser variables, valores de campos, etc.
Hemos aprendido a especificar condiciones de igualdad para seleccionar registros de una tabla;
por ejemplo:
where autor='Borges';
Los operadores relacionales vinculan un campo con un valor para que PostgreSQL compare cada
registro (el campo especificado) con el valor dado.
= igual like
Podemos seleccionar los registros cuyo autor sea diferente de "Borges", para ello usamos la
condición:
where autor<>'Borges';
Podemos comparar valores numéricos. Por ejemplo, queremos mostrar los títulos y precios de los
libros cuyo precio sea mayor a 20 euros:
from libros
where precio>20;
Queremos seleccionar los libros cuyo precio sea menor o igual a 30:
142
select * from libros
where precio<=30;
Los operadores relacionales comparan valores del mismo tipo. Se emplean para comprobar si un
campo cumple con una condición.
titulo varchar(30),
autor varchar(30),
editorial varchar(15),
precio float
);
where autor<>'Borges';
-- Seleccionamos los registros cuyo precio supere los 20 euros, sólo el título y
precio:
select titulo,precio
143
from libros
where precio>20;
where precio<=30;
144
8 - Borrar registros (delete) DML
Si no queremos eliminar todos los registros, sino solamente algunos, debemos indicar cuál o
cuáles, para ello utilizamos el comando "delete" junto con la clausula "where" con la cual
establecemos la condición que deben cumplir los registros a borrar.
Por ejemplo, queremos eliminar aquel registro cuyo nombre de usuario es "Marcelo":
where nombre='Marcelo';
Si solicitamos el borrado de un registro que no existe, es decir, ningún registro cumple con la
condición especificada, ningún registro será eliminado.
Tenga en cuenta que si no colocamos una condición, se eliminan todos los registros de la tabla
nombrada.
nombre varchar(30),
clave varchar(10)
);
values ('Marcelo','River');
values ('Susana','chapita');
values ('CarlosFuentes','Boca');
145
values ('FedericoLopez','Boca');
where nombre='Marcelo';
where nombre='Marcelo';
where clave='Boca';
146
La ejecución de este lote de comandos SQL genera una salida similar a:
147
9 - Actualizar registros (update) DML
Para modificar uno o varios datos de uno o varios registros utilizamos "update" (actualizar).
Por ejemplo, en nuestra tabla "usuarios", queremos cambiar los valores de todas las claves, por
"RealMadrid":
Utilizamos "update" junto al nombre de la tabla y "set" junto con el campo a modificar y su nuevo
valor.
Podemos modificar algunos registros, para ello debemos establecer condiciones de selección con
"where".
Por ejemplo, queremos cambiar el valor correspondiente a la clave de nuestro usuario llamado
"Federicolopez", queremos como nueva clave "Boca", necesitamos una condición "where" que
afecte solamente a este registro:
where nombre='Federicolopez';
Si PostgreSQL no encuentra registros que cumplan con la condición del "where", no se modifica
ninguno.
where nombre='Marcelo';
Para ello colocamos "update", el nombre de la tabla, "set" junto al nombre del campo y el nuevo
valor y separado por coma, el otro nombre del campo con su nuevo valor.
nombre varchar(20),
clave varchar(10)
148
);
values ('Marcelo','River');
values ('Susana','chapita');
values ('Carlosfuentes','Boca');
values ('Federicolopez','Boca');
where nombre='Federicolopez';
-- modifican registros:
where nombre='JuanaJuarez';
149
select * from usuarios;
where nombre='Marcelo';
-- Si vemos la tabla:
Seleccionemos con el mouse todas las instrucciones hasta el primer comando 'select' y luego
ejecutemos dicho bloque. Debe aparecer una salida similar a:
Ejecutemos luego los otros update y veamos cada uno de los resultados.
150
10 - Comentarios
Para aclarar algunas instrucciones, en ocasiones, necesitamos agregar comentarios.
Es posible ingresar comentarios en la línea de comandos, es decir, un texto que no se ejecuta;
para ello se emplean dos guiones (--) al comienzo de la línea:
en la línea anterior, todo lo que está luego de los guiones (hacia la derecha) no se ejecuta.
Para agregar varias líneas de comentarios, se coloca una barra seguida de un asterisco (/*) al
comienzo del bloque de comentario y al finalizarlo, un asterisco seguido de una barra (*/).
/*mostramos títulos y
from libros;
-- Creamos la tabla
nombre varchar(30),
clave varchar(10)
);
/*
nombre varchar(30),
clave varchar(10),
151
mail varchar(70)
);
*/
152
11 - Valores null (is null)
"null" significa "dato desconocido" o "valor inexistente". No es lo mismo que un valor "0", una
cadena vacía o una cadena literal "null".
Por ejemplo, en nuestra tabla de libros, podemos tener valores nulos en el campo "precio"
porque es posible que para algunos libros no le hayamos establecido el precio para la venta.
Veamos un ejemplo. Tenemos nuestra tabla "libros". El campo "titulo" no debería estar vacío
nunca, igualmente el campo "autor". Para ello, al crear la tabla, debemos especificar que dichos
campos no admitan valores nulos:
precio float
);
Para especificar que un campo no admita valores nulos, debemos colocar "not null" luego de la
definición del campo.
En el ejemplo anterior, los campos "editorial" y "precio" si admiten valores nulos.
Cuando colocamos "null" estamos diciendo que admite valores nulos (caso del campo
"editorial"); por defecto, es decir, si no lo aclaramos, los campos permiten valores nulos (caso del
campo "precio").
Si ingresamos los datos de un libro, para el cual aún no hemos definido el precio podemos colocar
"null" para mostrar que no tiene precio:
values('El aleph','Borges','Emece',null);
Note que el valor "null" no es una cadena de caracteres, no se coloca entre comillas.
Entonces, si un campo acepta valores nulos, podemos ingresar "null" cuando no conocemos el
valor.
Si intentamos ingresar el valor "null" en campos que no admiten valores nulos (como "titulo" o
"autor"), PostgreSQL no lo permite, muestra un mensaje y la inserción no se realiza; por ejemplo:
values(null,'Borges','Siglo XXI',25);
Para ver cuáles campos admiten valores nulos y cuáles no, podemos consultar el catálogo. Nos
muestra mucha información, en la columna "is_nullable" vemos que muestra "NO" en los campos
que no permiten valores nulos y "YES" en los campos que si los permiten.
select table_name,column_name,udt_name,character_maximum_length,is_nullable
from information_schema.columns
Para recuperar los registros que contengan el valor "null" en algún campo, no podemos utilizar
los operadores relacionales vistos anteriormente: = (igual) y <> (distinto); debemos utilizar los
operadores "is null" (es igual a null) y "is not null" (no es null):
where precio=0;
Con la primera sentencia veremos los libros cuyo precio es igual a "null" (desconocido); con la
segunda, los libros cuyo precio es 0.
Igualmente para campos de tipo cadena, las siguientes sentencias "select" no retornan los
mismos registros:
Con la primera sentencia veremos los libros cuya editorial es igual a "null", con la segunda, los
libros cuya editorial guarda una cadena vacía.
Entonces, para que un campo no permita valores nulos debemos especificarlo luego de definir el
campo, agregando "not null". Por defecto, los campos permiten valores nulos, pero podemos
especificarlo igualmente agregando "null".
154
create table libros(
precio float
);
values('El aleph','Borges','Emece',null);
--Para ver cuáles campos admiten valores nulos y cuáles no, empleamos:
select table_name,column_name,udt_name,character_maximum_length,is_nullable
from information_schema.columns
values('Uno','Richard Bach','',18.50);
-- Ingresamos otro registro, ahora cargamos una cadena vacía en el campo "titulo":
values('','Richard Bach','Planeta',22);
where precio=0;
-- Ahora veamos los libros cuya editorial almacena una cadena vacía:
where editorial='';
156
12 - Clave primaria
Una clave primaria es un campo (o varios) que identifica un solo registro (fila) en una tabla.
Para un valor del campo clave existe solamente un registro.
Veamos un ejemplo, si tenemos una tabla con datos de personas, el número de documento
puede establecerse como clave primaria, es un valor que no se repite; puede haber personas con
igual apellido y nombre, incluso el mismo domicilio (padre e hijo por ejemplo), pero su
documento será siempre distinto.
Si tenemos la tabla "usuarios", el nombre de cada usuario puede establecerse como clave
primaria, es un valor que no se repite; puede haber usuarios con igual clave, pero su nombre de
usuario será siempre diferente.
Podemos establecer que un campo sea clave primaria al momento de crear la tabla o luego que
ha sido creada. Vamos a aprender a establecerla al crear la tabla. Hay 2 maneras de hacerlo, por
ahora veremos la sintaxis más sencilla.
CAMPO TIPO,
...
);
En el siguiente ejemplo definimos una clave primaria, para nuestra tabla "usuarios" para
asegurarnos que cada usuario tendrá un nombre diferente y único:
nombre varchar(20),
clave varchar(10),
primary key(nombre)
);
Lo que hacemos agregar luego de la definición de cada campo, "primary key" y entre paréntesis,
el nombre del campo que será clave primaria.
Una tabla sólo puede tener una clave primaria. Cualquier campo (de cualquier tipo) puede ser
clave primaria, debe cumplir como requisito, que sus valores no se repitan ni sean nulos. Por ello,
al definir un campo como clave primaria, automáticamente PostgreSQL lo convierte a "not null".
Luego de haber establecido un campo como clave primaria, al ingresar los registros, PostgreSQL
controla que los valores para el campo establecido como clave primaria no estén repetidos en la
157
tabla; si estuviesen repetidos, muestra un mensaje y la inserción no se realiza. Es decir, si en
nuestra tabla "usuarios" ya existe un usuario con nombre "juanperez" e intentamos ingresar un
nuevo usuario con nombre "juanperez", aparece un mensaje y la instrucción "insert" no se
ejecuta.
Igualmente, si realizamos una actualización, PostgreSQL controla que los valores para el campo
establecido como clave primaria no estén repetidos en la tabla, si lo estuviese, aparece un
mensaje indicando que se viola la clave primaria y la actualización no se realiza.
nombre varchar(20),
clave varchar(10),
primary key(nombre)
);
-- Al campo "nombre" no lo definimos "not null", pero al establecerse como clave primaria,
-- PostgreSQL lo convierte en "not null", veamos que en la columna "is_nullable" aparece "NO":
select table_name,column_name,udt_name,character_maximum_length,is_nullable
from information_schema.columns
values ('juanperez','Boca');
values ('raulgarcia','River');
values ('juanperez','payaso');
values (null,'payaso');
Si realizamos alguna actualización, PostgreSQL controla que los valores para el campo
where nombre='raulgarcia';
*/
159
13 - Campo entero serial (autoincremento)
Para establecer que un campo autoincremente sus valores automáticamente, éste debe ser de
tipo serial:
codigo serial,
titulo varchar(20),
autor varchar(30),
editorial varchar(15),
);
Hasta ahora, al ingresar registros, colocamos el nombre de todos los campos antes de los valores;
es posible ingresar valores para algunos de los campos de la tabla, pero recuerde que al ingresar
los valores debemos tener en cuenta los campos que detallamos y el orden en que lo hacemos.
Cuando un campo es de tipo serial no es necesario ingresar valor para él, porque se inserta
automáticamente tomando el último valor como referencia, o 1 si es el primero.
Para ingresar registros omitimos el campo definido como serial, por ejemplo:
values('El aleph','Borges','Planeta');
Más adelante cuando veamos el concepto de secuencias veremos que los campos serial son el
realidad un campo int que tienen asociado una "secuencia".
Un campo serial podemos indicar el valor en el insert, pero en la siguiente inserción que hagamos
la secuencia continúa en el último valor generado automáticamente. Puede tener sentido utilizar
160
esta característica para reutilizar un código de un campo borrado, por ejemplo si en la tabla libros
borramos el libro con el código 1, luego podemos insertar otro libro con dicho código:
codigo serial,
titulo varchar(30),
autor varchar(30),
editorial varchar(15),
);
select table_name,column_name,udt_name,character_maximum_length,is_nullable
from information_schema.columns
values('El aleph','Borges','Planeta');
-- Note que al detallar los campos para los cuales ingresaremos valores hemos
-- ingresar los datos de todos los campos que se detallan y en el mismo orden.
161
-- Si mostramos los registros:
values('Cervantes y el quijote','Borges','Paidos');
-- Insertamos un nuevo libro e indicamos el valor que debe tomar el campo serial:
-- Luego si insertamos otro registro sin indicar el valor del campo serial el valor
La ejecución de parte de este lote de comandos SQL genera una salida similar a:
163
14 - Comando truncate table
Aprendimos que para borrar todos los registro de una tabla se usa "delete" sin condición
"where".
También podemos eliminar todos los registros de una tabla con "truncate table". Por ejemplo,
queremos vaciar la tabla "libros", usamos:
La sentencia "truncate table" vacía la tabla (elimina todos los registros) y vuelve a crear la tabla
con la misma estructura.
La diferencia con "drop table" es que esta sentencia borra la tabla, "truncate table" la vacía.
La diferencia con "delete" es la velocidad, es más rápido "truncate table" que "delete" (se nota
cuando la cantidad de registros es muy grande) ya que éste borra los registros uno a uno.
codigo serial,
titulo varchar(30),
autor varchar(30),
editorial varchar(15),
);
values('Cervantes y el quijote','Borges','Paidos');
-- Veamos el resultado:
-- Veamos el resultado:
-- más alto de ese campo, antes de eliminar todos los registros era "5".
-- Veamos qué sucede si ingresamos otro registro sin valor para el código:
-- Ejecutamos entonces:
165
select * from libros;
166
15 - Tipo de dato texto
Ya explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir los
campos y sus tipos más precisos, según el caso.
char(x): define una cadena de longitud fija determinada por el argumento "x". Su rango es de 1 a
10485760 caracteres.
Si la longitud es invariable, es conveniente utilizar el tipo char; caso contrario, el tipo varchar.
"char" viene de character, que significa caracter en inglés.
text: define una cadena de longitud variable, podemos almacenar una cadena de hasta 1GB
(podemos utilizar las palabras claves character varying en lugar de text).
Por ejemplo, si definimos un campo de tipo varchar(10) y le asignamos la cadena 'Aprenda PHP'
(11 caracteres), aparece un mensaje y la sentencia no se ejecuta.
Si ingresamos un valor numérico (omitiendo las comillas), lo convierte a cadena y lo ingresa como
tal.
Por ejemplo, si en un campo definido como varchar(5) ingresamos el valor 12345, lo toma como
si hubiésemos tipeado '12345', igualmente, si ingresamos el valor 23.56, lo convierte a '23.56'. Si
el valor numérico, al ser convertido a cadena supera la longitud definida, aparece un mensaje de
error y la sentencia no se ejecuta.
Para almacenar cadenas que varían en su longitud, es decir, no todos los registros tendrán la
misma longitud en un campo determinado, se emplea "varchar" en lugar de "char".
Por ejemplo, en campos que guardamos nombres y apellidos, no todos los nombres y apellidos
tienen la misma longitud.
167
Para almacenar cadenas que no varían en su longitud, es decir, todos los registros tendrán la
misma longitud en un campo determinado, se emplea "char".
Por ejemplo, definimos un campo "codigo" que constará de 5 caracteres, todos los registros
tendrán un código de 5 caracteres, ni más ni menos.
Con PostgreSQL podemos utilizar como sinónimos las palabras claves 'character varying(n)' en
lugar de 'varchar(n)', igualmente la palabra 'character(n)' remplazando a 'char(n)'.
nombre varchar(30),
edad integer,
sexo char(1),
domicilio varchar(30),
ciudad varchar(20),
telefono varchar(11)
);
edad integer,
sexo character(1),
);
-- Insertamos un registro:
169
16 - Tipo de dato numérico
Ya explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir los
campos y sus tipos más precisos, según el caso.
Para almacenar valores ENTEROS, por ejemplo, en campos que hacen referencia a cantidades,
usamos:
2) smallint (int2): Puede contener hasta 5 digitos. Su rango va desde –32767 hasta 32767.
Para almacenar valores numéricos EXACTOS con decimales, especificando la cantidad de cifras a
la izquierda y derecha del separador decimal, utilizamos:
4) decimal o numeric (t,d): Pueden tener hasta 1000 digitos, guarda un valor exacto. El primer
argumento indica el total de dígitos y el segundo, la cantidad de decimales.
Por ejemplo, si queremos almacenar valores entre -99.99 y 99.99 debemos definir el campo
como tipo "decimal(4,2)". Si no se indica el valor del segundo argumento, por defecto es "0". Por
ejemplo, si definimos "decimal(4)" se pueden guardar valores entre -9999 y 9999.
Si ingresamos un valor con más decimales que los permitidos, redondea al más cercano; por
ejemplo, si definimos "decimal(4,2)" e ingresamos el valor "12.686", guardará "12.69",
redondeando hacia arriba; si ingresamos el valor "12.682", guardará "12.68", redondeando hacia
abajo.
Para almacenar valores numéricos APROXIMADOS con decimales utilizamos:
Es importante elegir el tipo de dato adecuado según el caso, el más preciso. Por ejemplo, si un
campo numérico almacenará valores positivos menores a 255, el tipo "int" no es el más
adecuado, conviene el tipo "smallint", de esta manera usamos el menor espacio de
almacenamiento posible.
codigo serial,
autor varchar(30),
editorial varchar(15),
precio decimal(10,2),
cantidad smallint,
);
values('El aleph','Borges','Emece',25000,100000);
172
17 - Tipo de dato fecha y hora
Ya explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir los
campos y sus tipos más precisos, según el caso.
Para almacenar valores de tipo FECHA Y HORA PostgreSQL dispone de tres tipos:
1) date: almacena una fecha en el rango de 4713 antes de crísto hasta 32767 después de cristo.
Para almacenar valores de tipo fecha se permiten como separadores "/", "-","." entre otros.
Con el ejemplo anterior luego podemos ingresar una fecha con el formato Europeo que es
dd/mm/aaaa:
173
German utiliza [Link] para la representación numérica de las fechas.
Para almacenar solo la hora debemos utilizar el tipo time. En un campo tipo time podemos
almacenar un valor en el rango: 00:00:00.00 23:59:59.99.
Por último si queremos almacenar la fecha y la hora en un único campo debemos definirlo de
tipo timestamp:
dni char(8),
fecha date,
hora time,
);
-- Ingresamos un registro:
-- Mostramos el registro:
-- Borramos la tabla:
174
drop table asistencia;
dni char(8),
fechahora timestamp,
);
-- Ingresamos un registro:
-- Mostramos el registro:
-- Mostramos el registro:
175
176
18 - Valores por defecto (default)
Hemos visto que si al insertar registros no se especifica un valor para un campo que admite
valores nulos, se ingresa automáticamente "null" y si el campo está declarado serial o bigserial, se
inserta el siguiente de la secuencia. A estos valores se les denomina valores por defecto o
predeterminados.
Para campos de cualquier tipo no declarados "not null", es decir, que admiten valores nulos, el
valor por defecto es "null". Para campos declarados "not null", no existe valor por defecto, a
menos que se declare explícitamente con la cláusula "default".
Para todos los tipos, excepto los declarados serial, se pueden explicitar valores por defecto con la
cláusula "default".
Podemos establecer valores por defecto para los campos cuando creamos la tabla. Para ello
utilizamos "default" al definir el campo. Por ejemplo, queremos que el valor por defecto del
campo "autor" de la tabla "libros" sea "Desconocido" y el valor por defecto del campo "cantidad"
sea "0":
codigo serial,
titulo varchar(40),
editorial varchar(20),
precio decimal(5,2),
primary key(codigo)
);
Si al ingresar un nuevo registro omitimos los valores para el campo "autor" y "cantidad",
PostgreSQL insertará los valores por defecto; el siguiente valor de la secuencia en "codigo", en
"autor" colocará "Desconocido" y en cantidad "0".
Entonces, si al definir el campo explicitamos un valor mediante la cláusula "default", ése será el
valor por defecto.
También se puede utilizar "default" para dar el valor por defecto a los campos en sentencias
"insert", por ejemplo:
177
insert into libros (titulo,autor,precio,cantidad)
Si todos los campos de una tabla tienen valores predeterminados (ya sea por ser "identity",
permitir valores nulos o tener un valor por defecto), se puede ingresar un registro de la siguiente
manera:
La sentencia anterior almacenará un registro con los valores predetermiandos para cada uno de
sus campos.
Los campos para los cuales no se ingresan valores en un "insert" tomarán los valores por defecto:
- si está declarado explícitamente "not null", no tiene valor "default" y no tiene el atributo
"identity", no hay valor por defecto, así que causará un error y el "insert" no se ejecutará.
- si tiene cláusula "default" (admita o no valores nulos), el valor definido como predeterminado;
- para campos de tipo fecha y hora, si omitimos la parte de la fecha, el valor predeterminado para
la fecha es "1900-01-01" y si omitimos la parte de la hora, "00:00:00".
Un campo sólo puede tener un valor por defecto. Una tabla puede tener todos sus campos con
valores por defecto. Que un campo tenga valor por defecto no significa que no admita valores
nulos, puede o no admitirlos.
codigo serial,
titulo varchar(40),
editorial varchar(20),
precio decimal(5,2),
178
primary key(codigo)
);
values('Java en 10 minutos','Paidos',50.40);
select *
from information_schema.columns
-- Podemos emplear "default" para dar el valor por defecto a algunos campos:
179
-- Como todos los campos de "libros" tienen valores predeterminados, podemos tipear:
-- Que un campo tenga valor por defecto no significa que no admita valores nulos,
180
19 - Columnas calculadas (operadores
aritméticos y de concatenación)
Aprendimos que los operadores son símbolos que permiten realizar distintos tipos de
operaciones.
Dijimos que PostgreSQL tiene 4 tipos de operadores: 1) relacionales o de comparación (los
vimos), 2) lógicos (lo veremos más adelante, 3) aritméticos y 4) de concatenación.
Es posible obtener salidas en las cuales una columna sea el resultado de un cálculo y no un
campo de una tabla.
Si queremos ver los títulos, precio y cantidad de cada libro escribimos la siguiente sentencia:
select titulo,precio,cantidad
from libros;
Si queremos saber el monto total en dinero de un título podemos multiplicar el precio por la
cantidad por cada título, pero también podemos hacer que PostgreSQL realice el cálculo y lo
incluya en una columna extra en la salida:
precio*cantidad
from libros;
Si queremos saber el precio de cada libro con un 10% de descuento podemos incluir en la
sentencia los siguientes cálculos:
select titulo,precio,
precio-(precio*0.1)
from libros;
select 5/0;
181
Los operadores de concatenación: permite concatenar cadenas, el más (||).
select titulo||'-'||autor||'-'||editorial
from libros;
Note que concatenamos además unos guiones para separar los campos.
codigo serial,
editorial varchar(20),
precio decimal(6,2),
);
values('El aleph','Borges','Emece',25);
182
precio*cantidad
from libros;
select titulo,precio,
precio-(precio*0.1)
from libros;
select titulo||'-'||autor||'-'||editorial
from libros;
183
20 - Alias
Una manera de hacer más comprensible el resultado de una consulta consiste en cambiar los
encabezados de las columnas.
Por ejemplo, tenemos la tabla "agenda" con un campo "nombre" (entre otros) en el cual se
almacena el nombre y apellido de nuestros amigos; queremos que al mostrar la información de
dicha tabla aparezca como encabezado del campo "nombre" el texto "nombre y apellido", para
ello colocamos un alias de la siguiente manera:
domicilio,telefono
from agenda;
Para reemplazar el nombre de un campo por otro, se coloca la palabra clave "as" seguido del
texto del encabezado.
Entonces, un "alias" se usa como nombre de un campo o de una expresión. En estos casos, son
opcionales, sirven para hacer más comprensible el resultado; en otros casos, que veremos más
adelante, son obligatorios.
nombre varchar(30),
domicilio varchar(30),
telefono varchar(11)
);
184
values('Carlos Garcia','Sarmiento 1258',null);
domicilio,telefono
from agenda;
domicilio,telefono
from agenda;
185
21 - Funciones para el manejo de cadenas
PostgreSQL tiene funciones para trabajar con cadenas de caracteres. Estas son algunas:
select char_length('Hola');
retorna un 4.
select upper('Hola');
retorna 'HOLA'.
select lower('Hola');
retorna 'hola'.
retorna 6.
retorna 0 (ya que no coinciden mayúsculas y minúsculas, EN MYSQL devuelve un 6 no es tan esquisito con
las mayusculas/minusculas como postgresql)
substring(string [from int] [for int]): Retorna un substring, le indicamos la posición inicial y la
cantidad de caracteres a extraer desde dicha posición. Ejemplo:
retorna 'Ho'.
retorna 'Mundo'.
186
trim([leading|trailing|both] [string] from string): Elimina caracteres del principio o o final de un
string. Por defecto elimina los espacios en blanco si no indicamos el caracter o string. Ejemplo:
retorna un 10. Esto es debido a que primero se ejecuta la función trim que elimina los dos
espacios iniciales y los dos finales.
retorna un 12. Esto es debido a indicamos que elimine los espacios en blanco de la cadena solo
del comienzo (leading).
retorna '--Hola Mundo'. Esto es debido a indicamos que elimine los guiones del final del stirng.
ltrim(string,string): Elimina los caracteres de la izquierda según el dato del segundo parámetro de
la función. Ejemplo:
retorna un 4.
select ltrim('---Hola','-');
retorna 'Hola'.
rtrim(string,string): Elimina los caracteres de la derecha según el dato del segundo parámetro de
la función. Ejemplo:
retorna un 4.
select rtrim('Hola----','-');
retorna un 'Hola'.
retorna 'ola'.
retorna 'ola Mundo' (si no indicamos el tercer parámetro retorna todo el string hasta el final)
187
lpad(text,int,text): Rellena de caracteres por la izquierda. El tamaño total de campo es indicado
por el segundo parámetro y el texto a insertar se indica en el tercero. Ejemplo:
codigo serial,
editorial varchar(20),
precio decimal(6,2),
);
values('El aleph','Borges','Emece',25);
188
values('Java en 10 minutos','Mario Molina','Siglo XXI',50.40,100);
from libros;
from libros;
select *
from libros
-- Imprimimos todos los libros que tienen un título con 10 o más caracteres:
select *
from libros
where char_length(titulo)>=10;
189
190
22 - Funciones matemáticas
PostgreSQL tiene algunas funciones para trabajar con números. Aquí presentamos algunas.
select abs(-20);
retorna 20.
select cbrt(27);
retorna 3.
select ceiling(12.34);
retorna 13.
select floor(12.34);
retorna 12.
select power(2,3);
retorna 8.
select round(10.4);
retorna "10".
191
sign(x): si el argumento es un valor positivo devuelve 1;-1 si es negativo y si es 0, 0. Ejemplo:
select sign(-23.4);
retorna "-1".
sqrt(x): devuelve la raíz cuadrada del valor enviado como argumento. Ejemplo:
select sqrt(9);
retorna "3".
select mod(11,2);
retorna "1".
select pi();
retorna "3.14159265358979".
select random();
select trunc(34.7);
retorna "34".
trunc(x,decimales): Retorna la parte entera del parámetro y la parte decimal truncando hasta el
valor indicado en el segundo parámetro. Ejemplo:
select trunc(34.7777,2);
retorna "34.77".
192
sin(x): Retorna el valor del seno en radianes. Ejemplo:
select sin(0);
retorna "0".
select cos(0);
retorna "1".
select tan(0);
retorna "0".
codigo serial,
editorial varchar(20),
precio decimal(9,2),
);
values('El aleph','Borges','Emece',25.33);
select titulo,autor,precio,
floor(precio) as abajo,
ceiling(precio) as arriba
from libros;
194
23 - Funciones para el uso de fechas y horas
PostgreSQL ofrece algunas funciones para trabajar con fechas y horas. Estas son algunas:
select current_date;
select current_time;
select current_timestamp;
- extract(valor from timestamp): retorna una parte de la fecha u hora según le indiquemos antes
del from, luego del from debemos indicar un campo o valor de tipo timestamp (o en su defecto
anteceder la palabra clave timestamp para convertirlo). Ejemplo:
editorial varchar(20),
edicion timestamp,
precio decimal(6,2)
);
values('El aleph','Borges','Emece','1980/10/10',25.33);
197
24 - Ordenar registros (order by)
Podemos ordenar el resultado de un "select" para que los registros se muestren ordenados por
algún campo, para ello usamos la cláusula "order by".
order by CAMPO;
Por ejemplo, recuperamos los registros de la tabla "libros" ordenados por el título:
order by titulo;
También podemos colocar el número de orden del campo por el que queremos que se ordene en
lugar de su nombre, es decir, referenciar a los campos por su posición en la lista de selección. Por
ejemplo, queremos el resultado del "select" ordenado por "precio":
select titulo,autor,precio
Por defecto, si no aclaramos en la sentencia, los ordena de manera ascendente (de menor a
mayor).
Podemos ordenarlos de mayor a menor, para ello agregamos la palabra clave "desc":
select * libros
También podemos ordenar por varios campos, por ejemplo, por "titulo" y "editorial":
order by titulo,editorial;
Incluso, podemos ordenar en distintos sentidos, por ejemplo, por "titulo" en sentido ascendente
y "editorial" en sentido descendente:
Debe aclararse al lado de cada campo, pues estas palabras claves afectan al campo
inmediatamente anterior.
codigo serial,
editorial varchar(20),
precio decimal(6,2),
);
values('El aleph','Borges','Emece',25.33);
select titulo,autor,precio
order by titulo,editorial;
from libros
order by precio;
precio+(precio*0.1) as preciocondescuento
from libros
order by 4;
order by titulo;
200
201
25 - Operadores lógicos (and - or - not)
Hasta el momento, hemos aprendido a establecer una condición con "where" utilizando
operadores relacionales. Podemos establecer más de una condición con la cláusula "where", para
ello aprenderemos los operadores lógicos.
- (), paréntesis
Si queremos recuperar todos los libros cuyo autor sea igual a "Borges" y cuyo precio no supere
los 20 euros, necesitamos 2 condiciones:
(precio<=20);
Los registros recuperados en una sentencia que une 2 condiciones con el operador "and",
cumplen con las 2 condiciones.
Queremos ver los libros cuyo autor sea "Borges" y/o cuya editorial sea "Planeta":
where autor='Borges' or
editorial='Planeta';
En la sentencia anterior usamos el operador "or"; indicamos que recupere los libros en los cuales
el valor del campo "autor" sea "Borges" y/o el valor del campo "editorial" sea "Planeta", es decir,
seleccionará los registros que cumplan con la primera condición, con la segunda condición o con
ambas condiciones.
Los registros recuperados con una sentencia que une 2 condiciones con el operador "or",
cumplen 1 de las condiciones o ambas.
Queremos recuperar los libros que NO cumplan la condición dada, por ejemplo, aquellos cuya
editorial NO sea "Planeta":
Los registros recuperados en una sentencia en la cual aparece el operador "not", no cumplen con
la condición a la cual afecta el "NOT".
Los paréntesis se usan para encerrar condiciones, para que se evalúen como una sola expresión.
Cuando explicitamos varias condiciones con diferentes operadores lógicos (combinamos "and",
"or") permite establecer el orden de prioridad de la evaluación; además permite diferenciar las
expresiones más claramente.
where (autor='Borges') or
(precio<20);
Si bien los paréntesis no son obligatorios en todos los casos, se recomienda utilizarlos para evitar
confusiones.
El orden de prioridad de los operadores lógicos es el siguiente: "not" se aplica antes que "and" y
"and" antes que "or", si no se especifica un orden de evaluación mediante el uso de paréntesis.
El orden en el que se evalúan los operadores con igual nivel de precedencia es indefinido, por ello
se recomienda usar los paréntesis.
Entonces, para establecer más de una condición en un "where" es necesario emplear operadores
lógicos. "and" significa "y", indica que se cumplan ambas condiciones; "or" significa "y/o", indica
que se cumpla una u otra condición (o ambas); "not" significa "no", indica que no se cumpla la
condición especificada.
codigo serial,
editorial varchar(20),
203
precio decimal(6,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',15.90);
values('Antología poética','Borges','Planeta',39.50);
values('Cervantes y el quijote','Borges','Paidos',18.40);
--Seleccionamos los libros cuyo autor es "Borges" y/o cuya editorial es "Planeta":
where autor='Borges' or
editorial='Planeta';
where (autor='Borges') or
(precio<20);
(precio<=20);
205
26 - Otros operadores relacionales (is null)
Hemos aprendido los operadores relacionales "=" (igual), "<>" (distinto), ">" (mayor), "<"
(menor), ">=" (mayor o igual) y "<=" (menor o igual). Dijimos que no eran los únicos.
Se emplea el operador "is null" para recuperar los registros en los cuales esté almacenado el valor
"null" en un campo específico:
Para obtener los registros que no contiene "null", se puede emplear "is not null", esto mostrará
los registros con valores conocidos.
Siempre que sea posible, emplee condiciones de búsqueda positivas ("is null"), evite las negativas
("is not null") porque con ellas se evalúan todos los registros y esto hace más lenta la
recuperación de los datos.
codigo serial,
editorial varchar(20),
precio decimal(6,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',15.90);
values('Cervantes y el quijote','Borges','Paidos',null);
206
insert into libros(titulo,autor,editorial,precio)
values('Antología poética','Borges',25.50);
-- en el campo "editorial":
207
27 - Otros operadores relacionales (between)
Hemos visto los operadores relacionales: = (igual), <> (distinto), > (mayor), < (menor), >= (mayor
o igual), <= (menor o igual), is null/is not null (si un valor es NULL o no).
Hasta ahora, para recuperar de la tabla "libros" los libros con precio mayor o igual a 20 y menor o
igual a 40, usamos 2 condiciones unidas por el operador lógico "and":
precio<=40;
Averiguamos si el valor de un campo dado (precio) está entre los valores mínimo y máximo
especificados (20 y 40 respectivamente).
Siempre que sea posible, emplee condiciones de búsqueda positivas ("between"), evite las
negativas ("not between") porque hace más lenta la recuperación de los datos.
Entonces, se puede usar el operador "between" para reducir las condiciones "where".
208
codigo serial,
editorial varchar(20),
precio decimal(6,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',15.90);
values('Cervantes y el quijote','Borges','Paidos',null);
values('Antología poética','Borges',32);
-- Para seleccionar los libros cuyo precio NO esté entre un intervalo de valores
210
28 - Otros operadores relacionales (in)
Se utiliza "in" para averiguar si el valor de un campo está incluido en una lista de valores
especificada.
En la siguiente sentencia usamos "in" para averiguar si el valor del campo autor está incluido en
la lista de valores especificada (en este caso, 2 cadenas).
Hasta ahora, para recuperar los libros cuyo autor sea 'Paenza' o 'Borges' usábamos 2 condiciones:
Para recuperar los libros cuyo autor no sea 'Paenza' ni 'Borges' usábamos:
autor<>'Paenza';
Empleando "in" averiguamos si el valor del campo está incluido en la lista de valores especificada;
con "not" antecediendo la condición, invertimos el resultado, es decir, recuperamos los valores
que no se encuentran (coinciden) con la lista de valores.
Recuerde: siempre que sea posible, emplee condiciones de búsqueda positivas ("in"), evite las
negativas ("not in") porque con ellas se evalúan todos los registros y esto hace más lenta la
recuperación de los datos.
211
codigo serial,
autor varchar(20),
editorial varchar(20),
precio decimal(6,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',15.90);
values('Cervantes y el quijote','Borges','Paidos',null);
values('Antología poética',32);
213
29 - Búsqueda de patrones (like - not like)
Existe un operador relacional que se usa para realizar comparaciones exclusivamente de cadenas,
"like" y "not like".
Hemos realizado consultas utilizando operadores relacionales para comparar cadenas. Por
ejemplo, sabemos recuperar los libros cuyo autor sea igual a la cadena "Borges":
where autor='Borges';
El operador igual ("=") nos permite comparar cadenas de caracteres, pero al realizar la
comparación, busca coincidencias de cadenas completas, realiza una búsqueda exacta.
where autor='Borges';
sólo aparecerá el primer registro, ya que la cadena "Borges" no es igual a la cadena "J.L. Borges".
Esto sucede porque el operador "=" (igual), también el operador "<>" (distinto) comparan
cadenas de caracteres completas. Para comparar porciones de cadenas utilizamos los operadores
"like" y "not like".
Entonces, podemos comparar trozos de cadenas de caracteres para realizar consultas. Para
recuperar todos los registros cuyo autor contenga la cadena "Borges" debemos tipear:
Note que el símbolo "%" ya no está al comienzo, con esto indicamos que el título debe tener
como primera letra la "M" y luego, cualquier cantidad de caracteres.
214
Para seleccionar todos los libros que NO comiencen con "M":
Así como "%" reemplaza cualquier cantidad de caracteres, el guión bajo "_" reemplaza un
caracter, es otro caracter comodín. Por ejemplo, queremos ver los libros de "Lewis Carroll" pero
no recordamos si se escribe "Carroll" o "Carrolt", entonces tipeamos esta condición:
"like" se emplea con tipos de datos char, varchar, date, time, timestamp. Si empleamos "like" con
tipos de datos que no son caracteres utilizamos el comando 'cast' convirtiendo éste al tipo de
dato. Por ejemplo, queremos buscar todos los libros cuyo precio se encuentre entre 10.00 y
19.99:
codigo serial,
editorial varchar(20),
precio decimal(6,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',15.90);
215
insert into libros(titulo,autor,editorial,precio)
-- Recuperamos todos los libros que contengan en el campo "autor" la cadena "Borges":
-- Si queremos ver los libros de "Lewis Carroll" pero no recordamos si se escribe "Carroll"
-- o "Carrolt", podemos emplear el comodín "_" (guión bajo) y establecer la siguiente condición:
-- Recuperamos todos los libros cuyo precio se encuentra entre 10.00 y 19.99:
216
select titulo,precio from libros
217
30 - Contar registros (count)
Existen en PostgreSQL funciones que nos permiten contar registros, calcular sumas, promedios,
obtener valores máximos y mínimos. Estas funciones se denominan funciones de agregado y
operan sobre un conjunto de valores (registros), no con datos individuales y devuelven un único
valor.
Imaginemos que nuestra tabla "libros" contiene muchos registros. Para averiguar la cantidad sin
necesidad de contarlos manualmente usamos la función "count()":
select count(*)
from libros;
La función "count()" cuenta la cantidad de registros de una tabla, incluyendo los que tienen valor
nulo.
También podemos utilizar esta función junto con la cláusula "where" para una consulta más
específica. Queremos saber la cantidad de libros de la editorial "Planeta":
select count(*)
from libros
where editorial='Planeta';
Para contar los registros que tienen precio (sin tener en cuenta los que tienen valor nulo),
usamos la función "count()" y en los paréntesis colocamos el nombre del campo que necesitamos
contar:
select count(precio)
from libros;
Note que "count(*)" retorna la cantidad de registros de una tabla (incluyendo los que tienen
valor "null") mientras que "count(precio)" retorna la cantidad de registros en los cuales el campo
"precio" no es nulo. No es lo mismo. "count(*)" cuenta registros, si en lugar de un asterisco
colocamos como argumento el nombre de un campo, se contabilizan los registros cuyo valor en
ese campo NO es nulo.
codigo serial,
editorial varchar(20),
precio decimal(6,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',15.90);
values('Uno','Richard Bach','Planeta',20);
select count(*)
from libros;
-- Note que incluye todos los libros aunque tengan valor nulo en algún campo.
select count(*)
from libros
219
where editorial='Planeta';
-- Contamos los registros que tienen precio (sin tener en cuenta los que
select count(precio)
from libros;
220
31 - Funciones de agrupamiento (count - sum -
min - max - avg)
Hemos visto que PosgreSQL tiene funciones que nos permiten contar registros, calcular sumas,
promedios, obtener valores máximos y mínimos, las funciones de agregado.
Se pueden usar en una instrucción "select" y combinarlas con la cláusula "group by".
Todas estas funciones retornan "null" si ningún registro cumple con la condición del "where",
excepto "count" que en tal caso retorna cero.
El tipo de dato del campo determina las funciones que se pueden emplear con ellas.
Las relaciones entre las funciones de agrupamiento y los tipos de datos es la siguiente:
La función "sum()" retorna la suma de los valores que contiene el campo especificado. Si
queremos saber la cantidad total de libros que tenemos disponibles para la venta, debemos
sumar todos los valores del campo "cantidad":
select sum(cantidad)
from libros;
Para averiguar el valor máximo o mínimo de un campo usamos las funciones "max()" y "min()"
respectivamente.
Queremos saber cuál es el mayor precio de todos los libros:
select max(precio)
from libros;
Entonces, dentro del paréntesis de la función colocamos el nombre del campo del cuál queremos
el máximo valor.
La función "avg()" retorna el valor promedio de los valores del campo especificado. Queremos
saber el promedio del precio de los libros referentes a "PHP":
select avg(precio)
from libros
221
Ahora podemos entender porque estas funciones se denominan "funciones de agrupamiento",
porque operan sobre conjuntos de registros, no con datos individuales.
Si realiza una consulta con la función "count" de un campo que contiene 18 registros, 2 de los
cuales contienen valor nulo, el resultado devuelve un total de 16 filas porque no considera
aquellos con valor nulo.
Todas las funciones de agregado, excepto "count(*)", excluye los valores nulos de los campos.
"count(*)" cuenta todos los registros, incluidos los que contienen "null".
codigo serial,
editorial varchar(15),
precio decimal(5,2),
cantidad smallint,
primary key(codigo)
);
values('El aleph','Borges','Planeta',15,null);
222
values('Cervantes y el quijote','Bioy Casares- J.L. Borges','Paidos',null,100);
values('PHP de la A a la Z',default,0);
-- Para conocer la cantidad total de libros, sumamos las cantidades de cada uno:
select sum(cantidad)
from libros;
select sum(cantidad)
from libros
where editorial='Emece';
select max(precio)
from libros;
select min(precio)
from libros
select avg(precio)
from libros
224
32 - Agrupar registros (group by)
Hemos aprendido que las funciones de agregado permiten realizar varios cálculos operando con
conjuntos de registros.
Las funciones de agregado solas producen un valor de resumen para todos los registros de un
campo. Podemos generar valores de resumen para un solo campo, combinando las funciones de
agregado con la cláusula "group by", que agrupa registros para consultas detalladas.
Queremos saber la cantidad de libros de cada editorial, podemos tipear la siguiente sentencia:
where editorial='Planeta';
where editorial='Emece';
where editorial='Paidos';
...
from libros
group by editorial;
Entonces, para saber la cantidad de libros que tenemos de cada editorial, utilizamos la función
"count()", agregamos "group by" (que agrupa registros) y el campo por el que deseamos que se
realice el agrupamiento, también colocamos el nombre del campo a recuperar; la sintaxis básica
es la siguiente:
225
from NOMBRETABLA
group by CAMPO;
También se puede agrupar por más de un campo, en tal caso, luego del "group by" se listan los
campos, separados por comas. Todos los campos que se especifican en la cláusula "group by"
deben estar en la lista de selección.
from NOMBRETABLA
group by CAMPO1,CAMPO2;
Para obtener la cantidad libros con precio no nulo, de cada editorial utilizamos la función
"count()" enviándole como argumento el campo "precio", agregamos "group by" y el campo por
el que deseamos que se realice el agrupamiento (editorial):
from libros
group by editorial;
Como resultado aparecen los nombres de las editoriales y la cantidad de registros de cada una,
sin contar los que tienen precio nulo.
Recuerde la diferencia de los valores que retorna la función "count()" cuando enviamos como
argumento un asterisco o el nombre de un campo: en el primer caso cuenta todos los registros
incluyendo los que tienen valor nulo, en el segundo, los registros en los cuales el campo
especificado es no nulo.
from libros
group by editorial;
Para saber el máximo y mínimo valor de los libros agrupados por editorial:
select editorial,
max(precio) as mayor,
min(precio) as menor
from libros
group by editorial;
Para calcular el promedio del valor de los libros agrupados por editorial:
group by editorial;
Si incluye una cláusula "where", sólo se agrupan los registros que cumplen las condiciones.
Vamos a contar y agrupar por editorial considerando solamente los libros cuyo precio sea menor
a 30 euros:
from libros
where precio<30
group by editorial;
codigo serial,
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
precio decimal(5,2),
cantidad smallint,
primary key(codigo)
);
values('El aleph','Borges','Planeta',15,null);
227
insert into libros(titulo,autor,editorial,precio,cantidad)
values('PHP de la A a la Z',null,null,null,0);
-- Queremos saber la cantidad de libros de cada editorial, utilizando la cláusula "group by":
from libros
group by editorial;
from libros
group by editorial;
--Para conocer el total en dinero de los libros agrupados por editorial, tipeamos:
from libros
group by editorial;
228
-- Obtenemos el máximo y mínimo valor de los libros agrupados por editorial,
select editorial,
max(precio) as mayor,
min(precio) as menor
from libros
group by editorial;
from libros
group by editorial;
-- Es posible limitar la consulta con "where". Vamos a contar y agrupar por editorial
from libros
where precio<30
group by editorial;
229
230
33 - Seleccionar grupos (having)
Así como la cláusula "where" permite seleccionar (o rechazar) registros individuales; la cláusula
"having" permite seleccionar (o rechazar) un grupo de registros.
Si queremos saber la cantidad de libros agrupados por editorial usamos la siguiente instrucción ya
aprendida:
from libros
group by editorial;
Si queremos saber la cantidad de libros agrupados por editorial pero considerando sólo algunos
grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instrucción:
group by editorial
having count(*)>2;
Se utiliza "having", seguido de la condición de búsqueda, para seleccionar ciertas filas retornadas
por la cláusula "group by".
Veamos otros ejemplos. Queremos el promedio de los precios de los libros agrupados por
editorial, pero solamente de aquellos grupos cuyo promedio supere los 25 euros:
group by editorial
having avg(precio)>25;
En algunos casos es posible confundir las cláusulas "where" y "having". Queremos contar los
registros agrupados por editorial sin tener en cuenta a la editorial "Planeta".
Analicemos las siguientes sentencias:
where editorial<>'Planeta'
group by editorial;
group by editorial
having editorial<>'Planeta';
231
Ambas devuelven el mismo resultado, pero son diferentes. La primera, selecciona todos los
registros rechazando los de editorial "Planeta" y luego los agrupa para contarlos. La segunda,
selecciona todos los registros, los agrupa para contarlos y finalmente rechaza fila con la cuenta
correspondiente a la editorial "Planeta".
Veamos otros ejemplos combinando "where" y "having". Queremos la cantidad de libros, sin
considerar los que tienen precio nulo, agrupados por editorial, sin considerar la editorial
"Planeta":
group by editorial
having editorial<>'Planeta';
Aquí, selecciona los registros rechazando los que no cumplan con la condición dada en "where",
luego los agrupa por "editorial" y finalmente rechaza los grupos que no cumplan con la condición
dada en el "having".
Se emplea la cláusula "having" con funciones de agrupamiento, esto no puede hacerlo la cláusula
"where". Por ejemplo queremos el promedio de los precios agrupados por editorial, de aquellas
editoriales que tienen más de 2 libros:
group by editorial
Podemos encontrar el mayor valor de los libros agrupados y ordenados por editorial y seleccionar
las filas que tengan un valor menor a 100 y mayor a 30:
from libros
group by editorial
min(precio)>30
order by editorial;
Entonces, usamos la cláusula "having" para restringir las filas que devuelve una salida "group by".
Va siempre después de la cláusula "group by" y antes de la cláusula "order by" si la hubiere.
232
Ingresemos el siguiente lote de comandos SQL en Navicat:
codigo serial,
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
precio decimal(5,2),
cantidad smallint,
primary key(codigo)
);
values('El aleph','Borges','Planeta',35,null);
values('PHP de la A a la Z',null,null,110,0);
values('Uno','Richard Bach','Planeta',25,null);
-- sólo algunos grupos, por ejemplo, los que devuelvan un valor mayor a 2,
group by editorial
having count(*)>2;
group by editorial
having avg(precio)>25;
group by editorial
having editorial<>'Planeta';
234
-- Necesitamos el promedio de los precios agrupados por editorial,
group by editorial
from libros
group by editorial
max(precio)>30
order by editorial;
235
34 - Registros duplicados (distinct)
Con la cláusula "distinct" se especifica que los registros con ciertos datos duplicados sean
obviadas en el resultado. Por ejemplo, queremos conocer todos los autores de los cuales
tenemos libros, si utilizamos esta sentencia:
group by autor;
Note que en los tres casos anteriores aparece "null" como un valor para "autor"· Si sólo
queremos la lista de autores conocidos, es decir, no queremos incluir "null" en la lista, podemos
utilizar la sentencia siguiente:
Para contar los distintos autores, sin considerar el valor "null" usamos:
from libros;
Note que si contamos los autores sin "distinct", no incluirá los valores "null" pero si los repetidos:
select count(autor)
from libros;
Podemos combinarla con "where". Por ejemplo, queremos conocer los distintos autores de la
editorial "Planeta":
where editorial='Planeta';
También puede utilizarse con "group by" para contar los diferentes autores por editorial:
from libros
236
group by editorial;
La cláusula "distinct" afecta a todos los campos presentados. Para mostrar los títulos y editoriales
de los libros sin repetir títulos ni editoriales, usamos:
from libros
order by titulo;
Note que los registros no están duplicados, aparecen títulos iguales pero con editorial diferente,
cada registro es diferente.
codigo serial,
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
primary key(codigo)
);
values('El aleph','Borges','Planeta');
values('Antologia poetica','Borges','Planeta');
237
values('Aprenda PHP','Mario Molina','Emece');
values('Aprenda PHP','Lopez','Emece');
values('Cervantes y el quijote',null,'Paidos');
values('PHP de la A a la Z',null,null);
values('Uno','Richard Bach','Planeta');
-- "null" en la lista:
238
-- Contamos los distintos autores:
from libros;
where editorial='Planeta';
from libros
group by editorial;
from libros
order by titulo;
239
240
35 - Clave primaria compuesta
Las claves primarias pueden ser simples, formadas por un solo campo o compuestas, más de un
campo.
Recordemos que una clave primaria identifica 1 solo registro en una tabla.
Para un valor del campo clave existe solamente 1 registro. Los valores no se repiten ni pueden ser
nulos.
Existe un parking que almacena cada día los datos de los vehículos que ingresan en la tabla
llamada "vehiculos" con los siguientes campos:
- horallegada time,
- horasalida time,
Necesitamos definir una clave primaria para una tabla con los datos descriptos arriba. No
podemos usar solamente la patente porque un mismo auto puede ingresar más de una vez en el
día en el parking; tampoco podemos usar la hora de entrada porque varios autos pueden ingresar
a una misma hora.
Tampoco sirven los otros campos.
Como ningún campo, por si sólo cumple con la condición para ser clave, es decir, debe identificar
un solo registro, el valor no puede repetirse, debemos usar 2 campos.
Definimos una clave compuesta cuando ningún campo por si solo cumple con la condición para
ser clave.
En este ejemplo, un auto puede ingresar varias veces en un día al parking, pero siempre será a
distinta hora.
Usamos 2 campos como clave, la patente junto con la hora de llegada, así identificamos
unívocamente cada registro.
Para establecer más de un campo como clave primaria usamos la siguiente sintaxis:
horallegada time,
horasalida time,
241
primary key(patente,horallegada)
);
Nombramos los campos que formarán parte de la clave separados por comas.
Al ingresar los registros, PostgreSQL controla que los valores para los campos establecidos como
clave primaria no estén repetidos en la tabla; si estuviesen repetidos, muestra un mensaje y la
inserción no se realiza. Lo mismo sucede si realizamos una actualización.
Entonces, si un solo campo no identifica unívocamente un registro podemos definir una clave
primaria compuesta, es decir formada por más de un campo.
horallegada time,
horasalida time,
primary key(patente,horallegada)
);
242
-- Si ingresamos un registro repitiendo el valor de uno de los
243
36 - Restricción check
La restricción "check" especifica los valores que acepta un campo, evitando que se ingresen
valores inapropiados.
check CONDICION;
Trabajamos con la tabla "libros" de una librería que tiene los siguientes campos: codigo, titulo,
autor, editorial, preciomin (que indica el precio para los minoristas) y preciomay (que indica el
precio para los mayoristas).
Este tipo de restricción verifica los datos cada vez que se ejecuta una sentencia "insert" o
"update", es decir, actúa en inserciones y actualizaciones.
La condición puede hacer referencia a otros campos de la misma tabla. Por ejemplo, podemos
controlar que el precio mayorista no sea mayor al precio minorista:
check (preciomay<=preciomin);
Por convención, cuando demos el nombre a las restricciones "check" seguiremos la misma
estructura: comenzamos con "CK", seguido del nombre de la tabla, del campo y alguna palabra
con la cual podamos identificar fácilmente de qué se trata la restricción, por si tenemos varias
restricciones "check" para el mismo campo.
Un campo puede tener varias restricciones "check" y una restricción "check" puede incluir varios
campos.
244
Si un campo permite valores nulos, "null" es un valor aceptado aunque no esté incluido en la
condición de restricción.
codigo serial,
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
preciomin decimal(5,2),
preciomay decimal(5,2),
primary key(codigo)
);
-- Agregamos una restricción "check" para asegurar que los valores de los
245
values ('Python para todos','Rodriguez','Siglo XXI', -10, 40);
246
37 - Restricción primary key
Ahora veremos las restricciones que se aplican a las tablas, que aseguran valores únicos para
cada registro.
Anteriormente, para establecer una clave primaria para una tabla empleábamos la siguiente
sintaxis al crear la tabla, por ejemplo:
titulo varchar(30),
autor varchar(30),
editorial varchar(20),
primary key(codigo)
);
Cada vez que establecíamos la clave primaria para la tabla, PostgreSQL creaba automáticamente
una restricción "primary key" para dicha tabla. Dicha restricción, a la cual no le dábamos un
nombre, recibía un nombre dado por PostgreSQL, por ejemplo 'libros_pkey'
Podemos agregar una restricción "primary key" a una tabla existente con la sintaxis básica
siguiente:
En el siguiente ejemplo definimos una restricción "primary key" para nuestra tabla "libros" para
asegurarnos que cada libro tendrá un código diferente y único:
primary key(codigo);
Con esta restricción, si intentamos ingresar un registro con un valor para el campo "codigo" que
ya existe o el valor "null", aparece un mensaje de error, porque no se permiten valores
duplicados ni nulos. Igualmente, si actualizamos.
247
Por convención, cuando demos el nombre a las restricciones "primary key" seguiremos el
formato "PK_NOMBRETABLA_NOMBRECAMPO".
Sabemos que cuando agregamos una restricción a una tabla que contiene información,
PostgreSQL controla los datos existentes para confirmar que cumplen las exigencias de la
restricción, si no los cumple, la restricción no se aplica y aparece un mensaje de error. Por
ejemplo, si intentamos definir la restricción "primary key" para "libros" y hay registros con
códigos repetidos o con un valor "null", la restricción no se establece.
PostgreSQL permite definir solamente una restricción "primary key" por tabla, que asegura la
unicidad de cada registro de una tabla.
Si ejecutamos:
select *
from information_schema.table_constraints
podemos ver las restricciones "primary key" (y todos los tipos de restricciones) de dicha tabla.
Un campo con una restricción "primary key" puede tener una restricción "check".
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
);
select *
from information_schema.table_constraints
248
-- Vamos a eliminar la tabla y la crearemos nuevamente, sin establecer la clave primaria:
titulo varchar(40),
autor varchar(30),
editorial varchar(15)
);
-- Definimos una restricción "primary key" para nuestra tabla "libros" para asegurarnos
primary key(codigo);
select *
from information_schema.table_constraints
249
38 - Restricción unique
Anteriormente aprendimos la restricción "primary key", otra restricción para las tablas es
"unique".
La restricción "unique" impide la duplicación de claves alternas (no primarias), es decir, especifica
que dos registros no puedan tener el mismo valor en un campo. Se permiten valores nulos. Se
pueden aplicar varias restricciones de este tipo a una misma tabla, y pueden aplicarse a uno o
varios campos que no sean clave primaria.
Se emplea cuando ya se estableció una clave primaria (como un número de legajo) pero se
necesita asegurar que otros datos también sean únicos y no se repitan (como número de
documento).
unique (CAMPO);
Ejemplo:
unique (documento);
Por convención, cuando demos el nombre a las restricciones "unique" seguiremos la misma
estructura: "UQ_NOMBRETABLA_NOMBRECAMPO". Quizá parezca innecesario colocar el nombre
de la tabla, pero cuando empleemos varias tablas verá que es útil identificar las restricciones por
tipo, tabla y campo.
Recuerde que cuando agregamos una restricción a una tabla que contiene información,
PostgreSQL controla los datos existentes para confirmar que cumplen la condición de la
restricción, si no los cumple, la restricción no se aplica y aparece un mensaje de error. En el caso
del ejemplo anterior, si la tabla contiene números de documento duplicados, la restricción no
podrá establecerse; si podrá establecerse si tiene valores nulos.
apellido varchar(20),
nombre varchar(20),
documento char(8)
);
primary key(legajo);
unique (documento);
select *
from information_schema.table_constraints
252
39 - Eliminar restricciones (alter table - drop
constraint)
Cuando eliminamos una tabla, todas las restricciones que fueron establecidas en ella, se eliminan
también.
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
precio decimal(6,2)
);
primary key(codigo);
check (precio>=0);
select *
from information_schema.table_constraints
-- Vemos si se eliminó:
select *
from information_schema.table_constraints
254
40 - Indice de una tabla.
El indice de una tabla desempeña la misma función que el índice de un libro: permite encontrar
datos rápidamente; en el caso de las tablas, localiza registros.
El índice es un tipo de archivo con 2 entradas: un dato (un valor de algún campo de la tabla) y un
puntero.
Un índice posibilita el acceso directo y rápido haciendo más eficiente las búsquedas. Sin índice, se
debe recorrer secuencialmente toda la tabla para encontrar un registro.
La desventaja es que consume espacio en el disco y las inserciones y borrados de registros son
más lentas.
La indexación es una técnica que optimiza el acceso a los datos, mejora el rendimiento
acelerando las consultas y otras operaciones. Es útil cuando la tabla contiene miles de registros.
Es importante identificar el o los campos por los que sería útil crear un indice, aquellos campos
por los cuales se realizan operaciones de búsqueda con frecuencia.
1) "primary key": es el que definimos como clave primaria. Los valores indexados deben ser
únicos y además no pueden ser nulos. PostgreSQL le da el nombre "PRIMARY". Una tabla
solamente puede tener una clave primaria.
2) "index": crea un indice común, los valores no necesariamente son únicos y aceptan valores
"null". Podemos darle un nombre, si no se lo damos, se coloca uno por defecto. "key" es
sinónimo de "index". Puede haber varios por tabla.
3) "unique": crea un indice para los cuales los valores deben ser únicos y diferentes, aparece un
mensaje de error si intentamos agregar un registro con un valor ya existente. Permite valores
nulos y pueden definirse varios por tabla. Podemos darle un nombre, si no se lo damos, se coloca
uno por defecto.
Todos los índices pueden ser multicolumna, es decir, pueden estar formados por más de 1
campo.
255
En las siguientes lecciones aprenderemos sobre cada uno de ellos.
Una tabla puede ser indexada por campos de tipo numérico o de tipo caracter. También se puede
indexar por un campo que contenga valores NULL, excepto los PRIMARY.
256
41 - Típos de índices (create y drop)
El índice llamado primary se crea automáticamente cuando establecemos un campo como clave
primaria.
Los valores indexados deben ser únicos y además no pueden ser nulos. Una tabla solamente
puede tener una clave primaria. Puede ser multicolumna, es decir, pueden estar formados por
más de un campo.
Vamos a otro tipo de índice común. Un índice común se crea con "create index", los valores no
necesariamente son únicos y aceptan valores "null". Puede haber varios por tabla.
titulo varchar(40),
autor varchar(30),
editorial varchar(15),
precio decimal(6,2)
);
Un campo por el cual realizamos consultas frecuentemente es "editorial", indexar la tabla por ese
campo sería útil.
Creamos un índice:
Debemos definir un nombre para el índice (en este caso utilizamos como nomenclatura el carater
I, luego el nombre de la tabla y finalmente el o los nombres del campo por el cual creamos el
índice. Luego de la palabra clave on indicamos el nombre de la tabla y entre paréntesis el nombre
del campo o los campos por el cual se indexa.
Veamos otro tipo de índice llamado "único". Un índice único se crea con "create unique index",
los valores deben ser únicos y diferentes, aparece un mensaje de error si intentamos agregar un
registro con un valor ya existente. Permite valores nulos y pueden definirse varios por tabla.
257
Para eliminar un índice usamos "drop index". Ejemplo:
Podemos eliminar los índices creados, pero no el creado automáticamente con la clave primaria.
codigo serial,
autor varchar(30),
editorial varchar(15),
primary key(codigo)
);
258
259
42 - Cláusulas limit y offset del comando select
Las cláusulas "limit" y "offset" se usan para restringir los registros que se retornan en una
consulta "select".
La cláusula limit recibe un argumento numérico positivo que indica el número máximo de
registros a retornar; la cláusula offset indica el número del primer registro a retornar. El número
de registro inicial es 0 (no 1).
Ejemplo:
Si tipeamos:
Si se coloca solo la cláusula limit retorna tantos registros como el valor indicado, comenzando
desde 0. Ejemplo:
Es conveniente utilizar la cláusula order by cuando utilizamos limit y offset, por ejemplo:
codigo serial,
autor varchar(30),
editorial varchar(15),
precio decimal(5,2),
values('El aleph','Borges','Planeta',15);
values('Antologia poetica','Borges','Planeta',40);
values('Cervantes y el quijote','Borges','Paidos',36.40);
262
43 - Trabajar con varias tablas
Hasta el momento hemos trabajado con una sola tabla, pero generalmente, se trabaja con más
de una.
Para evitar la repetición de datos y ocupar menos espacio, se separa la información en varias
tablas. Cada tabla almacena parte de la información que necesitamos registrar.
Por ejemplo, los datos de nuestra tabla "libros" podrían separarse en 2 tablas, una llamada
"libros" y otra "editoriales" que guardará la información de las editoriales.
En nuestra tabla "libros" haremos referencia a la editorial colocando un código que la identifique.
Veamos:
codigo serial,
precio decimal(5,2),
);
codigo serial,
primary key(codigo)
);
De esta manera, evitamos almacenar tantas veces los nombres de las editoriales en la tabla
"libros" y guardamos el nombre en la tabla "editoriales"; para indicar la editorial de cada libro
agregamos un campo que hace referencia al código de la editorial en la tabla "libros" y en
"editoriales".
263
vemos que en el campo "editorial" aparece el código, pero no sabemos el nombre de la editorial.
Para obtener los datos de cada libro, incluyendo el nombre de la editorial, necesitamos consultar
ambas tablas, traer información de las dos.
Cuando obtenemos información de más de una tabla decimos que hacemos un "join"
(combinación).
Veamos un ejemplo:
join editoriales
on [Link]=[Link];
Hay tres tipos de combinaciones. En los siguientes capítulos explicamos cada una de ellas.
264
44 - Combinación interna (inner join)
Un join es una operación que relaciona dos o más tablas para obtener un resultado que incluya
datos (campos y registros) de ambas; las tablas participantes se combinan según los campos
comunes a ambas tablas.
combinaciones externas y
combinaciones cruzadas.
También es posible emplear varias combinaciones en una consulta "select", incluso puede
combinarse una tabla consigo misma.
La combinación interna emplea "join", que es la forma abreviada de "inner join". Se emplea para
obtener información de dos tablas y combinar dicha información en una salida.
select CAMPOS
from TABLA1
join TABLA2
on CONDICIONdeCOMBINACION;
Ejemplo:
join editoriales
on codigoeditorial=[Link];
- combinamos esa tabla con "join" y el nombre de la otra tabla ("editoriales"); se especifica qué
tablas se van a combinar y cómo;
- cuando se combina información de varias tablas, es necesario especificar qué registro de una
tabla se combinará con qué registro de la otra tabla, con "on". Se debe especificar la condición
para enlazarlas, es decir, el campo por el cual se combinarán, que tienen en común.
"on" hace coincidir registros de ambas tablas basándose en el valor de tal campo, en el ejemplo,
265
el campo "codigoeditorial" de "libros" y el campo "codigo" de "editoriales" son los que enlazarán
ambas tablas. Se emplean campos comunes, que deben tener tipos de datos iguales o similares.
La condición de combinación, es decir, el o los campos por los que se van a combinar (parte
"on"), se especifica según las claves primarias y externas.
Note que en la consulta, al nombrar el campo usamos el nombre de la tabla también. Cuando las
tablas referenciadas tienen campos con igual nombre, esto es necesario para evitar confusiones y
ambiguedades al momento de referenciar un campo. En el ejemplo, si no especificamos
"[Link]" y solamente tipeamos "codigo", PosgreSQL no sabrá si nos referimos al
campo "codigo" de "libros" o de "editoriales" y mostrará un mensaje de error indicando que
"codigo" es ambiguo.
Entonces, si las tablas que combinamos tienen nombres de campos iguales, DEBE especificarse a
qué tabla pertenece anteponiendo el nombre de la tabla al nombre del campo, separado por un
punto (.).
Si una de las tablas tiene clave primaria compuesta, al combinarla con la otra, en la cláusula "on"
se debe hacer referencia a la clave completa, es decir, la condición referenciará a todos los
campos clave que identifican al registro.
Se puede incluir en la consulta join la cláusula "where" para restringir los registros que retorna el
resultado; también "order by", etc..
Se emplea este tipo de combinación para encontrar registros de la primera tabla que se
correspondan con los registros de la otra, es decir, que cumplan la condición del "on". Si un valor
de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.
select [Link],titulo,autor,nombre
from libros as l
join editoriales as e
on [Link]=[Link];
En algunos casos (como en este ejemplo) el uso de alias es para fines de simplificación y hace más
legible la consulta si es larga y compleja, pero en algunas consultas es absolutamente necesario.
codigo serial,
titulo varchar(40),
266
autor varchar(30) default 'Desconocido',
precio decimal(5,2),
primary key(codigo)
);
codigo serial,
nombre varchar(20),
);
values('El aleph','Borges',2,20);
values('Java en 10 minutos',default,3,45);
from libros
join editoriales
on codigoeditorial=[Link];
select [Link],titulo,autor,nombre,precio
from libros as l
join editoriales as e
on codigoeditorial=[Link];
select [Link],titulo,autor,nombre,precio
from libros as l
join editoriales as e
on codigoeditorial=[Link]
-- Obtenemos título, autor y nombre de la editorial, esta vez ordenados por título:
select titulo,autor,nombre
268
from libros as l
join editoriales as e
on codigoeditorial=[Link]
order by titulo;
269
45 - Combinación externa izquierda (left join)
Vimos que una combinación interna (join) encuentra registros de la primera tabla que se
correspondan con los registros de la segunda, es decir, que cumplan la condición del "on" y si un
valor de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.
Las combinaciones externas combinan registros de dos tablas que cumplen la condición, más los
registros de la segunda tabla que no la cumplen; es decir, muestran todos los registros de las
tablas relacionadas, aún cuando no haya valores coincidentes entre ellas.
Este tipo de combinación se emplea cuando se necesita una lista completa de los datos de una de
las tablas y la información que cumple con la condición. Las combinaciones externas se realizan
solamente entre 2 tablas.
Hay tres tipos de combinaciones externas: "left outer join", "right outer join" y "full outer join";
se pueden abreviar con "left join", "right join" y "full join" respectivamente.
Se emplea una combinación externa izquierda para mostrar todos los registros de la tabla de la
izquierda. Si no encuentra coincidencia con la tabla de la derecha, el registro muestra los campos
de la segunda tabla seteados a "null".
select titulo,nombre
from editoriales as e
on codigoeditorial = [Link];
El resultado mostrará el título y nombre de la editorial; las editoriales de las cuales no hay libros,
es decir, cuyo código de editorial no está presente en "libros" aparece en el resultado, pero con el
valor "null" en el campo "titulo".
Es importante la posición en que se colocan las tablas en un "left join", la tabla de la izquierda es
la que se usa para localizar registros en la tabla de la derecha.
Entonces, un "left join" se usa para hacer coincidir registros en una tabla (izquierda) con otra
tabla (derecha); si un valor de la tabla de la izquierda no encuentra coincidencia en la tabla de la
derecha, se genera una fila extra (una por cada valor no encontrado) con todos los campos
correspondientes a la tabla derecha seteados a "null". La sintaxis básica es la siguiente:
select CAMPOS
270
from TABLAIZQUIERDA
on CONDICION;
select titulo,nombre
from libros as l
on codigoeditorial = [Link];
El resultado mostrará el título del libro y el nombre de la editorial; los títulos cuyo código de
editorial no está presente en "editoriales" aparecen en el resultado, pero con el valor "null" en el
campo "nombre".
Un "left join" puede tener clausula "where" que restringa el resultado de la consulta
considerando solamente los registros que encuentran coincidencia en la tabla de la derecha, es
decir, cuyo valor de código está presente en "libros":
select titulo,nombre
from editoriales as e
on [Link]=codigoeditorial
También podemos mostrar las editoriales que NO están presentes en "libros", es decir, que NO
encuentran coincidencia en la tabla de la derecha:
select titulo,nombre
from editoriales as e
on [Link]=codigoeditorial
271
create table libros(
codigo serial,
titulo varchar(40),
precio decimal(5,2),
primary key(codigo)
);
codigo serial,
nombre varchar(20),
);
values('El aleph','Borges',1,20);
values('Java en 10 minutos',default,4,45);
from editoriales as e
on codigoeditorial = [Link];
select titulo,nombre
from libros as l
on codigoeditorial = [Link];
select titulo,nombre
from editoriales as e
on [Link]=codigoeditorial
select titulo,nombre
273
from editoriales as e
on [Link]=codigoeditorial
274
46 - Combinación externa derecha (right join)
Vimos que una combinación externa izquierda (left join) encuentra registros de la tabla izquierda
que se correspondan con los registros de la tabla derecha y si un valor de la tabla izquierda no se
encuentra en la tabla derecha, el registro muestra los campos correspondientes a la tabla de la
derecha seteados a "null".
Una combinación externa derecha ("right outer join" o "right join") opera del mismo modo sólo
que la tabla derecha es la que localiza los registros en la tabla izquierda.
select titulo,nombre
from libros as l
on codigoeditorial = [Link];
El resultado mostrará el título y nombre de la editorial; las editoriales de las cuales no hay libros,
es decir, cuyo código de editorial no está presente en "libros" aparece en el resultado, pero con el
valor "null" en el campo "titulo".
Es FUNDAMENTAL tener en cuenta la posición en que se colocan las tablas en los "outer join". En
un "left join" la primera tabla (izquierda) es la que busca coincidencias en la segunda tabla
(derecha); en el "right join" la segunda tabla (derecha) es la que busca coincidencias en la primera
tabla (izquierda).
En la siguiente consulta empleamos un "left join" para conseguir el mismo resultado que el "right
join" anterior":
select titulo,nombre
from editoriales as e
on codigoeditorial = [Link];
Note que la tabla que busca coincidencias ("editoriales") está en primer lugar porque es un "left
join"; en el "right join" precedente, estaba en segundo lugar.
Un "right join" hace coincidir registros en una tabla (derecha) con otra tabla (izquierda); si un
valor de la tabla de la derecha no encuentra coincidencia en la tabla izquierda, se genera una fila
extra (una por cada valor no encontrado) con todos los campos correspondientes a la tabla
izquierda seteados a "null". La sintaxis básica es la siguiente:
275
select CAMPOS
from TABLAIZQUIERDA
on CONDICION;
Un "right join" también puede tener cláusula "where" que restringa el resultado de la consulta
considerando solamente los registros que encuentran coincidencia en la tabla izquierda:
select titulo,nombre
from libros as l
on [Link]=codigoeditorial
Mostramos las editoriales que NO están presentes en "libros", es decir, que NO encuentran
coincidencia en la tabla de la derecha empleando un "right join":
select titulo,nombre
from libros as l
rightjoin editoriales as e
on [Link]=codigoeditorial
codigo serial,
titulo varchar(40),
precio decimal(5,2),
primary key(codigo)
276
);
codigo serial,
nombre varchar(20),
);
values('El aleph','Borges',1,20);
values('Java en 10 minutos',default,4,45);
-- un "right join":
select titulo,nombre
from libros as l
on codigoeditorial = [Link];
-- Las editoriales de las cuales no hay libros, es decir, cuyo código de editorial
-- en la tabla izquierda:
select titulo,nombre
from libros as l
on [Link]=codigoeditorial
select titulo,nombre
from libros as l
on [Link]=codigoeditorial
278
47 - Combinación externa completa (full join)
Vimos que un "left join" encuentra registros de la tabla izquierda que se correspondan con los
registros de la tabla derecha y si un valor de la tabla izquierda no se encuentra en la tabla
derecha, el registro muestra los campos correspondientes a la tabla de la derecha seteados a
"null". Aprendimos también que un "right join" opera del mismo modo sólo que la tabla derecha
es la que localiza los registros en la tabla izquierda.
Una combinación externa completa ("full outer join" o "full join") retorna todos los registros de
ambas tablas. Si un registro de una tabla izquierda no encuentra coincidencia en la tabla derecha,
las columnas correspondientes a campos de la tabla derecha aparecen seteadas a "null", y si la
tabla de la derecha no encuentra correspondencia en la tabla izquierda, los campos de esta
última aparecen conteniendo "null".
Veamos un ejemplo:
select titulo,nombre
from editoriales as e
on codigoeditorial = [Link];
La salida del "full join" precedente muestra todos los registros de ambas tablas, incluyendo los
libros cuyo código de editorial no existe en la tabla "editoriales" y las editoriales de las cuales no
hay correspondencia en "libros".
codigo serial,
titulo varchar(40),
precio decimal(5,2),
primary key(codigo)
279
);
codigo serial,
nombre varchar(20),
);
values('El aleph','Borges',1,20);
values('Java en 10 minutos',default,4,45);
select titulo,nombre
from editoriales as e
on codigoeditorial = [Link];
Vimos que hay tres tipos de combinaciones: 1) combinaciones internas (join), 2) combinaciones
externas (left, right y full join) y 3) combinaciones cruzadas.
Las combinaciones cruzadas (cross join) muestran todas las combinaciones de todos los registros
de las tablas combinadas. Para este tipo de join no se incluye una condición de enlace. Se genera
el producto cartesiano en el que el número de filas del resultado es igual al número de registros
de la primera tabla multiplicado por el número de registros de la segunda tabla, es decir, si hay 5
registros en una tabla y 6 en la otra, retorna 30 filas.
select CAMPOS
from TABLA1
Veamos un ejemplo. Un pequeño restaurante almacena los nombres y precios de sus comidas en
una tabla llamada "comidas" y en una tabla denominada "postres" los mismos datos de sus
postres.
Si necesitamos conocer todas las combinaciones posibles para un menú, cada comida con cada
postre, empleamos un "cross join":
from comidas as c
La salida muestra cada plato combinado con cada uno de los postres.
Como cualquier tipo de "join", puede emplearse una cláusula "where" que condicione la salida.
codigo serial,
nombre varchar(30),
precio decimal(4,2),
282
primary key(codigo)
);
codigo serial,
nombre varchar(30),
precio decimal(4,2),
primary key(codigo)
);
[Link] as postre,
[Link]+[Link] as total
from comidas as c
283
284
49 - Autocombinación
Un pequeño restaurante tiene almacenadas sus comidas en una tabla llamada "comidas" que
consta de los siguientes campos:
- nombre varchar(20),
- rubro char(6)-- que indica con 'plato' si es un plato principal y 'postre' si es postre.
Podemos obtener la combinación de platos empleando un "cross join" con una sola tabla:
[Link] as postre,
[Link]+[Link] as total
from comidas as c1
En la consulta anterior aparecen filas duplicadas, para evitarlo debemos emplear un "where":
[Link] as postre,
[Link]+[Link] as total
from comidas as c1
[Link]='postre';
En la consulta anterior se empleó un "where" que especifica que se combine "plato" con
"postre".
En una autocombinación se combina una tabla con una copia de si misma. Para ello debemos
utilizar 2 alias para la tabla. Para evitar que aparezcan filas duplicadas, debemos emplear un
"where".
[Link]+[Link] as total
from comidas as c1
join comidas as c2
on [Link]<>[Link]
[Link]='postre';
codigo serial,
nombre varchar(30),
precio decimal(4,2),
primary key(codigo)
);
[Link] as postre,
286
[Link]+[Link] as total
from comidas as c1
-- Note que aparecen filas duplicadas, por ejemplo, "ravioles" se combina con
[Link] as postre,
[Link]+[Link] as total
from comidas as c1
[Link]='postre';
[Link] as postre,
[Link]+[Link] as total
from comidas as c1
join comidas as c2
on [Link]<>[Link]
[Link]='postre';
287
288
50 - Combinaciones y funciones de
agrupamiento
Podemos usar "group by" y las funciones de agrupamiento con combinaciones de tablas.
Para ver la cantidad de libros de cada editorial consultando la tabla "libros" y "editoriales",
tipeamos:
count(*) as cantidad
from editoriales as e
join libros as l
on codigoeditorial=[Link]
group by [Link];
Note que las editoriales que no tienen libros no aparecen en la salida porque empleamos un
"join".
Empleamos otra función de agrupamiento con "left join". Para conocer el mayor precio de los
libros de cada editorial usamos la función "max()", hacemos un "left join" y agrupamos por
nombre de la editorial:
max(precio) as mayorprecio
from editoriales as e
on codigoeditorial=[Link]
group by nombre;
En la sentencia anterior, mostrará, para la editorial de la cual no haya libros, el valor "null" en la
columna calculada.
289
codigo serial,
titulo varchar(40),
autor varchar(30),
precio decimal(5,2),
primary key(codigo)
);
codigo serial,
nombre varchar(20),
);
values('El aleph','Borges',1,20);
values('Uno','Richard Bach',3,15);
values('Java en 10 minutos',default,4,45);
count(*) as cantidad
from editoriales as e
join libros as l
on codigoeditorial=[Link]
group by [Link];
max(precio) as mayorprecio
from editoriales as e
on codigoeditorial=[Link]
group by nombre;
291
51 - Combinación de más de dos tablas
Podemos hacer un "join" con más de dos tablas.
Cada join combina 2 tablas. Se pueden emplear varios join para enlazar varias tablas. Cada
resultado de un join es una tabla que puede combinarse con otro join.
La librería almacena los datos de sus libros en tres tablas: libros, editoriales y autores.
En la tabla "libros" un campo "codigoautor" hace referencia al autor y un campo "codigoeditorial"
referencia la editorial.
Para recuperar todos los datos de los libros empleamos la siguiente consulta:
select titulo,[Link],[Link]
from autores as a
join libros as l
on codigoautor=[Link]
join editoriales as e
on codigoeditorial=[Link];
Analicemos la consulta anterior. Indicamos el nombre de la tabla luego del "from" ("autores"),
combinamos esa tabla con la tabla "libros" especificando con "on" el campo por el cual se
combinarán; luego debemos hacer coincidir los valores para el enlace con la tabla "editoriales"
enlazándolas por los campos correspondientes. Utilizamos alias para una sentencia más sencilla y
comprensible.
Note que especificamos a qué tabla pertenecen los campos cuyo nombre se repiten en las tablas,
esto es necesario para evitar confusiones y ambiguedades al momento de referenciar un campo.
Note que no aparecen los libros cuyo código de autor no se encuentra en "autores" y cuya
editorial no existe en "editoriales", esto es porque realizamos una combinación interna.
select titulo,[Link],[Link]
from autores as a
on codigoautor=[Link]
En la consulta anterior solicitamos el título, autor y editorial de todos los libros que encuentren o
no coincidencia con "autores" ("right join") y a ese resultado lo combinamos con "editoriales",
encuentren o no coincidencia.
292
Es posible realizar varias combinaciones para obtener información de varias tablas. Las tablas
deben tener claves externas relacionadas con las tablas a combinar.
En consultas en las cuales empleamos varios "join" es importante tener en cuenta el orden de las
tablas y los tipos de "join"; recuerde que la tabla resultado del primer join es la que se combina
con el segundo join, no la segunda tabla nombrada. En el ejemplo anterior, el "left join" no se
realiza entre las tablas "libros" y "editoriales" sino entre el resultado del "right join" y la tabla
"editoriales".
codigo serial,
titulo varchar(40),
precio decimal(5,2),
primary key(codigo)
);
codigo serial,
nombre varchar(20),
);
codigo serial,
nombre varchar(20),
values('El aleph',2,2,20);
values('Martin Fierro',3,1,30);
values('Aprenda PHP',4,3,50);
values('Uno',1,1,15);
values('Java en 10 minutos',0,3,45);
values('Java de la A a la Z',4,0,50);
-- Recuperamos todos los datos de los libros consultando las tres tablas:
select titulo,[Link],[Link],precio
294
from autores as a
join libros as l
on codigoautor=[Link]
join editoriales as e
on codigoeditorial=[Link];
select titulo,[Link],[Link],precio
from autores as a
on codigoautor=[Link]
on codigoeditorial=[Link];
295
52 - Clave foránea
Un campo que no es clave primaria en una tabla y sirve para enlazar sus valores con otra tabla en
la cual es clave primaria se denomina clave foránea, externa o ajena.
En el ejemplo de la librería en que utilizamos las tablas "libros" y "editoriales" con estos campos:
el campo "codigoeditorial" de "libros" es una clave foránea, se emplea para enlazar la tabla
"libros" con "editoriales" y es clave primaria en "editoriales" con el nombre "codigo".
Las claves foráneas y las claves primarias deben ser del mismo tipo para poder enlazarse. Si
modificamos una, debemos modificar la otra para que los valores se correspondan.
Cuando alteramos una tabla, debemos tener cuidado con las claves foráneas. Si modificamos el
tipo, longitud o atributos de una clave foránea, ésta puede quedar inhabilitada para hacer los
enlaces.
Entonces, una clave foránea es un campo (o varios) empleados para enlazar datos de 2 tablas,
para establecer un "join" con otra tabla en la cual es clave primaria.
296
53 - Restricciones (foreign key)
Hemos visto que una de las alternativas que PostgreSQL ofrece para asegurar la integridad de
datos es el uso de restricciones (constraints). Aprendimos que las restricciones se establecen en
tablas y campos asegurando que los datos sean válidos y que las relaciones entre las tablas se
mantengan.
Con la restricción "foreign key" se define un campo (o varios) cuyos valores coinciden con la clave
primaria de la misma tabla o de otra, es decir, se define una referencia a un campo con una
restricción "primary key" o "unique" de la misma tabla o de otra.
La integridad referencial asegura que se mantengan las referencias entre las claves primarias y las
externas. Por ejemplo, controla que si se agrega un código de editorial en la tabla "libros", tal
código exista en la tabla "editoriales".
También controla que no pueda eliminarse un registro de una tabla ni modificar la clave primaria
si una clave externa hace referencia al registro. Por ejemplo, que no se pueda eliminar o
modificar un código de "editoriales" si existen libros con dicho código.
La siguiente es la sintaxis parcial general para agregar una restricción "foreign key":
Analicémosla:
- luego de "foreign key", entre paréntesis se coloca el campo de la tabla a la que le aplicamos la
restricción que será establecida como clave foránea,
Para agregar una restricción "foreign key" al campo "codigoeditorial" de "libros", tipeamos:
En el ejemplo implementamos una restricción "foreign key" para asegurarnos que el código de la
editorial de la tabla "libros" ("codigoeditorial") esté asociada con un código válido en la tabla
"editoriales" ("codigo").
Cuando agregamos cualquier restricción a una tabla que contiene información, PostgreSQL
controla los datos existentes para confirmar que cumplen con la restricción, si no los cumple, la
restricción no se aplica y aparece un mensaje de error. Por ejemplo, si intentamos agregar una
restricción "foreign key" a la tabla "libros" y existe un libro con un valor de código para editorial
que no existe en la tabla "editoriales", la restricción no se agrega.
Actúa en inserciones. Si intentamos ingresar un registro (un libro) con un valor de clave foránea
(codigoeditorial) que no existe en la tabla referenciada (editoriales), PostgreSQL muestra un
mensaje de error. Si al ingresar un registro (un libro), no colocamos el valor para el campo clave
foránea (codigoeditorial), almacenará "null", porque esta restricción permite valores nulos (a
menos que se haya especificado lo contrario al definir el campo).
La cantidad y tipo de datos de los campos especificados luego de "foreign key" DEBEN coincidir
con la cantidad y tipo de datos de los campos de la cláusula "references".
No se puede eliminar una tabla referenciada en una restricción "foreign key", aparece un
mensaje de error.
Una restriccion "foreign key" no puede modificarse, debe eliminarse y volverse a crear.
codigo serial,
titulo varchar(40),
autor varchar(30),
codigoeditorial smallint,
298
primary key(codigo)
);
codigo serial,
nombre varchar(20),
);
references editoriales(codigo);
La restricción "foreign key", que define una referencia a un campo con una restricción "primary
key" o "unique" se puede definir entre distintas tablas (como hemos aprendido) o dentro de la
misma tabla.
Una mutual almacena los datos de sus afiliados en una tabla llamada "afiliados". Algunos afiliados
inscriben a sus familiares. La tabla contiene un campo que hace referencia al afiliado que lo
incorporó a la mutual, del cual dependen.
numero serial,
nombre varchar(30),
afiliadotitular int,
unique (numero)
);
En caso que un afiliado no haya sido incorporado a la mutual por otro afiliado, el campo
"afiliadotitular" almacenará "null".
Establecemos una restricción "foreign key" para asegurarnos que el número de afiliado que se
ingrese en el campo "afiliadotitular" exista en la tabla "afiliados":
Luego de aplicar esta restricción, cada vez que se ingrese un valor en el campo "afiliadotitular",
PostgreSQL controlará que dicho número exista en la tabla, si no existe, mostrará un mensaje de
error.
301
Ingresemos el siguiente lote de comandos SQL en Navicat:
numero serial,
nombre varchar(30),
afiliadotitular int,
unique (numero)
);
-- Establecemos una restricción "foreign key" para asegurarnos que el número de afiliado
-- en el campo "afiliadotitular":
303
55 - Restricciones foreign key al crear la tabla
Hasta el momento hemos agregado restricciones a tablas existentes con "alter table" (manera
aconsejada), también pueden establecerse al momento de crear una tabla (en la instrucción
"create table").
codigo serial,
nombre varchar(20),
);
codigo serial,
titulo varchar(40),
autor varchar(30),
primary key(codigo)
);
En el ejemplo anterior creamos una restricción "foreign key" para establecer el campo
"codigoeditorial" como clave externa que haga referencia al campo "codigo" de "editoriales.
Si definimos una restricción "foreign key" al crear una tabla, la tabla referenciada debe existir.
304
create table editoriales(
codigo serial,
nombre varchar(20),
);
codigo serial,
titulo varchar(40),
autor varchar(30),
primary key(codigo)
);
305
306
56 - Restricciones foreign key (acciones)
Si intentamos eliminar un registro de la tabla referenciada por una restricción "foreign key" cuyo
valor de clave primaria existe referenciada en la tabla que tiene dicha restricción, la acción no se
ejecuta y aparece un mensaje de error. Esto sucede porque, por defecto, para eliminaciones, la
opción de la restricción "foreign key" es "no action". Lo mismo sucede si intentamos actualizar un
valor de clave primaria de una tabla referenciada por una "foreign key" existente en la tabla
principal.
La restricción "foreign key" tiene las cláusulas "on delete" y "on update" que son opcionales.
Estas cláusulas especifican cómo debe actuar PostgreSQL frente a eliminaciones y modificaciones
de las tablas referenciadas en la restricción.
Las opciones para estas cláusulas son las siguientes:
- "no action": indica que si intentamos eliminar o actualizar un valor de la clave primaria de la
tabla referenciada (TABLA2) que tengan referencia en la tabla principal (TABLA1), se genere un
error y la acción no se realice; es la opción predeterminada.
references TABLA2(CAMPOCLAVEPRIMARIA)
on delete OPCION
on update OPCION;
307
- se especifica "cascade" para eliminaciones ("on delete cascade") y elimina un registro de la tabla
referenciada (editoriales) cuyo valor de clave primaria (codigo) existe en la tabla principal(libros),
la eliminación de la tabla referenciada (editoriales) se realiza y se eliminan de la tabla principal
(libros) todos los registros cuyo valor coincide con el registro eliminado de la tabla referenciada
(editoriales).
Veamos un ejemplo. Definimos una restricción "foreign key" a la tabla "libros" estableciendo el
campo "codigoeditorial" como clave foránea que referencia al campo "codigo" de la tabla
"editoriales". La tabla "editoriales" tiene como clave primaria el campo "codigo". Especificamos la
acción en cascada para las actualizaciones y eliminaciones:
references editoriales(codigo)
on update cascade
on delete cascade;
codigo serial,
titulo varchar(40),
autor varchar(30),
308
codigoeditorial smallint,
primary key(codigo)
);
codigo serial,
nombre varchar(20),
);
-- Establecemos una restricción "foreign key" para evitar que se ingrese en "libros" un código
-- y eliminaciones:
references editoriales(codigo)
on update cascade
on delete cascade;
from libros as l
join editoriales as e
on codigoeditorial=[Link];
from libros as l
join editoriales as e
on codigoeditorial=[Link];
310
57 - Unión
Se usa cuando los datos que se quieren obtener pertenecen a distintas tablas y no se puede
acceder a ellos con una sola consulta.
Es necesario que las tablas referenciadas tengan tipos de datos similares, la misma cantidad de
campos y el mismo orden de campos en la lista de selección de cada consulta. No se incluyen las
filas duplicadas en el resultado, a menos que coloque la opción "all".
Puede dividir una consulta compleja en varias consultas "select" y luego emplear el operador
"union" para combinarlas.
Una academia de enseñanza almacena los datos de los alumnos en una tabla llamada "alumnos"
y los datos de los profesores en otra denominada "profesores".
La academia necesita el nombre y domicilio de profesores y alumnos para enviarles una tarjeta
de invitación.
Para obtener los datos necesarios de ambas tablas en una sola consulta necesitamos realizar una
unión:
union
El primer "select" devuelve el nombre y domicilio de todos los alumnos; el segundo, el nombre y
domicilio de todos los profesores.
Los encabezados del resultado de una unión son los que se especifican en el primer "select".
311
domicilio varchar(30),
primary key(documento)
);
domicilio varchar(30),
primary key(documento)
);
union
-- Note que existe un profesor que también está presente en la tabla "alumnos";
union
order by domicilio;
union
order by condicion;
313
58 - Subconsultas
Una subconsulta (subquery) es una sentencia "select" anidada en otra sentencia "select",
"insert", "update" o "delete" (o en otra subconsulta).
Las subconsultas se emplean cuando una consulta es muy compleja, entonces se la divide en
varios pasos lógicos y se obtiene el resultado con una única instrucción y cuando la consulta
depende de los resultados de otra consulta.
Generalmente, una subconsulta se puede reemplazar por combinaciones y estas últimas son más
eficientes.
- en lugar de una expresión, siempre que devuelvan un solo valor o una lista de valores.
- que retornen un conjunto de registros de varios campos en lugar de una tabla o para obtener el
mismo resultado que una combinación (join).
las que retornan un solo valor escalar que se utiliza con un operador de comparación o en lugar
de una expresión.
las que retornan una lista de valores, se combinan con "in", o los operadores "any", "some" y
"all".
- si el "where" de la consulta exterior incluye un campo, este debe ser compatible con el campo
en la lista de selección de la subconsulta.
- las subconsultas luego de un operador de comparación (que no es seguido por "any" o "all") no
pueden incluir cláusulas "group by" ni "having".
- una subconsulta puede estar anidada dentro del "where" o "having" de una consulta externa o
dentro de otra subconsulta.
Una subconsulta puede reemplazar una expresión. Dicha subconsulta debe devolver un valor
escalar (o una lista de valores de un campo).
Las subconsultas que retornan un solo valor escalar se utiliza con un operador de comparación o
en lugar de una expresión:
select CAMPOS
from TABLA
from TABLA;
Si queremos saber el precio de un determinado libro y la diferencia con el precio del libro más
costoso, anteriormente debíamos averiguar en una consulta el precio del libro más costoso y
luego, en otra consulta, calcular la diferencia con el valor del libro que solicitamos. Podemos
conseguirlo en una sola sentencia combinando dos consultas:
select titulo,precio,
from libros
where titulo='Uno';
En el ejemplo anterior se muestra el título, el precio de un libro y la diferencia entre el precio del
libro y el máximo valor de precio.
from libros
where precio=
Note que el campo del "where" de la consulta exterior es compatible con el valor retornado por
la expresión de la subconsulta.
where CAMPO=(SUBCONSULTA);
No olvide que las subconsultas luego de un operador de comparación (que no es seguido por
"any" o "all") no pueden incluir cláusulas "group by".
codigo serial,
titulo varchar(40),
autor varchar(30),
editorial varchar(20),
precio decimal(5,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',10.00);
316
insert into libros(titulo,autor,editorial,precio)
values('Ilusiones','Richard Bach','Planeta',15.00);
values('Uno','Richard Bach','Planeta',10.00);
select titulo,precio,
from libros
where titulo='Uno';
from libros
where precio=
where precio=
317
-- Eliminamos los libros con precio menor:
where precio=
318
60 - Subconsultas con in
Vimos que una subconsulta puede reemplazar una expresión. Dicha subconsulta debe devolver
un valor escalar o una lista de valores de un campo; las subconsultas que retornan una lista de
valores reemplazan a una expresión en una cláusula "where" que contiene la palabra clave "in".
El resultado de una subconsulta con "in" (o "not in") es una lista. Luego que la subconsulta
retorna resultados, la consulta exterior los usa.
Este ejemplo muestra los nombres de las editoriales que han publicado libros de un determinado
autor:
select nombre
from editoriales
where codigo in
(select codigoeditorial
from libros
La subconsulta (consulta interna) retorna una lista de valores de un solo campo (codigo) que la
consulta exterior luego emplea al recuperar los datos.
from editoriales as e
join libros
on codigoeditorial=[Link]
Una combinación (join) siempre puede ser expresada como una subconsulta; pero una
subconsulta no siempre puede reemplazarse por una combinación que retorne el mismo
resultado. Si es posible, es aconsejable emplear combinaciones en lugar de subconsultas, son más
eficientes.
Se recomienda probar las subconsultas antes de incluirlas en una consulta exterior, así puede
verificar que retorna lo necesario, porque a veces resulta difícil verlo en consultas anidadas.
319
También podemos buscar valores No coincidentes con una lista de valores que retorna una
subconsulta; por ejemplo, las editoriales que no han publicado libros de un autor específico:
select nombre
from editoriales
(select codigoeditorial
from libros
codigo serial,
nombre varchar(30),
);
codigo serial,
titulo varchar(40),
autor varchar(30),
codigoeditorial smallint,
primary key(codigo)
);
320
insert into editoriales(nombre) values('Siglo XXI');
-- Queremos conocer el nombre de las editoriales que han publicado libros del autor "Richard
Bach":
select nombre
from editoriales
where codigo in
(select codigoeditorial
from libros
-- Probamos la subconsulta separada de la consulta exterior para verificar que retorna una lista
select codigoeditorial
from libros
from editoriales as e
join libros
on codigoeditorial=[Link]
321
-- También podemos buscar las editoriales que no han publicado libros de "Richard Bach":
select nombre
from editoriales
(select codigoeditorial
from libros
322
61 - Subconsultas any - some - all
"any" y "some" son sinónimos. Chequean si alguna fila de la lista resultado de una subconsulta se
encuentra el valor especificado en la condición.
Compara un valor escalar con los valores de un campo y devuelven "true" si la comparación con
cada valor de la lista de la subconsulta es verdadera, sino "false".
...VALORESCALAR OPERADORDECOMPARACION
ANY (SUBCONSULTA);
Queremos saber los títulos de los libros de "Borges" que pertenecen a editoriales que han
publicado también libros de "Richard Bach", es decir, si los libros de "Borges" coinciden con
ALGUNA de las editoriales que publicó libros de "Richard Bach":
select titulo
from libros
codigoeditorial = any
(select [Link]
from editoriales as e
join libros as l
on codigoeditorial=[Link]
La consulta interna (subconsulta) retorna una lista de valores de un solo campo (puede ejecutar
la subconsulta como una consulta para probarla), luego, la consulta externa compara cada valor
de "codigoeditorial" con cada valor de la lista devolviendo los títulos de "Borges" que coinciden.
"all" también compara un valor escalar con una serie de valores. Chequea si TODOS los valores de
la lista de la consulta externa se encuentran en la lista de valores devuelta por la consulta interna.
Sintaxis:
Queremos saber si TODAS las editoriales que publicaron libros de "Borges" coinciden con TODAS
las editoriales que publicaron libros de "Richard Bach":
select titulo
323
from libros
codigoeditorial = all
(select [Link]
from editoriales as e
join libros as l
on codigoeditorial=[Link]
La consulta interna (subconsulta) retorna una lista de valores de un solo campo (puede ejecutar
la subconsulta como una consulta para probarla), luego, la consulta externa compara cada valor
de "codigoeditorial" con cada valor de la lista, si TODOS coinciden, devuelve los títulos.
Queremos saber si ALGUN precio de los libros de "Borges" es mayor a ALGUN precio de los libros
de "Richard Bach":
select titulo,precio
from libros
(select precio
from libros
where autor='Bach');
El precio de cada libro de "Borges" es comparado con cada valor de la lista de valores retornada
por la subconsulta; si ALGUNO cumple la condición, es decir, es mayor a ALGUN precio de
"Richard Bach", se lista.
select titulo,precio
from libros
(select precio
from libros
324
where autor='bach');
El precio de cada libro de "Borges" es comparado con cada valor de la lista de valores retornada
por la subconsulta; si cumple la condición, es decir, si es mayor a TODOS los precios de "Richard
Bach" (o al mayor), se lista.
codigo serial,
nombre varchar(30),
);
codigo serial,
titulo varchar(40),
autor varchar(30),
codigoeditorial smallint,
precio decimal(5,2),
primary key(codigo)
);
-- Mostramos los títulos de los libros de "Borges" de editoriales que han publicado
select titulo
from libros
codigoeditorial = any
(select [Link]
from editoriales as e
join libros as l
on codigoeditorial=[Link]
select titulo
from libros
codigoeditorial = all
(select [Link]
326
from editoriales as e
join libros as l
on codigoeditorial=[Link]
-- Mostramos los títulos y precios de los libros "Borges" cuyo precio supera
select titulo,precio
from libros
(select precio
from libros
select titulo,precio
from libros
(select precio
from libros
(select precio
327
from libros
328
62 - Subconsultas correlacionadas
Un almacén almacena la información de sus ventas en una tabla llamada "facturas" en la cual
guarda el número de factura, la fecha y el nombre del cliente y una tabla denominada "detalles"
en la cual se almacenan los distintos items correspondientes a cada factura: el nombre del
artículo, el precio (unitario) y la cantidad.
Se necesita una lista de todas las facturas que incluya el número, la fecha, el cliente, la cantidad
de artículos comprados y el total:
select f.*,
(select count([Link])
from Detalles as d
(select sum([Link]*cantidad)
from Detalles as d
from facturas as f;
El segundo "select" retorna una lista de valores de una sola columna con la cantidad de items por
factura (el número de factura lo toma del "select" exterior); el tercer "select" retorna una lista de
valores de una sola columna con el total por factura (el número de factura lo toma del "select"
exterior); el primer "select" (externo) devuelve todos los datos de cada factura.
cliente varchar(30),
primary key(numero)
);
articulo varchar(30),
precio decimal(5,2),
cantidad int,
primary key(numerofactura,numeroitem)
);
select f.*,
(select count([Link])
from detalles as d
(select sum([Link]*cantidad)
from detalles as d
from facturas as f;
331
63 - Subconsultas (Exists y Not Exists)
Los operadores "exists" y "not exists" se emplean para determinar si hay o no datos en una lista
de valores.
Cuando se coloca en una subconsulta el operador "exists", PostgreSQL analiza si hay datos que
coinciden con la subconsulta, no se devuelve ningún registro, es como un test de existencia;
PostgreSQL termina la recuperación de registros cuando por lo menos un registro cumple la
condición "where" de la subconsulta.
En este ejemplo se usa una subconsulta correlacionada con un operador "exists" en la cláusula
"where" para devolver una lista de clientes que compraron el artículo "lapiz":
select cliente,numero
from facturas as f
where exists
where [Link]=[Link]
and [Link]='lapiz');
Podemos buscar los clientes que no han adquirido el artículo "lapiz" empleando "if not exists":
select cliente,numero
from facturas as f
where [Link]=[Link]
and [Link]='lapiz');
332
Ingresemos el siguiente lote de comandos SQL en Navicat:
fecha date,
cliente varchar(30),
primary key(numero)
);
articulo varchar(30),
precio decimal(5,2),
cantidad int,
primary key(numerofactura,numeroitem)
);
select cliente,numero
from facturas as f
where exists
where [Link]=[Link]
and [Link]='lapiz');
select cliente,numero
from facturas as f
where [Link]=[Link]
and [Link]='lapiz');
334
335
64 - Subconsulta simil autocombinación
Algunas sentencias en las cuales la consulta interna y la externa emplean la misma tabla pueden
reemplazarse por una autocombinación.
Por ejemplo, queremos una lista de los libros que han sido publicados por distintas editoriales.
from libros as l1
where [Link] in
(select [Link]
from libros as l2
from libros as l1
join libros as l2
on [Link]=[Link] and
[Link]=[Link]
where [Link]<>[Link];
Otro ejemplo: Buscamos todos los libros que tienen el mismo precio que "El aleph" empleando
subconsulta:
select titulo
from libros
precio =
(select precio
from libros
Buscamos los libros cuyo precio supere el precio promedio de los libros por editorial:
select [Link],[Link],[Link]
from libros as l1
(select avg([Link])
from libros as l2
Por cada valor de l1, se evalúa la subconsulta, si el precio es mayor que el promedio.
codigo serial,
titulo varchar(40),
autor varchar(30),
editorial varchar(20),
precio decimal(5,2),
primary key(codigo)
);
values('El aleph','Borges','Emece',10.00);
337
insert into libros(titulo,autor,editorial,precio)
values('Ilusiones','Richard Bach','Planeta',15.00);
values('Uno','Richard Bach','Planeta',10.00);
-- Obtenemos la lista de los libros que han sido publicados por distintas
from libros as l1
where [Link] in
(select [Link]
from libros as l2
from libros as l1
join libros as l2
on [Link]=[Link]
where [Link]<>[Link];
from libros
precio =
(select precio
from libros
select [Link]
from libros as l1
join libros as l2
on [Link]=[Link]
[Link]<>[Link];
select [Link],[Link],[Link]
from libros as l1
(select avg([Link])
from libros as l2
select [Link],[Link],[Link]
from libros as l1
join libros as l2
339
on [Link]=[Link]
340
65 - Subconsulta en lugar de una tabla
Se la denomina tabla derivada y se coloca en la cláusula "from" para que la use un "select"
externo.
La tabla derivada debe ir entre paréntesis y tener un alias para poder referenciarla. La sintaxis
básica es la siguiente:
select [Link]
Podemos probar la consulta que retorna la tabla derivada y luego agregar el "select" externo:
select f.*,
(select sum([Link]*cantidad)
from Detalles as d
from facturas as f;
La consulta anterior contiene una subconsulta correlacionada; retorna todos los datos de
"facturas" y el monto total por factura de "detalles". Esta consulta retorna varios registros y
varios campos y será la tabla derivada que emplearemos en la siguiente consulta:
select [Link],[Link],[Link]
from clientes as c
(select sum([Link]*cantidad)
from Detalles as d
from facturas as f) as td
on [Link]=[Link];
La consulta anterior retorna, de la tabla derivada (referenciada con "td") el número de factura y
el monto total, y de la tabla "clientes", el nombre del cliente. Note que este "join" no emplea 2
341
tablas, sino una tabla propiamente dicha y una tabla derivada, que es en realidad una
subconsulta.
codigo serial,
nombre varchar(30),
domicilio varchar(30),
primary key(codigo)
);
fecha date,
primary key(numero)
);
articulo varchar(30),
precio decimal(5,2),
cantidad int,
primary key(numerofactura,numeroitem)
);
342
insert into clientes(nombre,domicilio) values('Juan Lopez','Colon 123');
select f.*,
(select sum([Link]*cantidad)
from detalles as d
from facturas as f;
-- y recuperar el número de factura, el nombre del cliente y el monto total por factura:
select [Link],[Link],[Link]
from clientes as c
(select sum([Link]*cantidad)
from detalles as d
from facturas as f) as td
on [Link]=[Link];
344
66 - Subconsulta (update - delete)
Dijimos que podemos emplear subconsultas en sentencias "insert", "update", "delete", además
de "select".
where codigoeditorial=
(select codigo
from editoriales
where nombre='Emece');
Eliminamos todos los libros de las editoriales que tiene publicados libros de "Juan Perez":
where codigoeditorial in
(select [Link]
from editoriales as e
join libros
on codigoeditorial=[Link]
La subconsulta es una combinación que retorna una lista de valores que la consulta externa
emplea al seleccionar los registros para la eliminación.
codigo serial,
nombre varchar(30),
);
codigo serial,
titulo varchar(40),
autor varchar(30),
codigoeditorial smallint,
precio decimal(5,2),
primary key(codigo)
);
values('Uno','Richard Bach',1,15);
values('Ilusiones','Richard Bach',2,20);
values('El aleph','Borges',3,10);
values('Poemas','Juan Perez',1,20);
values('Cuentos','Juan Perez',3,25);
where codigoeditorial=
(select codigo
from editoriales
where nombre='Emece');
-- Eliminamos todos los libros de las editoriales que tiene publicados libros de "Juan Perez":
where codigoeditorial in
(select [Link]
from editoriales as e
join libros
on codigoeditorial=[Link]
347
67 - Subconsulta (insert)
Aprendimos que una subconsulta puede estar dentro de un "select", "update" y "delete";
también puede estar dentro de un "insert".
select (CAMPOSTABLACONSULTADA)
from TABLACONSULTADA;
Un profesor almacena las notas de sus alumnos en una tabla llamada "alumnos". Tiene otra tabla
llamada "aprobados", con algunos campos iguales a la tabla "alumnos" pero en ella solamente
almacenará los alumnos que han aprobado el ciclo.
select (documento,nota)
from alumnos;
Entonces, se puede insertar registros en una tabla con la salida devuelta por una consulta a otra
tabla; para ello escribimos la consulta y le anteponemos "insert into" junto al nombre de la tabla
en la cual ingresaremos los registros y los campos que se cargarán (si se ingresan todos los
campos no es necesario listarlos).
La cantidad de columnas devueltas en la consulta debe ser la misma que la cantidad de campos a
cargar en el "insert".
Se pueden insertar valores en una tabla con el resultado de una consulta que incluya cualquier
tipo de "join".
nombre varchar(30),
348
nota decimal(4,2),
primary key(documento)
);
nota decimal(4,2),
primary key(documento)
);
select documento,nota
from alumnos
where nota>=4;
349
350
68 - Vistas
Una vista es una alternativa para mostrar datos de varias tablas. Una vista es como una tabla
virtual que almacena una consulta. Los datos accesibles a través de la vista no están almacenados
en la base de datos como un objeto.
Entonces, una vista almacena una consulta como un objeto para utilizarse posteriormente. Las
tablas consultadas en una vista se llaman tablas base. En general, se puede dar un nombre a
cualquier consulta y almacenarla como una vista.
Una vista suele llamarse también tabla virtual porque los resultados que retorna y la manera de
referenciarlas es la misma que para una tabla.
- simplificar la administración de los permisos de usuario: se pueden dar al usuario permisos para
que solamente pueda acceder a los datos a través de vistas, en lugar de concederle permisos
para acceder a ciertos campos, así se protegen las tablas base de cambios en su estructura.
Podemos crear vistas con: un subconjunto de registros y campos de una tabla; una unión de
varias tablas; una combinación de varias tablas; un resumen estadístico de una tabla; un
subconjunto de otra vista, combinación de vistas y tablas.
SENTENCIAS SELECT
from TABLA;
from empleados as e
join secciones as s
on codigo=seccion
from vista_empleados;
Los nombres para vistas deben seguir las mismas reglas que cualquier identificador. Para
distinguir una tabla de una vista podemos fijar una convención para darle nombres, por ejemplo,
colocar el sufijo “vista” y luego el nombre de las tablas consultadas en ellas.
Los campos y expresiones de la consulta que define una vista DEBEN tener un nombre. Se debe
colocar nombre de campo cuando es un campo calculado o si hay 2 campos con el mismo
nombre. Note que en el ejemplo, al concatenar los campos "apellido" y "nombre" colocamos un
alias; si no lo hubiésemos hecho aparecería un mensaje de error porque dicha expresión DEBE
tener un encabezado, PostgreSQL no lo coloca por defecto.
Los nombres de los campos y expresiones de la consulta que define una vista DEBEN ser únicos
(no puede haber dos campos o encabezados con igual nombre). Note que en la vista definida en
el ejemplo, al campo "[Link]" le colocamos un alias porque ya había un encabezado (el alias
de la concatenación) llamado "nombre" y no pueden repetirse, si sucediera, aparecería un
mensaje de error.
as
SENTENCIASSELECT
from TABLA;
as
from empleados
352
group by extract(year from fechaingreso);
La diferencia es que se colocan entre paréntesis los encabezados de las columnas que aparecerán
en la vista. Si no los colocamos y empleamos la sintaxis vista anteriormente, se emplean los
nombres de los campos o alias (que en este caso habría que agregar) colocados en el "select" que
define la vista. Los nombres que se colocan entre paréntesis deben ser tantos como los campos o
expresiones que se definen en la vista.
Al crear una vista, PostgreSQL verifica que existan las tablas a las que se hacen referencia en ella.
Se aconseja probar la sentencia "select" con la cual definiremos la vista antes de crearla para
asegurarnos que el resultado que retorna es el imaginado.
codigo serial,
nombre varchar(20),
sueldo decimal(5,2),
);
legajo serial,
documento char(8),
sexo char(1),
apellido varchar(20),
nombre varchar(20),
domicilio varchar(30),
353
seccion smallint not null,
cantidadhijos smallint,
estadocivil char(10),
fechaingreso date,
);
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('22222222','f','Lopez','Ana','Colon 123',1,2,'casado','1990-10-10');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('23333333','m','Lopez','Luis','Sucre 235',1,0,'soltero','1990-02-10');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('24444444','m','Garcia','Marcos','Sarmiento 1234',2,3,'divorciado','1998-07-12');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('25555555','m','Gomez','Pablo','Bulnes 321',3,2,'casado','1998-10-09');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('26666666','f','Perez','Laura','Peru 1254',3,3,'casado','2000-05-09');
-- se muestran 5 campos:
354
create view vista_empleados as
from empleados as e
join secciones as s
on codigo=seccion;
from vista_empleados
group by seccion;
as
from empleados
-- Vemos la información:
355
356
69 - Vistas (eliminar)
Si se intenta eliminar una tabla a la que hace referencia una vista, la tabla no se elimina, hay que
eliminar la vista previamente.
codigo serial,
nombre varchar(20),
sueldo decimal(5,2),
);
legajo serial,
documento char(8),
sexo char(1),
apellido varchar(20),
nombre varchar(20),
domicilio varchar(30),
357
cantidadhijos smallint,
estadocivil char(10),
fechaingreso date,
);
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('22222222','f','Lopez','Ana','Colon 123',1,2,'casado','1990-10-10');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('23333333','m','Lopez','Luis','Sucre 235',1,0,'soltero','1990-02-10');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('24444444','m','Garcia','Marcos','Sarmiento 1234',2,3,'divorciado','1998-07-12');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('25555555','m','Gomez','Pablo','Bulnes 321',3,2,'casado','1998-10-09');
(documento,sexo,apellido,nombre,domicilio,seccion,cantidadhijos,estadocivil,fechaingreso)
values('26666666','f','Perez','Laura','Peru 1254',3,3,'casado','2000-05-09');
358
select (apellido||' '||[Link]) as nombre,sexo,
from empleados as e
join secciones as s
on codigo=seccion;
-- Eliminamos la vista:
359
70 - Secuencias (create sequence- alter sequence
- nextval - drop sequence)
Una secuencia (sequence) se emplea para generar valores enteros secuenciales únicos y
asignárselos a campos numéricos; se utilizan generalmente para las claves primarias de las tablas
garantizando que sus valores no se repitan (normalmente utilizamos la definición de un campo
serial, este tiene asociado una secuencia en forma automática)
Una secuencia es una tabla con un campo numérico en el cual se almacena un valor y cada vez
que se consulta, se incrementa tal valor para la próxima consulta.
Sintaxis general:
increment by VALORENTERO
maxvalue VALORENTERO
minvalue VALORENTERO
cycle;
- La cláusula "start with" indica el valor desde el cual comenzará la generación de números
secuenciales. Si no se especifica, se inicia con el valor que indique "minvalue".
- La cláusula "increment by" especifica el incremento, es decir, la diferencia entre los números de
la secuencia; debe ser un valor numérico entero positivo o negativo diferente de 0. Si no se
indica, por defecto es 1.
- La cláusula "cycle" indica que, cuando la secuencia llegue a máximo valor (valor de "maxvalue")
se reinicie, comenzando con el mínimo valor ("minvalue") nuevamente, es decir, la secuencia
vuelve a utilizar los números. Si se omite, por defecto la secuencia se crea "nocycle", lo que
produce un error si supera el máximo valor.
360
En el siguiente ejemplo creamos una secuencia llamada "sec_codigolibros", estableciendo que
comience en 1, sus valores estén entre 1 y 99999 y se incrementen en 1, por defecto, será
"nocycle":
start with 1
increment by 1
maxvalue 99999
minvalue 1;
Si bien, las secuencias son independientes de las tablas, se utilizarán generalmente para una tabla
específica, por lo tanto, es conveniente darle un nombre que referencie a la misma.
Otro ejemplo:
start with 2
increment by 5
cycle;
Dijimos que las secuencias son tablas; por lo tanto se accede a ellas mediante consultas,
empleando "select".
select nextval('sec_numerosocios');
select nextval('sec_numerosocios');
Imprime un 2 y un 3.
Creamos una secuencia para el código de la tabla "libros", especificando el valor máximo, el
incremento y que no sea circular:
minvalue 1000
maxvalue 999999
361
increment by 1;
codigo nextval('sec_codigolibros'),
titulo varchar(30),
autor varchar(30),
editorial varchar(15),
);
Luego si imprimimos los dos registros podemos comprobar que el campo codigo almacena el
valor 1000 y 1001 respectivamente.
Si la secuencia depende de otro objeto (en este caso una tabla) no se procede al borrado),
debemos primero borrar la tabla y luego la secuencia, o utilizar (borra los objetos asociados a la
secuencia):
increment by VALORENTERO
maxvalue VALORENTERO
minvalue VALORENTERO
362
cycle;
minvalue 1000
maxvalue 999999
increment by 1;
titulo varchar(30),
autor varchar(30),
editorial varchar(15),
);
363
364
71 - Funciones
Hemos visto que PostgreSQL nos brinda un conjunto de funciones para el manejo de fechas,
string, números etc. pero además nos permite crear funciones propias.
La creación de una función es muy útil cuando queremos reutilizar un algoritmo. Podemos crear
una función y luego llamarla en diferentes situaciones.
as
[definición de la función]
Se utiliza la sintaxis 'create or replace funtion' por si ya se creó la función con anterioridad (si no
disponemos 'or repalce' y la función ya existe aparecerá un mensaje de error)
La [definición de la función] depende del lenguaje utilizado para codificarla, pudiendo ser:
SQL
PL/PGSQL
PL/TCL
PL/Perl
365
72 - Funciones SQL
La forma más fácil de implementar funciones es utilizar el lenguaje SQL. Una función SQL nos
permite dar un nombre a uno o varios comandos sql.
as
[comandos sql]
language sql
Como primer problema implementaremos una función que reciba dos enteros y retorne la suma
de los mismos:
AS
'select $1+$2;'
language sql;
Cada parámetro se lo accede luego mediante la posición que ocupa y se le antecede el caracter $.
El o los comandos SQL deben ir entre simples comillas (si tenemos que utilizar las simples
comillas en el comando SQL debemos disponer dos simples comillas seguidas) y separados por
punto y coma. Luego indicamos al final que se trata de una función SQL.
select sumar(3,4);
nombre varchar(30),
clave varchar(10)
);
as
366
'select clave from usuarios where nombre=$1;'
language sql;
Luego para probar la función retornarclave debemos llamarla por ejemplo desde un select:
select retornarclave('Susana');
AS
'select $1+$2;'
language sql;
select sumar(3,4);
nombre varchar(30),
clave varchar(10)
);
-- Creamos una función que reciba una cadena con el nombre de usuario
language sql;
select retornarclave('Susana');
368
73 - Función SQL que no retorna dato (void)
Cuando queremos crear una función que no retorne dato lo debemos indicar luego de la palabra
clave returns disponiendo el valor void:
as
[comandos sql]
language sql
as
$$
$$
language sql;
Otra sintaxis permitida en PostgreSQL es encerrar los comando SQL entre dos símbolos de $ (esto
es muy útil si tenemos que utilizar la simple comilla dentro de los comandos SQL, en caso de
disponer como delimitador las simples comillas la función debe expresarse:
as
'
'
369
language sql;
select cargarusuarios();
nombre varchar(30),
clave varchar(10)
);
as
$$
$$
language sql;
select cargarusuarios();
Hemos visto que una función puede no retornar dato, retornar un dato simple (integer, varchar
etc.) Ahora veremos como retornar toda una fila de una tabla.
Para indicar que una función retorna una fila de una tabla debemos indicar luego de la palabra
returns el nombre de la tabla. Por ejemplo si creamos la tabla libros y cargamos algunos registros:
codigo serial,
editorial varchar(20),
precio decimal(6,2),
);
values('El aleph','Borges','Emece',25.33);
Luego al definir la función indicamos el nombre de la tabla como dato que devuelve:
as
372
language sql;
Debemos siempre disponer un comando SQL que retorne una fila de la tabla. Luego al llamar la
función con un código de libro:
select retornarlibro(4);
Tenemos como resultado un dato compuesto con todos los campos de dicha fila:
codigo serial,
editorial varchar(20),
precio decimal(6,2),
);
values('El aleph','Borges','Emece',25.33);
373
create or replace function retornarlibro(int) returns libros
as
language sql;
-- Llamamos a la función:
select retornarlibro(4);
374
75.- Disparadores TRIGGERS
Introduccion
Conceptos Básicos
Creación de Disparadores
documento varchar(8),
operation VARCHAR(10),
old_data JSONB,
new_data JSONB,
change_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
BEGIN
RETURN NEW;
RETURN NEW;
RETURN OLD;
END IF;
END;
$$ LANGUAGE plpgsql;
product_id INT,
quantity INT,
order_date DATE
);
BEGIN
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Tipos de Disparadores
Ventajas:
Desventajas:
Conclusion