1 - Objetivos del tutorial de PostgreSQL.
El tutorial 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.
La única herramienta que necesitamos inicialmente es este sitio ya que podrá ejecutar todos los
problemas como son la creación de tablas, insert, delete, update, definición de índices y
restricciones, vistas, subconsultas, creación de trigger etc.
La única restricción es que todos los visitantes de este sitio comparten la misma base de datos
llamada: base1_000003 (este nombre un poco singular se debe a que las empresas de hosting es
la que lo define)
Siempre que lancemos un comando SQL en el sitio [Link] estaremos
accediendo a la base de datos base1_000003.
2 - Crear una tabla (create table)
Una base de datos almacena su información en tablas.
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.
Cada registro contiene un dato por cada columna de la tabla.
Cada campo (columna) debe tener un nombre. El nombre del campo hace referencia a la
información que almacenará.
Cada campo (columna) también debe definir el tipo de dato que almacenará.
Las tablas forman parte de una base de datos.
Nosotros trabajaremos con la base de datos llamada bd1 , que ya he creado en el servidor
[Link].
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.
La sintaxis básica y general para crear una tabla es la siguiente:
create table NOMBRETABLA(
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:
create table usuarios (
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:
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 con otros usuarios de este sitio que creen tablas
con el mismo nombre hemos creado una rutina que borra todas las tablas luego que ejecuta el
ejercicio.
Para ver la estructura de una tabla consultaremos una tabla propia del PostgreSQL:
SELECT table_name,column_name,udt_name,character_maximum_length
FROM information_schema.columns WHERE table_name = 'usuarios';
Aparece el nombre de la tabla, los nombres de columna y el largo máximo de cada campo.:
table_name column_name udt_name character_maximum_length
usuarios clave varchar 10
usuarios nombre varchar 30
Para eliminar una tabla usamos "drop table" junto al nombre de la tabla a eliminar:
drop table usuarios;
Si intentamos eliminar una tabla que no existe, aparece un mensaje de error indicando tal
situación y la sentencia no se ejecuta.
2 - Crear una tabla (create table)
Primer problema:
Necesita almacenar los datos de sus amigos en una tabla. Los datos que
guardará serán: apellido,
nombre, domicilio y teléfono.
1- Intente crear una tabla llamada "/agenda":
create table /agenda(
apellido varchar(30),
nombre varchar(20),
domicilio varchar(30),
telefono varchar(11)
);
aparece un mensaje de error porque usamos un caracter inválido ("/") para el
nombre.
2- Cree una tabla llamada "agenda", debe tener los siguientes campos:
apellido, varchar(30); nombre,
varchar(20); domicilio, varchar (30) y telefono, varchar(11).
3- Intente crearla nuevamente. Aparece mensaje de error.
4- Visualice la estructura de la tabla "agenda".
5- Elimine la tabla.
6- Intente eliminar nuevamente la tabla. Debe aparecer un mensaje de error.
Ver solución
Segundo problema:
Necesita almacenar información referente a los libros de su biblioteca
personal. Los datos que
guardará serán: título del libro, nombre del autor y nombre de la editorial.
1- Cree una tabla llamada "libros". Debe definirse con los siguientes campos:
titulo, varchar(20);
autor, varchar(30) y editorial, varchar(15).
2- Intente crearla nuevamente. Aparece mensaje de error.
3- Visualice la estructura de la tabla "libros".
4- Elimine la tabla.
5- Intente eliminar la tabla nuevamente.
Ver solución
3 - Insertar y recuperar registros de una
tabla (insert into - select)
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.
La sintaxis básica y general es la siguiente:
insert into NOMBRETABLA (NOMBRECAMPO1, ..., NOMBRECAMPOn)
values (VALORCAMPO1, ..., VALORCAMPOn);
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.
Para agregar un registro a la tabla tipeamos:
insert into usuarios (nombre, clave) values ('Mariano','payaso');
Note que los datos ingresados, como corresponden a cadenas de caracteres se colocan entre
comillas simples.
Para ver los registros de una tabla usamos "select":
select * from usuarios;
El comando "select" recupera los registros de una tabla.
Con el asterisco indicamos que muestre todos los campos de la tabla "usuarios".
Es importante ingresar los valores en el mismo orden en que se nombran los campos:
insert into usuarios (clave, nombre) values ('River','Juan');
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":
insert into usuarios (nombre,clave) values ('Boca','Luis');
3 - Insertar y recuperar registros de una
tabla (insert into - select)
Primer problema:
Trabaje con la tabla "agenda" que almacena información de sus amigos.
1- Cree una tabla llamada "agenda". Debe tener los siguientes campos: apellido
(cadena de 30),
nombre (cadena de 20), domicilio (cadena de 30) y telefono (cadena de 11)
2 - Visualice la estructura de la tabla "agenda".
3- Ingrese los siguientes registros:
insert into agenda (apellido, nombre, domicilio, telefono)
values ('Moreno','Alberto','Colon 123','4234567');
insert into agenda (apellido,nombre, domicilio, telefono)
values ('Torres','Juan','Avellaneda 135','4458787');
4- Seleccione todos los registros de la tabla:
select * from agenda;
5- Elimine la tabla "agenda":
6- Intente eliminar la tabla nuevamente (aparece un mensaje de error)
Ver solución
Segundo problema:
Trabaje con la tabla "libros" que almacena los datos de los libros de su
propia biblioteca.
1- Cree una tabla llamada "libros". Debe definirse con los siguientes campos:
titulo (cadena de 20), autor (cadena de 30) y editorial (cadena de 15).
2- Visualice la estructura de la tabla "libros".
3- Ingrese los siguientes registros:
insert into libros (titulo,autor,editorial)
values ('El aleph','Borges','Planeta');
insert into libros (titulo,autor,editorial)
values ('Martin Fierro','Jose Hernandez','Emece');
insert into libros (titulo,autor,editorial)
values ('Aprenda PHP','Mario Molina','Emece');
4- Muestre todos los registros (select).
Ver solución
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.
4 - Tipos de datos básicos
Primer problema:
Un videoclub que alquila películas en video almacena la información de sus
películas en una tabla
llamada "peliculas"; para cada película necesita los siguientes datos:
-nombre, cadena de caracteres de 20 de longitud,
-actor, cadena de caracteres de 20 de longitud,
-duración, valor numérico entero.
-cantidad de copias: valor entero.
1- Cree la tabla eligiendo el tipo de dato adecuado para cada campo.
2- Vea la estructura de la tabla.
3- Ingrese los siguientes registros:
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mision imposible','Tom Cruise',128,3);
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mision imposible 2','Tom Cruise',130,2);
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mujer bonita','Julia Roberts',118,3);
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Elsa y Fred','China Zorrilla',110,2);
4- Muestre todos los registros.
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados" que
guarda los siguientes
datos: nombre, documento, sexo, domicilio, sueldobasico.
1- Cree la tabla eligiendo el tipo de dato adecuado para cada campo.
2- Vea la estructura de la tabla:
3- Ingrese algunos registros:
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Juan Perez','22333444','m','Sarmiento 123',500);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Ana Acosta','24555666','f','Colon 134',650);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Bartolome Barrios','27888999','m','Urquiza 479',800);
4- Seleccione todos los registros.
Ver solución
5 - Recuperar algunos campos (select)
Hemos aprendido cómo ver todos los registros de una tabla, empleando la instrucción "select".
La sintaxis básica y general es la siguiente:
select * from NOMBRETABLA;
El asterisco (*) indica que se seleccionan todos los campos de la tabla.
Podemos especificar el nombre de los campos que queremos ver separándolos por comas:
select titulo,autor from libros;
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.
5 - Recuperar algunos campos (select)
Primer problema:
Un videoclub que alquila películas en video almacena la información de sus
películas en alquiler en
una tabla llamada "peliculas".
1- Cree la tabla:
create table peliculas(
titulo varchar(20),
actor varchar(20),
duracion integer,
cantidad integer
);
2- Vea la estructura de la tabla.
3- Ingrese alos siguientes registros:
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible','Tom Cruise',180,3);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible 2','Tom Cruise',190,2);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mujer bonita','Julia Roberts',118,3);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Elsa y Fred','China Zorrilla',110,2);
4- Realice un "select" mostrando solamente el título y actor de todas las
películas
5- Muestre el título y duración de todas las peliculas
6- Muestre el título y la cantidad de copias
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla llamada
"empleados".
1- Cree la tabla:
create table empleados(
nombre varchar(20),
documento varchar(8),
sexo varchar(1),
domicilio varchar(30),
sueldobasico float
);
2- Vea la estructura de la tabla
3- Ingrese algunos registros:
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Juan Juarez','22333444','m','Sarmiento 123',500);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Ana Acosta','27888999','f','Colon 134',700);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Carlos Caseres','31222333','m','Urquiza 479',850);
4- Muestre todos los datos de los empleados
5- Muestre el nombre, documento y domicilio de los empleados
6- Realice un "select" mostrando el documento, sexo y sueldo básico de todos
los empleados
Ver solución
6 - Recuperar algunos registros (where)
Hemos aprendido a seleccionar algunos campos de una tabla.
También es posible recuperar algunos registros.
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:
select nombre, clave
from usuarios
where nombre='Marcelo';
La sintaxis básica y general es la siguiente:
select NOMBRECAMPO1, ..., NOMBRECAMPOn
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.
Entonces, con "where" establecemos condiciones para recuperar algunos registros.
Para recuperar algunos campos de algunos registros combinamos en la consulta la lista de
campos y la cláusula "where":
select nombre
from usuarios
where clave='River';
En la consulta anterior solicitamos el nombre de todos los usuarios cuya clave sea igual a
"River".
6 - Recuperar algunos registros (where)
Primer problema:
Trabaje con la tabla "agenda" en la que registra los datos de sus amigos.
1- Cree la tabla, con los siguientes campos: apellido (cadena de 30), nombre
(cadena de 20),
domicilio (cadena de 30) y telefono (cadena de 11).
2- Visualice la estructura de la tabla "agenda".
3- Ingrese los siguientes registros:
Acosta, Ana, Colon 123, 4234567;
Bustamante, Betina, Avellaneda 135, 4458787;
Lopez, Hector, Salta 545, 4887788;
Lopez, Luis, Urquiza 333, 4545454;
Lopez, Marisa, Urquiza 333, 4545454.
4- Seleccione todos los registros de la tabla
5- Seleccione el registro cuyo nombre sea "Marisa" (1 registro)
6- Seleccione los nombres y domicilios de quienes tengan apellido igual a
"Lopez" (3 registros)
7- Muestre el nombre de quienes tengan el teléfono "4545454" (2 registros)
Ver solución
Segundo problema:
Trabaje con la tabla "libros" de una librería que guarda información referente
a sus libros
disponibles para la venta.
1- Cree la tabla "libros". Debe tener la siguiente estructura:
create table libros (
titulo varchar(20),
autor varchar(30),
editorial varchar(15));
2- Visualice la estructura de la tabla "libros".
3- Ingrese los siguientes registros:
El aleph,Borges,Emece;
Martin Fierro,Jose Hernandez,Emece;
Martin Fierro,Jose Hernandez,Planeta;
Aprenda PHP,Mario Molina,Siglo XXI;
4- Seleccione los registros cuyo autor sea "Borges" (1 registro)
5- Seleccione los títulos de los libros cuya editorial sea "Emece" (2
registros)
6- Seleccione los nombres de las editoriales de los libros cuyo titulo sea
"Martin Fierro" (2
registros)
Ver solución
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:
select * from libros
where autor='Borges';
Utilizamos el operador relacional de igualdad.
Los operadores relacionales vinculan un campo con un valor para que PostgreSQL compare cada
registro (el campo especificado) con el valor dado.
Los operadores relacionales son los siguientes:
= igual
<> distinto
> mayor
< menor
>= mayor o igual
<= menor o igual
Podemos seleccionar los registros cuyo autor sea diferente de "Borges", para ello usamos la
condición:
select * from libros
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 pesos:
select titulo, precio
from libros
where precio>20;
Queremos seleccionar los libros cuyo precio sea menor o igual a 30:
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.
7 - Operadores relacionales
Primer problema:
Un comercio que vende artículos de computación registra los datos de sus
artículos en una tabla con
ese nombre.
1- Cree la tabla, con la siguiente estructura:
create table articulos(
codigo integer,
nombre varchar(20),
descripcion varchar(30),
precio float,
cantidad integer
);
2- Ingrese algunos registros:
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (1,'impresora','Epson Stylus C45',400.80,20);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (2,'impresora','Epson Stylus C85',500,30);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (3,'monitor','Samsung 14',800,10);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (4,'teclado','ingles Biswal',100,50);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (5,'teclado','español Biswal',90,50);
3- Seleccione los datos de las impresoras (2 registros)
4- Seleccione los artículos cuyo precio sea mayor o igual a 400 (3 registros)
5- Seleccione el código y nombre de los artículos cuya cantidad sea menor a 30
(2 registros)
6- Selecciones el nombre y descripción de los artículos que NO cuesten $100 (4
registros)
Ver solución
Segundo problema:
Un video club que alquila películas en video almacena la información de sus
películas en alquiler
en una tabla denominada "peliculas".
1- Cree la tabla eligiendo el tipo de dato adecuado para cada campo:
create table peliculas(
titulo varchar(20),
actor varchar(20),
duracion integer,
cantidad integer
);
2- Ingrese los siguientes registros:
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible','Tom Cruise',120,3);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible 2','Tom Cruise',180,4);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mujer bonita','Julia R.',90,1);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Elsa y Fred','China Zorrilla',80,2);
3- Seleccione las películas cuya duración no supere los 90 minutos (2
registros)
4- Seleccione el título de todas las películas en las que el actor NO sea "Tom
Cruise" (2
registros)
5- Muestre todos los campos, excepto "duracion", de todas las películas de las
que haya más de 2
copias (2 registros)
Ver solución
8 - Borrar registros (delete)
Para eliminar los registros de una tabla usamos el comando "delete":
delete from usuarios;
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":
delete from usuarios
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.
8 - Borrar registros (delete)
Para eliminar los registros de una tabla usamos el comando "delete":
delete from usuarios;
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":
delete from usuarios
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.
9 - Actualizar registros (update)
Decimos que actualizamos un registro cuando modificamos alguno de sus valores.
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":
update usuarios set clave='RealMadrid';
Utilizamos "update" junto al nombre de la tabla y "set" junto con el campo a modificar y su
nuevo valor.
El cambio afectará a todos los registros.
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:
update usuarios set clave='Boca'
where nombre='Federicolopez';
Si PostgreSQL no encuentra registros que cumplan con la condición del "where", no se modifica
ninguno.
Las condiciones no son obligatorias, pero si omitimos la cláusula "where", la actualización
afectará a todos los registros.
También podemos actualizar varios campos en una sola instrucción:
update usuarios set nombre='Marceloduarte', clave='Marce'
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.
9 - Actualizar registros (update)
Primer problema:
Trabaje con la tabla "agenda" que almacena los datos de sus amigos.
1- Cree la tabla:
create table agenda(
apellido varchar(30),
nombre varchar(20),
domicilio varchar(30),
telefono varchar(11)
);
2- Ingrese los siguientes registros:
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Acosta','Alberto','Colon 123','4234567');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Juarez','Juan','Avellaneda 135','4458787');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Lopez','Maria','Urquiza 333','4545454');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Lopez','Jose','Urquiza 333','4545454');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Suarez','Susana','Gral. Paz 1234','4123456');
3- Modifique el registro cuyo nombre sea "Juan" por "Juan Jose" (1 registro
afectado)
4- Actualice los registros cuyo número telefónico sea igual a "4545454" por
"4445566"
(2 registros afectados)
5- Actualice los registros que tengan en el campo "nombre" el valor "Juan" por
"Juan Jose" (ningún
registro afectado porque ninguno cumple con la condición del "where")
6 - Luego de cada actualización ejecute un select que muestre todos los
registros de la tabla.
Ver solución
Segundo problema:
Trabaje con la tabla "libros" de una librería.
1- Créela con los siguientes campos: titulo (cadena de 30 caracteres de
longitud), autor (cadena de
20), editorial (cadena de 15) y precio (float):
create table libros (
titulo varchar(30),
autor varchar(20),
editorial varchar(15),
precio float
);
2- Ingrese los siguientes registros:
insert into libros (titulo, autor, editorial, precio)
values ('El aleph','Borges','Emece',25.00);
insert into libros (titulo, autor, editorial, precio)
values ('Martin Fierro','Jose Hernandez','Planeta',35.50);
insert into libros (titulo, autor, editorial, precio)
values ('Aprenda PHP','Mario Molina','Emece',45.50);
insert into libros (titulo, autor, editorial, precio)
values ('Cervantes y el quijote','Borges','Emece',25);
insert into libros (titulo, autor, editorial, precio)
values ('Matematica estas ahi','Paenza','Siglo XXI',15);
3- Muestre todos los registros (5 registros):
4- Modifique los registros cuyo autor sea igual a "Paenza", por "Adrian
Paenza" (1 registro
afectado)
5- Nuevamente, modifique los registros cuyo autor sea igual a "Paenza", por
"Adrian Paenza"
(ningún registro afectado porque ninguno cumple la condición)
6- Actualice el precio del libro de "Mario Molina" a 27 pesos (1 registro
afectado):
update libros set precio=27
where autor='Mario Molina';
7- Actualice el valor del campo "editorial" por "Emece S.A.", para todos los
registros cuya
editorial sea igual a "Emece" (3 registros afectados)
8 - Luego de cada actualización ejecute un select que muestre todos los
registros de la tabla.
Ver solución
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:
select * from libros -- mostramos los registros de libros;
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 (*/).
select titulo, autor
/*mostramos títulos y
nombres de los autores*/
from libros;
todo lo que está entre los símbolos "/*" y "*/" no se ejecuta.
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".
A veces, puede desconocerse o no existir el dato correspondiente a algún campo de un registro.
En estos casos decimos que el campo puede contener valores nulos.
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.
En contraposición, tenemos campos que no pueden estar vacíos jamás.
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:
create table libros(
titulo varchar(30) not null,
autor varchar(20) not null,
editorial varchar(15) null,
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:
insert into libros (titulo,autor,editorial,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.
También podemos colocar "null" en el campo "editorial" si desconocemos el nombre de la
editorial a la cual pertenece el libro que vamos a ingresar:
insert into libros (titulo,autor,editorial,precio)
values('Alicia en el pais','Lewis Carroll',null,25);
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:
insert into libros (titulo,autor,editorial,precio)
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
where table_name = 'libros';
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):
select * from libros
where precio is null;
La sentencia anterior tendrá una salida diferente a la siguiente:
select * from libros
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:
select * from libros where editorial is null;
select * from libros where editorial='';
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".
11 - Valores null (is null)
Primer problema:
Una farmacia guarda información referente a sus medicamentos en una tabla
llamada "medicamentos".
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo integer not null,
nombre varchar(20) not null,
laboratorio varchar(20),
precio float,
cantidad integer not null
);
2- Visualice la estructura de la tabla "medicamentos" indicando si el campo
admite valores null.
3- Ingrese algunos registros con valores "null" para los campos que lo
admitan:
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(1,'Sertal gotas',null,null,100);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(2,'Sertal compuesto',null,8.90,150);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(3,'Buscapina','Roche',null,200);
4- Vea todos los registros:
5- Ingrese un registro con valor "0" para el precio y cadena vacía para el
laboratorio.
6- Ingrese un registro con valor "0" para el código y cantidad y cadena vacía
para el nombre.
7- Muestre todos los registros.
8- Intente ingresar un registro con valor nulo para un campo que no lo admite
(aparece un mensaje de error):
9- Recupere los registros que contengan valor "null" en el campo
"laboratorio", luego los que
tengan una cadena vacía en el mismo campo. Note que el resultado es diferente.
10- Recupere los registros que contengan valor "null" en el campo "precio",
luego los que tengan el
valor 0 en el mismo campo. Note que el resultado es distinto.
11- Recupere los registros cuyo laboratorio no contenga una cadena vacía,
luego los que sean
distintos de "null".
Note que la salida de la primera sentencia no muestra los registros con
cadenas vacías y tampoco los
que tienen valor nulo; el resultado de la segunda sentencia muestra los
registros con valor para el
campo laboratorio (incluso cadena vacía).
12- Recupere los registros cuyo precio sea distinto de 0, luego los que sean
distintos de "null".
Note que la salida de la primera sentencia no muestra los registros con valor
0 y tampoco los que
tienen valor nulo; el resultado de la segunda sentencia muestra los registros
con valor para el
campo precio (incluso el valor 0).
Ver solución
Segundo problema:
Trabaje con la tabla que almacena los datos sobre películas, llamada
"peliculas".
1- Créela con la siguiente estructura:
create table peliculas(
codigo int not null,
titulo varchar(40) not null,
actor varchar(20),
duracion int
);
2- Visualice la estructura de la tabla
note que el campo "codigo" y "titulo", en la columna "ins_nullable" muestra
"NO" y los otros campos "YES".
3- Ingrese los siguientes registros:
insert into peliculas (codigo,titulo,actor,duracion)
values(1,'Mision imposible','Tom Cruise',120);
insert into peliculas (codigo,titulo,actor,duracion)
values(2,'Harry Potter y la piedra filosofal',null,180);
insert into peliculas (codigo,titulo,actor,duracion)
values(3,'Harry Potter y la camara secreta','Daniel R.',null);
insert into peliculas (codigo,titulo,actor,duracion)
values(0,'Mision imposible 2','',150);
insert into peliculas (codigo,titulo,actor,duracion)
values(4,'','L. Di Caprio',220);
insert into peliculas (codigo,titulo,actor,duracion)
values(5,'Mujer bonita','R. Gere-J. Roberts',0);
4- Recupere todos los registros para ver cómo PostgreSQL los almacenó:
select * from peliculas;
5- Intente ingresar un registro con valor nulo para campos que no lo admiten
(aparece un mensaje de
error)
6- Muestre los registros con valor nulo en el campo "actor" y luego los que
guardan una cadena vacía
(note que la salida es distinta) (1 registro)
7- Modifique los registros que tengan valor de duración desconocido (nulo) por
"120" (1 registro
actualizado)
8- Coloque 'Desconocido' en el campo "actor" en los registros que tengan una
cadena vacía en dicho
campo (1 registro afectado)
9- Muestre todos los registros. Note que el cambio anterior no afectó a los
registros con valor
nulo en el campo "actor".
10- Elimine los registros cuyo título sea una cadena vacía (1 registro)
Ver solución
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.
Tenemos nuestra tabla "usuarios" definida con 2 campos ("nombre" y "clave").
La sintaxis básica y general es la siguiente:
create table NOMBRETABLA(
CAMPO TIPO,
...
primary key (NOMBRECAMPO)
);
En el siguiente ejemplo definimos una clave primaria, para nuestra tabla "usuarios" para
asegurarnos que cada usuario tendrá un nombre diferente y único:
create table usuarios(
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
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.
12 - Clave primaria
Primer problema:
Trabaje con la tabla "libros" de una librería.
1- Créela con los siguientes campos, estableciendo como clave primaria el
campo "codigo":
create table libros(
codigo int not null,
titulo varchar(40) not null,
autor varchar(20),
editorial varchar(15),
primary key(codigo)
);
2- Ingrese los siguientes registros:
insert into libros (codigo,titulo,autor,editorial)
values (1,'El aleph','Borges','Emece');
insert into libros (codigo,titulo,autor,editorial)
values (2,'Martin Fierro','Jose Hernandez','Planeta');
insert into libros (codigo,titulo,autor,editorial)
values (3,'Aprenda PHP','Mario Molina','Nuevo Siglo');
3- Ingrese un registro con código repetido (aparece un mensaje de error)
4- Intente ingresar el valor "null" en el campo "codigo"
5- Intente actualizar el código del libro "Martin Fierro" a "1" (mensaje de
error)
Ver solución
Segundo problema:
Un instituto de enseñanza almacena los datos de sus estudiantes en una tabla
llamada "alumnos".
1- Cree la tabla con la siguiente estructura intentando establecer 2 campos
como clave primaria, el
campo "documento" y "legajo" (no lo permite):
create table alumnos(
legajo varchar(4) not null,
documento varchar(8),
nombre varchar(30),
domicilio varchar(30),
primary key(documento),
primary key(legajo)
);
2- Cree la tabla estableciendo como clave primaria el campo "documento":
create table alumnos(
legajo varchar(4) not null,
documento varchar(8),
nombre varchar(30),
domicilio varchar(30),
primary key(documento)
);
3- Verifique que el campo "documento" no admite valores nulos
4- Ingrese los siguientes registros:
insert into alumnos (legajo,documento,nombre,domicilio)
values('A233','22345345','Perez Mariana','Colon 234');
insert into alumnos (legajo,documento,nombre,domicilio)
values('A567','23545345','Morales Marcos','Avellaneda 348');
5- Intente ingresar un alumno con número de documento existente (no lo
permite)
6- Intente ingresar un alumno con documento nulo (no lo permite)
Ver solución
13 - Campo entero serial (autoincremento)
Los valores de un campo serial, se inician en 1 y se incrementan en 1 automáticamente.
Se utiliza generalmente en campos correspondientes a códigos de identificación para generar
valores únicos para cada nuevo registro que se inserta.
Normalmente se define luego este campo como clave primaria.
Para establecer que un campo autoincremente sus valores automáticamente, éste debe ser de tipo
serial:
create table libros(
codigo serial,
titulo varchar(20),
autor varchar(30),
editorial varchar(15),
primary key (codigo)
);
Para definir un campo autoincrementable lo hacemos con la palabra clave serial.
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:
insert into libros (titulo,autor,editorial)
values('El aleph','Borges','Planeta');
Este primer registro ingresado guardará el valor 1 en el campo correspondiente al código.
Si continuamos ingresando registros, el código (dato que no ingresamos) se cargará
automáticamente siguiendo la secuencia de autoincremento.
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 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:
delete from libros where codigo=1;
insert into libros (codigo,titulo,autor,editorial)
values(1,'Aprender Python', 'Rodriguez Luis', 'Paidos');
13 - Campo entero serial (autoincremento)
Primer problema:
Una farmacia guarda información referente a sus medicamentos en una tabla
llamada "medicamentos".
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio float,
cantidad integer,
primary key (codigo)
);
2- Visualice la estructura de la tabla "medicamentos"
3- Ingrese los siguientes registros (insert into):
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Sertal','Roche',5.2,100);
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Buscapina','Roche',4.10,200);
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Amoxidal 500','Bayer',15.60,100);
4- Verifique que el campo "código" generó los valores de modo automático.
Ver solución
Segundo problema:
Un videoclub almacena información sobre sus películas en una tabla llamada
"peliculas".
1- Créela con la siguiente estructura:
-codigo (serial),
-titulo (cadena de 40),
-actor (cadena de 20),
-duracion (entero),
-clave primaria: codigo.
2- Visualice la estructura de la tabla "peliculas".
3- Ingrese los siguientes registros:
insert into peliculas (titulo,actor,duracion)
values('Mision imposible','Tom Cruise',120);
insert into peliculas (titulo,actor,duracion)
values('Harry Potter y la piedra filosofal','xxx',180);
insert into peliculas (titulo,actor,duracion)
values('Harry Potter y la camara secreta','xxx',190);
insert into peliculas (titulo,actor,duracion)
values('Mision imposible 2','Tom Cruise',120);
insert into peliculas (titulo,actor,duracion)
values('La vida es bella','zzz',220);
4- Seleccione todos los registros y verifique la carga automática de los
códigos.
5- Actualice las películas cuyo código es 3 colocando en "actor" 'Daniel R.'
6- Elimine la película 'La vida es bella'.
7- Elimine todas las películas cuya duración sea igual a 120 minutos.
8- Visualice los registros.
9- Ingrese el siguiente registro, sin valor para la clave primaria:
insert into peliculas (titulo,actor,duracion)
values('Mujer bonita','Richard Gere',120);
Note que sigue la secuencia tomando el último valor generado, aunque ya no
esté.
Ver solución
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:
truncate table libros;
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.
14 - Comando truncate table
Primer problema:
Una farmacia guarda información referente a sus medicamentos en una tabla
llamada "medicamentos".
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio float,
cantidad integer,
primary key (codigo)
);
3- Ingrese los siguientes registros:
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Sertal','Roche',5.2,100);
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Buscapina','Roche',4.10,200);
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Amoxidal 500','Bayer',15.60,100);
3- Elimine todos los registros con "delete"
4- Ingrese 2 registros:
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Sertal','Roche',5.2,100);
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Amoxidal 500','Bayer',15.60,100);
5- Vea los registros para verificar que continuó la secuencia al generar el
valor para "codigo"
6- Vacíe la tabla con truncate table
7- Ingrese el siguiente registro:
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Buscapina','Roche',4.10,200);
8- Vea los registros para verificar que al cargar el código reinició la
secuencia en 1.
Ver solución
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.
Para almacenar TEXTO usamos cadenas de caracteres.
Las cadenas se colocan entre comillas simples.
Podemos almacenar letras, símbolos y dígitos con los que no se realizan operaciones
matemáticas, por ejemplo, códigos de identificación, números de documentos, números
telefónicos.
Tenemos los siguientes tipos:
1. varchar(x): define una cadena de caracteres de longitud variable en la cual determinamos el
máximo de caracteres con el argumento "x" que va entre paréntesis.
. Su rango va de 1 a 10485760 caracteres.
2. 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.
3. 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).
Si intentamos almacenar en un campo una cadena de caracteres de mayor longitud que la
definida, aparece un mensaje indicando tal situación y la sentencia no se ejecuta.
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.
Es importante elegir el tipo de dato adecuado según el caso, el más preciso.
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.
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)'.
15 - Tipo de dato texto
Primer problema:
Una concesionaria de autos vende autos usados y almacena los datos de los
autos en una tabla
llamada "autos".
1- Cree la tabla eligiendo el tipo de dato adecuado para cada campo,
estableciendo el campo
"patente" como clave primaria:
create table autos(
patente char(6),
marca varchar(20),
modelo char(4),
precio float,
primary key (patente)
);
Hemos definido el campo "patente" de tipo "char" y no "varchar" porque la
cadena de caracteres
siempre tendrá la misma longitud (6 caracteres). Lo mismo sucede con el campo
"modelo", en el cual
almacenaremos el año, necesitamos 4 caracteres fijos.
2- Ingrese los siguientes registros:
insert into autos
values('ACD123','Fiat 128','1970',15000);
insert into autos
values('ACG234','Renault 11','1990',40000);
insert into autos
values('BCD333','Peugeot 505','1990',80000);
insert into autos
values('GCD123','Renault Clio','1990',70000);
insert into autos
values('BCC333','Renault Megane','1998',95000);
insert into autos
values('BVF543','Fiat 128','1975',20000);
3- Seleccione todos los autos del año 1990:
4- Borre la tabla.
5- Crearla nuevamente con la misma estructura pero utilizando las otras
palabras claves para los tipos
de datos char y varchar.
6- Ingrese un registro.
7- Mostrar el contenido de la tabla.
Ver solución
Segundo problema:
Una empresa almacena los datos de sus clientes en una tabla llamada
"clientes".
1- Créela eligiendo el tipo de dato más adecuado para cada campo:
create table clientes(
documento char(8),
apellido varchar(20),
nombre varchar(20),
domicilio varchar(30),
telefono varchar (11)
);
2- Analice la definición de los campos. Se utiliza char(8) para el documento
porque siempre constará
de 8 caracteres. Para el número telefónico se usar "varchar" y no un tipo
numérico porque si bien es
un número, con él no se realizarán operaciones matemáticas.
3- Ingrese algunos registros:
insert into clientes
values('2233344','Perez','Juan','Sarmiento 980','4342345');
insert into clientes (documento,apellido,nombre,domicilio)
values('2333344','Perez','Ana','Colon 234');
insert into clientes
values('2433344','Garcia','Luis','Avellaneda 1454','4558877');
insert into clientes
values('2533344','Juarez','Ana','Urquiza 444','4789900');
4- Seleccione todos los clientes de apellido "Perez" (2 registros)
Ver solución
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 NUMERICOS PostgreSQL dispone de varios tipos.
Para almacenar valores ENTEROS, por ejemplo, en campos que hacen referencia a cantidades,
usamos:
1) int (integer o int4): su rango es de -2000000000 a 2000000000 aprox.
2) smallint (int2): Puede contener hasta 5 digitos. Su rango va desde –32000 hasta 32000 aprox.
3) bigint (int8): De –9000000000000000000 hasta 9000000000000000000 aprox.
Los campos de tipo serial : se almacenan en un campo de tipo int
y los bigserial : se almacenan en un campo de tipo bigint.
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.
El rango depende de los argumentos, también los bytes que ocupa.
Se utiliza el punto como separador de decimales.
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.67", redondeando hacia
abajo.
Para almacenar valores numéricos APROXIMADOS con decimales utilizamos:
5) float (real): De 1E-37 to 1E+37. Guarda valores aproximados.
6) double precision (float8): Desde 1E-307 to 1E+308. Guarda valores aproximados.
Para todos los tipos numéricos:
- si intentamos ingresar un valor fuera de rango, no lo permite.
- si ingresamos una cadena, PostgreSQL intenta convertirla a valor numérico, si dicha cadena
consta solamente de dígitos, la conversión se realiza, luego verifica si está dentro del rango, si es
así, la ingresa, sino, muestra un mensaje de error y no ejecuta la sentencia. Si la cadena contiene
caracteres que PostgreSQL no puede convertir a valor numérico, muestra un mensaje de error y
la sentencia no se ejecuta.
Por ejemplo, definimos un campo de tipo decimal(5,2), si ingresamos la cadena '12.22', la
convierte al valor numérico 12.22 y la ingresa; si intentamos ingresar la cadena '1234.56', la
convierte al valor numérico 1234.56, pero como el máximo valor permitido es 999.99, muestra
un mensaje indicando que está fuera de rango. Si intentamos ingresar el valor '12y.25',
PostgreSQL no puede realizar la conversión y muestra un mensaje de error.
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.
16 - Tipo de dato numérico
Primer problema:
Un banco tiene registrados las cuentas corrientes de sus clientes en una tabla
llamada "cuentas".
La tabla contiene estos datos:
Número de Cuenta Documento Nombre Saldo
______________________________________________________________
1234 25666777 Pedro Perez 500000.60
2234 27888999 Juan Lopez -250000
3344 27888999 Juan Lopez 4000.50
3346 32111222 Susana Molina 1000
1- Cree la tabla eligiendo el tipo de dato adecuado para almacenar los datos
descriptos arriba:
- Número de cuenta: entero, no puede haber valores repetidos, clave primaria;
- Documento del propietario de la cuenta: cadena de caracteres de 8 de
longitud (siempre 8), no nulo;
- Nombre del propietario de la cuenta: cadena de caracteres de 30 de
longitud,
- Saldo de la cuenta: valores altos con decimales.
2- Ingrese los siguientes registros:
insert into cuentas(numero,documento,nombre,saldo)
values('1234','25666777','Pedro Perez',500000.60);
insert into cuentas(numero,documento,nombre,saldo)
values('2234','27888999','Juan Lopez',-250000);
insert into cuentas(numero,documento,nombre,saldo)
values('3344','27888999','Juan Lopez',4000.50);
insert into cuentas(numero,documento,nombre,saldo)
values('3346','32111222','Susana Molina',1000);
Note que hay dos cuentas, con distinto número de cuenta, de la misma persona.
3- Seleccione todos los registros cuyo saldo sea mayor a "4000" (2 registros)
4- Muestre el número de cuenta y saldo de todas las cuentas cuyo propietario
sea "Juan Lopez" (2
registros)
5- Muestre las cuentas con saldo negativo (1 registro)
6- Muestre todas las cuentas cuyo número es igual o mayor a "3000" (2
registros):
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados" que
guarda los siguientes
datos: nombre, documento, sexo, domicilio, sueldobasico.
1- Cree la tabla eligiendo el tipo de dato adecuado para cada campo:
create table empleados(
nombre varchar(30),
documento char(8),
sexo char(1),
domicilio varchar(30),
sueldobasico decimal(7,2),--máximo estimado 99999.99
cantidadhijos smallint --no superará los 255
);
2- Ingrese algunos registros:
insert into empleados
(nombre,documento,sexo,domicilio,sueldobasico,cantidadhijos)
values ('Juan Perez','22333444','m','Sarmiento 123',500,2);
insert into empleados
(nombre,documento,sexo,domicilio,sueldobasico,cantidadhijos)
values ('Ana Acosta','24555666','f','Colon 134',850,0);
insert into empleados
(nombre,documento,sexo,domicilio,sueldobasico,cantidadhijos)
values ('Bartolome Barrios','27888999','m','Urquiza 479',10000.80,4);
3- Ingrese un valor de "sueldobasico" con más decimales que los definidos
(redondea los decimales al
valor más cercano 800.89):
insert into empleados
(nombre,documento,sexo,domicilio,sueldobasico,cantidadhijos)
values ('Susana Molina','29000555','f','Salta 876',800.888,3);
4- Intente ingresar un sueldo que supere los 7 dígitos (no lo permite)
5- Muestre todos los empleados cuyo sueldo no supere los 900 pesos (1
registro):
6- Seleccione los nombres de los empleados que tengan hijos (3 registros):
Ver solución
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.
2) time: Almacena la hora del día.
3) timestamp: Almacena la fecha y la hora del día.
Las fechas se ingresan entre comillas simples.
Para almacenar valores de tipo fecha se permiten como separadores "/", "-","." entre otros.
PostgreSQL requiere que se ingrese la fecha con el formato aaaa/mm/dd:
insert into empleados values('Ana Gomez','22222222','2008/12/31');
PostgreSQL permite configurar el formato de ingreso de la fecha seteando la variable de entorno
llamada DATESTYLE:
SET DATESTYLE TO 'European';
Con el ejemplo anterior luego podemos ingresar una fecha con el formato Europeo que es
dd/mm/aaaa:
insert into empleados values('Pablo Rodriguez','11111111','31/12/2008');
Otros valores de seteo son:
ISO utiliza fechas y horas de estilo ISO 8601.
SQL utiliza fechas y horas de estilo Oracle/Ingres.
Postgres utiliza el formato tradicional de Postgres.
European utiliza dd/mm/aaaa para la representación numérica de las fechas.
NonEuropean utiliza mm/dd/aaaa para la representación numérica de las fechas.
German utiliza [Link] para la representación numérica de las fechas.
US igual que 'NonEuropean'
DEFAULT recupera los valores por defecto ('US,Postgres')
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.
insert into asistencia(fecha,hora) values ('2008/12/31','13:00:59');
Por último si queremos almacenar la fecha y la hora en un único campo debemos definirlo de
tipo timestamp:
insert into asistencia (fechahora) values ('2008/12/31 13:00:00.59');
17 - Tipo de dato fecha y hora
Primer problema:
Una facultad almacena los datos de sus alumnos en una tabla denominada
"alumnos".
1- Cree la tabla eligiendo el tipo de dato adecuado para cada campo:
create table alumnos(
apellido varchar(30),
nombre varchar(30),
documento char(8),
domicilio varchar(30),
fechaingreso date,
fechanacimiento date
);
2- Setee el formato para entrada de datos de tipo fecha para que acepte
valores "día-mes-año"
3- Ingrese un alumno empleando distintos separadores para las fechas:
insert into alumnos values('Gonzalez','Ana','22222222','Colon 123','20-08-
1990','15/02/1972');
4- Ingrese otro alumno empleando solamente un dígito para día y mes y 2 para
el año:
insert into alumnos values('Juarez','Bernardo','25555555','Sucre 456','03-03-
1991','15/02/1972');
5- Ingrese un alumnos empleando 2 dígitos para el año de la fecha de ingreso y
"null" en
"fechanacimiento":
insert into alumnos values('Perez','Laura','26666666','Bulnes 345','03-03-
91',null);
6- Intente ingresar un alumno con fecha de ingreso correspondiente a "15 de
marzo de 1990" pero en
orden incorrecto "03-15-90":
insert into alumnos values('Lopez','Carlos','27777777','Sarmiento 1254','03-
15-1990',null);
aparece un mensaje de error porque lo lee con el formato día, mes y año y no
reconoce el mes 15.
7- Muestre todos los alumnos que ingresaron antes del '1-1-91'. 1 registro.
8- Muestre todos los alumnos que tienen "null" en "fechanacimiento". 1
registro.
Ver solución
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.
Un valor por defecto se inserta cuando no está presente al ingresar un registro.
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":
create table libros(
codigo serial,
titulo varchar(40),
autor varchar(30) not null default 'Desconocido',
editorial varchar(20),
precio decimal(5,2),
cantidad smallint default 0,
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.
Ahora, al visualizar la estructura de la tabla podemos entender lo que informa la columna
"column_default", muestra el valor por defecto del campo.
También se puede utilizar "default" para dar el valor por defecto a los campos en sentencias
"insert", por ejemplo:
insert into libros (titulo,autor,precio,cantidad)
values ('El gato con botas',default,default,100);
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:
insert into libros default values;
La sentencia anterior almacenará un registro con los valores predetermiandos para cada uno de
sus campos.
Entonces, la cláusula "default" permite especificar el valor por defecto de un campo. Si no se
explicita, el valor por defecto es "null", siempre que el campo no haya sido declarado "not null".
Los campos para los cuales no se ingresan valores en un "insert" tomarán los valores por defecto:
- si tiene el atributo "identity": el valor de inicio de la secuencia si es el primero o el siguiente
valor de la secuencia, no admite cláusula "default";
- si permite valores nulos y no tiene cláusula "default", almacenará "null";
- 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.
18 - Valores por defecto (default)
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
1- Cree la tabla con la siguiente estructura:
create table visitantes(
nombre varchar(30),
edad smallint,
sexo char(1) default 'f',
domicilio varchar(30),
ciudad varchar(20) default 'Cordoba',
telefono varchar(11),
mail varchar(30) default 'no tiene',
montocompra decimal (6,2)
);
2- Vea la información de las columnas "column_default" y "is_nullable"
3- Ingrese algunos registros sin especificar valores para algunos campos para
ver cómo opera la
cláusula "default":
insert into visitantes (nombre, domicilio, montocompra)
values ('Susana Molina','Colon 123',59.80);
insert into visitantes (nombre, edad, ciudad, mail)
values ('Marcos Torres',29,'Carlos Paz','marcostorres@[Link]');
select * from visitantes;
4- Use la palabra "default" para ingresar valores en un insert.
5- Ingrese un registro con "default values".
Ver solución
Segundo problema:
Una pequeña biblioteca de barrio registra los préstamos de sus libros en una
tabla llamada
"prestamos". En ella almacena la siguiente información: título del libro,
documento de identidad del
socio a quien se le presta el libro, fecha de préstamo, fecha en que tiene que
devolver el libro y
si el libro ha sido o no devuelto.
1- Cree la tabla:
create table prestamos(
titulo varchar(40) not null,
documento char(8) not null,
fechaprestamo date not null,
fechadevolucion date,
devuelto char(1) default 'n'
);
2- Ingrese algunos registros omitiendo el valor para los campos que lo
admiten:
insert into prestamos (titulo,documento,fechaprestamo,fechadevolucion)
values ('Manual de 1 grado','23456789','2006-12-15','2006-12-18');
insert into prestamos (titulo,documento,fechaprestamo)
values ('Alicia en el pais de las maravillas','23456789','2006-12-16');
insert into prestamos (titulo,documento,fechaprestamo,fechadevolucion)
values ('El aleph','22543987','2006-12-16','2006-08-19');
insert into prestamos (titulo,documento,fechaprestamo,devuelto)
values ('Manual de geografia 5 grado','25555666','2006-12-18','s');
3- Seleccione todos los registros
4- Ingrese un registro colocando "default" en los campos que lo admiten y vea
cómo se almacenó.
5- Intente ingresar un registro con "default values" y analice el mensaje de
error (no se puede)
Ver solución
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.
Los operadores aritméticos permiten realizar cálculos con valores numéricos.
Son: multiplicación (*), división (/) y módulo (%) (el resto de dividir números enteros), suma (+)
y resta (-).
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:
select titulo, precio,cantidad,
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;
También podemos actualizar los datos empleando operadores aritméticos:
update libros set precio=precio-(precio*0.1);
Todas las operaciones matemáticas retornan error si no se pueden ejecutar. Ejemplo:
select 5/0;
Los operadores de concatenación: permite concatenar cadenas, el más (||).
Para concatenar el título, el autor y la editorial de cada libro usamos el operador de
concatenación ("||"):
select titulo||'-'||autor||'-'||editorial
from libros;
Note que concatenamos además unos guiones para separar los campos.
19 - Columnas calculadas (operadores
aritméticos y de concatenación)
Primer problema:
Un comercio que vende artículos de computación registra los datos de sus
artículos en una tabla con
ese nombre.
1- Cree la tabla:
create table articulos(
codigo serial,
nombre varchar(20),
descripcion varchar(30),
precio decimal(9,2),
cantidad smallint default 0,
primary key (codigo)
);
2- Ingrese algunos registros:
insert into articulos (nombre, descripcion, precio,cantidad)
values ('impresora','Epson Stylus C45',400.80,20);
insert into articulos (nombre, descripcion, precio)
values ('impresora','Epson Stylus C85',500);
insert into articulos (nombre, descripcion, precio)
values ('monitor','Samsung 14',800);
insert into articulos (nombre, descripcion, precio,cantidad)
values ('teclado','ingles Biswal',100,50);
3- El comercio quiere aumentar los precios de todos sus artículos en un 15%.
Actualice todos los
precios empleando operadores aritméticos.
4- Vea el resultado
5- Muestre todos los artículos, concatenando el nombre y la descripción de
cada uno de ellos
separados por coma.
6- Reste a la cantidad de todos los teclados, el valor 5, empleando el
operador aritmético menos ("-")
Ver solución
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:
select nombre as Nombreyapellido,
domicilio,telefono
from agenda;
Para reemplazar el nombre de un campo por otro, se coloca la palabra clave "as" seguido del
texto del encabezado.
Se puede crear un alias para columnas calculadas.
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.
20 - Alias
Primer problema:
Trabaje con la tabla "libros" de una librería.
1- Cree la tabla:
create table libros(
codigo serial,
titulo varchar(40) not null,
autor varchar(20) default 'Desconocido',
editorial varchar(20),
precio decimal(6,2),
cantidad smallint default 0,
primary key (codigo)
);
2- Ingrese algunos registros:
insert into libros (titulo,autor,editorial,precio)
values('El aleph','Borges','Emece',25);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Java en 10 minutos','Mario Molina','Siglo XXI',50.40,100);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Alicia en el pais de las maravillas','Lewis Carroll','Emece',15,50);
3- Muestre todos los campos de los libros y un campo extra, con el encabezado
"monto_total" en la
que calcule el monto total en dinero de cada libro (precio por cantidad)
4- Muestre el título, autor y precio de todos los libros de editorial "Emece"
y agregue dos columnas
extra en las cuales muestre el descuento de cada libro, con el encabezado
"descuento" y el precio
con un 10% de descuento con el encabezado "precio_final".
5- Muestre una columna con el título y el autor concatenados con el encabezado
"título_y_autor"
Ver solución
21 - Funciones para el manejo de cadenas
PostgreSQL tiene algunas funciones para trabajar con cadenas de caracteres. Estas son algunas:
char_length(string): Retorna la longitud del texto. Ejemplo:
select char_length('Hola');
retorna un 4.
upper(string): Retorna el texto convertido a mayúsculas. Ejemplo:
select upper('Hola');
retorna 'HOLA'.
lower(string): Retorna el texto convertido a minúsculas. Ejemplo:
select lower('Hola');
retorna 'hola'.
position(string in string): Retorna la posición de un string dentro de otro. Si no está contenido
retorna un 0. Ejemplo:
select position('Mundo' in 'Hola Mundo');
retorna 6.
select position('MUNDO' in 'Hola Mundo');
retorna 0 (ya que no coinciden mayúsculas y minúsculas)
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:
select substring('Hola Mundo' from 1 for 2);
retorna 'Ho'.
select substring('Hola Mundo' from 6 for 5);
retorna 'Mundo'.
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:
select char_length(trim(' Hola Mundo '));
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.
select char_length(trim(leading ' ' from ' Hola Mundo '));
retorna un 12. Esto es debido a indicamos que elimine los espacios en blanco de la cadena solo
del comienzo (leading).
select trim(trailing '-' from '--Hola Mundo----');
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:
select char_length(ltrim(' Hola'));
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:
select char_length(rtrim('Hola '));
retorna un 4.
select rtrim('Hola----','-');
retorna un 'Hola'.
substr(text,int[,int]): Retorna una subcadena a partir de la posición que le indicamos en el
segundo parámetro hasta la posición indicada en el tercer parámetro. Ejemplo:
select substr('Hola Mundo',2,4);
retorna 'ola'.
select substr('Hola Mundo',2);
retorna 'ola Mundo' (si no indicamos el tercer parámetro retorna todo el string hasta el final)
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:
select lpad('Hola Mundo',20,'-');
retorna '----------Hola Mundo'.
rpad(text,int,text): Rellena de caracteres por la derecha. El tamaño total de campo es indicado
por el segundo parámetro y el texto a insertar se indica en el tercero. Ejemplo:
select rpad('Hola Mundo',20,'-');
retorna 'Hola Mundo----------'.
select rpad('Hola Mundo',20,'-*');
retorna 'Hola Mundo-*-*-*-*-*'.
21 - Funciones para el manejo de cadenas
Primer problema:
Trabaje con la tabla que almacena los datos de clientes.
1- Créela con la siguiente estructura:
create table clientes(
documento char(8),
apellido varchar(20),
nombre varchar(20),
domicilio varchar(30),
telefono varchar (11)
);
2- Ingresar algunos registros:
insert into clientes(documento,apellido,nombre,domicilio,telefono)
values('2233344','Perez','Juan','Sarmiento 980','4342345');
insert into clientes (documento,apellido,nombre,domicilio,telefono)
values('2333344','Perez','Ana','Colon 234','2345123');
insert into clientes(documento,apellido,nombre,domicilio,telefono)
values('2433344','Garcia','Luis','Avellaneda 1454','4558877');
insert into clientes (documento,apellido,nombre,domicilio,telefono)
values('2533344','Juarez','Ana','Urquiza 444','4789900');
3- Mostrar todos los registros disponiendo en mayúsculas el apellido y el
nombre.
4- Mostrar el primer caracter del nombre.
Ver solución
22 - Funciones matemáticas
Las funciones matemáticas realizan operaciones con expresiones numéricas y retornan un
resultado, operan con tipos de datos numéricos.
PostgreSQL tiene algunas funciones para trabajar con números. Aquí presentamos algunas.
abs(x): retorna el valor absoluto del argumento "x". Ejemplo:
select abs(-20);
retorna 20.
cbrt(x): retorna la raíz cúbica del argumento "x". Ejemplo:
select cbrt(27);
retorna 3.
ceiling(x): redondea hacia arriba el argumento "x". Ejemplo:
select ceiling(12.34);
retorna 13.
floor(x): redondea hacia abajo el argumento "x". Ejemplo:
select floor(12.34);
retorna 12.
power(x,y): retorna el valor de "x" elevado a la "y" potencia. Ejemplo:
select power(2,3);
retorna 8.
round(numero): retorna un número redondeado al valor más próximo. Ejemplo:
select round(10.4);
retorna "10".
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".
mod(x,y): devuelve el resto de dividir x con respecto a y. Ejemplo:
select mod(11,2);
retorna "1".
pi(): devuelve el valor de pi. Ejemplo:
select pi();
retorna "3.14159265358979".
random(): devuelve un valor aleatorio entre 0 y 1 (sin incluirlos). Ejemplo:
select random();
retorna por ejemplo "0.895562474101578".
trunc(x): Retorna la parte entera del parámetro. Ejemplo:
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".
sin(x): Retorna el valor del seno en radianes. Ejemplo:
select sin(0);
retorna "0".
cos(x): Retorna el valor del coseno en radianes. Ejemplo:
select cos(0);
retorna "1".
tan(x): Retorna el valor de la tangente en radianes. Ejemplo:
select tan(0);
retorna "0".
22 - Funciones matemáticas
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Créela con la siguiente estructura:
create table clientes (
codigo serial,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
provincia varchar (20),
credito decimal(9,2),
primary key(codigo)
);
2- Ingrese 5 registros:
insert into clientes(nombre,domicilio,ciudad,provincia,credito)
values ('Lopez Marcos','Colon 111','Cordoba','Cordoba',1900.56);
insert into clientes(nombre,domicilio,ciudad,provincia,credito)
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba',450.33);
insert into clientes(nombre,domicilio,ciudad,provincia,credito)
values ('Garcia Juan','Rivadavia 333','Villa del Rosario','Cordoba',190);
insert into clientes(nombre,domicilio,ciudad,provincia,credito)
values ('Olmos Luis','Sarmiento 444','Rosario','Santa Fe',670.22);
insert into clientes(nombre,domicilio,ciudad,provincia,credito)
values ('Pereyra Lucas','San Martin 555','Cruz del Eje','Cordoba',500.55);
3- Muestre todos los registros.
4- Mostrar el campo crédito redondeado hacia arriba.
Ver solución
23 - Funciones para el uso de fechas y horas
PostgreSQL ofrece algunas funciones para trabajar con fechas y horas. Estas son algunas:
- current_date: retorna la fecha actual. Ejemplo:
select current_date;
Retorna por ejemplo '2009-05-20'
- current_time: retorna la hora actual con la zona horaria. Ejemplo:
select current_time;
Retorna por ejemplo '18:33:06.074493+00'
- current_timestamp: retorna la fecha y la hora actual con la zona horaria. Ejemplo:
select current_timestamp;
Retorna por ejemplo '2009-05-20 18:34:16.63131+00'
- 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:
select extract(year from timestamp'2009-12-31 12:25:50');
Retorna el año '2009'
select extract(month from timestamp'2009-12-31 12:25:50');
Retorna el mes '12'
select extract(day from timestamp'2009-12-31 12:25:50');
Retorna el día '31'
select extract(hour from timestamp'2009-12-31 12:25:50');
Retorna la hora '12'
select extract(minute from timestamp'2009-12-31 12:25:50');
Retorna el minuto '25'
select extract(second from timestamp'2009-12-31 12:25:50');
Retorna el segundo '50'
select extract(century from timestamp'2009-12-31 12:25:50');
Retorna el siglo '21'
select extract(dow from timestamp'2009-12-31 12:25:50');
Retorna el día de a semana '4'
select extract(doy from timestamp'2009-12-31 12:25:50');
Retorna el día del año '365'
select extract(week from timestamp'2009-12-31 12:25:50');
Retorna el número de semana dentro del año '53'
select extract(quarter from timestamp'2009-12-31 12:25:50');
Retorna en que cuarto del año se ubica la fecha '4'
23 - Funciones para el uso de fechas y horas
Primer problema:
Una facultad almacena los datos de sus alumnos en una tabla denominada
"alumnos".
1- Cree la tabla eligiendo el tipo de dato adecuado para cada campo:
create table alumnos(
apellido varchar(30),
nombre varchar(30),
documento char(8),
domicilio varchar(30),
fechaingreso date,
fechanacimiento date
);
2- Setee el formato para entrada de datos de tipo fecha para que acepte
valores "día-mes-año"
3- Ingrese un alumno empleando distintos separadores para las fechas
4- Ingrese otro alumno empleando solamente un dígito para día y mes y 2 para
el año
5- Ingrese un alumnos empleando 2 dígitos para el año de la fecha de ingreso y
"null" en
"fechanacimiento"
6- Muestre todos los alumnos que ingresaron antes del '1-1-91'.
7- Muestre todos los alumnos que tienen "null" en "fechanacimiento":
8- Muestre el año de nacimiento de todos los alumnos.
Ver solución
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".
La sintaxis básica es la siguiente:
select * from NOMBRETABLA
order by CAMPO;
Por ejemplo, recuperamos los registros de la tabla "libros" ordenados por el título:
select * from libros
order by titulo;
Aparecen los registros ordenados alfabéticamente por el campo especificado.
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
from libros order by 3;
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
order by editorial desc;
También podemos ordenar por varios campos, por ejemplo, por "titulo" y "editorial":
select * from libros
order by titulo,editorial;
Incluso, podemos ordenar en distintos sentidos, por ejemplo, por "titulo" en sentido ascendente y
"editorial" en sentido descendente:
select * from libros
order by titulo asc, editorial desc;
Debe aclararse al lado de cada campo, pues estas palabras claves afectan al campo
inmediatamente anterior.
Es posible ordenar por un campo que no se lista en la selección.
Se permite ordenar por valores calculados o expresiones.
24 - Ordenar registros (order by)
Primer problema:
En una página web se guardan los siguientes datos de las visitas: número de
visita, nombre, mail,
pais, fecha.
1- Créela con la siguiente estructura:
create table visitas (
numero serial,
nombre varchar(30) default 'Anonimo',
mail varchar(50),
pais varchar (20),
fecha timestamp,
primary key(numero)
);
2- Ingrese algunos registros:
insert into visitas (nombre,mail,pais,fecha)
values ('Ana Maria Lopez','AnaMaria@[Link]','Argentina','2006-10-10
10:10');
insert into visitas (nombre,mail,pais,fecha)
values ('Gustavo Gonzalez','GustavoGGonzalez@[Link]','Chile','2006-10-
10 21:30');
insert into visitas (nombre,mail,pais,fecha)
values ('Juancito','JuanJosePerez@[Link]','Argentina','2006-10-11
15:45');
insert into visitas (nombre,mail,pais,fecha)
values ('Fabiola Martinez','MartinezFabiola@[Link]','Mexico','2006-10-
12 08:15');
insert into visitas (nombre,mail,pais,fecha)
values ('Fabiola Martinez','MartinezFabiola@[Link]','Mexico','2006-09-
12 20:45');
insert into visitas (nombre,mail,pais,fecha)
values ('Juancito','JuanJosePerez@[Link]','Argentina','2006-09-12
16:20');
insert into visitas (nombre,mail,pais,fecha)
values ('Juancito','JuanJosePerez@[Link]','Argentina','2006-09-15
16:25');
3- Ordene los registros por fecha, en orden descendente.
4- Muestre el nombre del usuario, pais y el número de mes, ordenado por pais
(ascendente)
y número de mes (descendente)
5- Muestre el pais, el mes, el día y la hora y ordene las visitas por nombre
del mes, del día y la
hora.
6- Muestre los mail, país, ordenado por país, de todos los que visitaron la
página en octubre (4
registros)
Ver solución
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.
Son los siguientes:
- and, significa "y",
- or, significa "y/o",
- not, significa "no", invierte el resultado
- (), paréntesis
Los operadores lógicos se usan para combinar condiciones.
Si queremos recuperar todos los libros cuyo autor sea igual a "Borges" y cuyo precio no supere
los 20 pesos, necesitamos 2 condiciones:
select * from libros
where (autor='Borges') and
(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":
select * from libros
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":
select * from libros
where not editorial='Planeta';
El operador "not" invierte el resultado de la condición a la cual antecede.
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.
Por ejemplo, las siguientes expresiones devuelven un resultado diferente:
select * from libros
where (autor='Borges') or
(editorial='Paidos' and precio<20);
select * from libros
where (autor='Borges' or editorial='Paidos') and
(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.
25 - Operadores lógicos (and - or - not)
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(5,2),
cantidad smallint,
primary key(codigo)
);
2- Ingrese algunos registros:
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Sertal','Roche',5.2,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Buscapina','Roche',4.10,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal 500','Bayer',15.60,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Paracetamol 500','Bago',1.90,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Bayaspirina','Bayer',2.10,150);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal jarabe','Bayer',5.10,250);
3- Recupere los códigos y nombres de los medicamentos cuyo laboratorio sea
'Roche' y cuyo precio sea
menor a 5 (1 registro cumple con ambas condiciones)
4- Recupere los medicamentos cuyo laboratorio sea 'Roche' o cuyo precio sea
menor a 5 (4 registros)
Note que el resultado es diferente al del punto 4, hemos cambiado el operador
de la sentencia
anterior.
5- Muestre todos los medicamentos cuyo laboratorio NO sea "Bayer" y cuya
cantidad sea=100 (1
registro)
6- Muestre todos los medicamentos cuyo laboratorio sea "Bayer" y cuya cantidad
NO sea=100 (2 registros)
Analice estas 2 últimas sentencias. El operador "not" afecta a la condición a
la cual antecede, no a
las siguientes. Los resultados de los puntos 6 y 7 son diferentes.
7- Elimine todos los registros cuyo laboratorio sea igual a "Bayer" y su
precio sea mayor a 10 (1
registro eliminado)
8- Cambie la cantidad por 200, a todos los medicamentos de "Roche" cuyo precio
sea mayor a 5 (1
registro afectado)
9- Borre los medicamentos cuyo laboratorio sea "Bayer" o cuyo precio sea menor
a 3 (3 registros
borrados)
Ver solución
Segundo problema:
Trabajamos con la tabla "peliculas" de un video club que alquila películas en
video.
1- Créela con la siguiente estructura:
create table peliculas(
codigo serial,
titulo varchar(40) not null,
actor varchar(20),
duracion smallint,
primary key (codigo)
);
2- Ingrese algunos registros:
insert into peliculas (titulo,actor,duracion)
values('Mision imposible','Tom Cruise',120);
insert into peliculas (titulo,actor,duracion)
values('Harry Potter y la piedra filosofal','Daniel R.',180);
insert into peliculas (titulo,actor,duracion)
values('Harry Potter y la camara secreta','Daniel R.',190);
insert into peliculas (titulo,actor,duracion)
values('Mision imposible 2','Tom Cruise',120);
insert into peliculas (titulo,actor,duracion)
values('Mujer bonita','Richard Gere',120);
insert into peliculas (titulo,actor,duracion)
values('Tootsie','D. Hoffman',90);
insert into peliculas (titulo,actor,duracion)
values('Un oso rojo','Julio Chavez',100);
insert into peliculas (titulo,actor,duracion)
values('Elsa y Fred','China Zorrilla',110);
3- Recupere los registros cuyo actor sea "Tom Cruise" or "Richard Gere" (3
registros)
4- Recupere los registros cuyo actor sea "Tom Cruise" y duración menor a 100
(ninguno cumple ambas
condiciones)
5- Cambie la duración a 200, de las películas cuyo actor sea "Daniel R." y
cuya duración sea 180 (1
registro afectado)
6- Borre todas las películas donde el actor NO sea "Tom Cruise" y cuya
duración sea mayor o igual a
100 (2 registros eliminados)
Ver solución
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.
Existen otro operador relacional "is null".
Se emplea el operador "is null" para recuperar los registros en los cuales esté almacenado el
valor "null" en un campo específico:
select * from libros
where editorial is null;
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.
26 - Otros operadores relacionales (is null)
Primer problema:
Trabajamos con la tabla "peliculas" de un video club que alquila películas en
video.
1- Créela con la siguiente estructura:
create table peliculas(
codigo serial,
titulo varchar(40) not null,
actor varchar(20),
duracion smallint,
primary key (codigo)
);
2- Ingrese algunos registros:
insert into peliculas(titulo,actor,duracion)
values('Mision imposible','Tom Cruise',120);
insert into peliculas(titulo,actor,duracion)
values('Harry Potter y la piedra filosofal','Daniel R.',null);
insert into peliculas(titulo,actor,duracion)
values('Harry Potter y la camara secreta','Daniel R.',190);
insert into peliculas(titulo,actor,duracion)
values('Mision imposible 2','Tom Cruise',120);
insert into peliculas(titulo,actor,duracion)
values('Mujer bonita',null,120);
insert into peliculas(titulo,actor,duracion)
values('Tootsie','D. Hoffman',90);
insert into peliculas (titulo)
values('Un oso rojo');
3- Recupere las películas cuyo actor sea nulo (2 registros)
4- Cambie la duración a 0, de las películas que tengan duración igual a "null"
(2 registros)
5- Borre todas las películas donde el actor sea "null" y cuya duración sea 0
(1 registro)
Ver solución
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).
Otro operador relacional es "between", trabajan con intervalos de valores.
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":
select * from libros
where precio>=20 and
precio<=40;
Podemos usar "between" y así simplificar la consulta:
select * from libros
where precio between 20 and 40;
Averiguamos si el valor de un campo dado (precio) está entre los valores mínimo y máximo
especificados (20 y 40 respectivamente).
"between" significa "entre". Trabaja con intervalo de valores.
Este operador se puede emplear con tipos de datos numéricos y tipos de datos fecha y hora
(incluye sólo el valor mínimo).
No tiene en cuenta los valores "null".
Si agregamos el operador "not" antes de "between" el resultado se invierte, es decir, se recuperan
los registros que están fuera del intervalo especificado. Por ejemplo, recuperamos los libros cuyo
precio NO se encuentre entre 20 y 35, es decir, los menores a 15 y mayores a 25:
select * from libros
where precio not between 20 and 35;
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".
27 - Otros operadores relacionales (between)
Primer problema:
En una página web se guardan los siguientes datos de las visitas: número de
visita, nombre, mail,
pais, fechayhora de la visita.
1- Créela con la siguiente estructura:
create table visitas (
numero serial,
nombre varchar(30) default 'Anonimo',
mail varchar(50),
pais varchar (20),
fechayhora timestamp,
primary key(numero)
);
3- Ingrese algunos registros:
insert into visitas (nombre,mail,pais,fechayhora)
values ('Ana Maria Lopez','AnaMaria@[Link]','Argentina','2006-10-10
10:10');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Gustavo Gonzalez','GustavoGGonzalez@[Link]','Chile','2006-10-
10 21:30');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@[Link]','Argentina','2006-10-11
15:45');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Fabiola Martinez','MartinezFabiola@[Link]','Mexico','2006-10-
12 08:15');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Fabiola Martinez','MartinezFabiola@[Link]','Mexico','2006-09-
12 20:45');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@[Link]','Argentina','2006-09-12
16:20');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@[Link]','Argentina','2006-09-15
16:25');
insert into visitas (nombre,mail,pais)
values ('Federico1','federicogarcia@[Link]','Argentina');
3- Seleccione los usuarios que visitaron la página entre el '2006-09-12' y
'2006-10-11' (5
registros)
Note que incluye los de fecha mayor o igual al valor mínimo y menores al valor
máximo, y que los
valores null no se incluyen.
4- Recupere las visitas cuyo número se encuentra entre 2 y 5 (4 registros)
Note que incluye los valores límites.
Ver solución
Segundo problema:
Una concesionaria de autos vende autos usados y almacena la información en una
tabla llamada
"autos".
1- Cree la tabla con la siguiente estructura:
create table autos(
patente char(6),
marca varchar(20),
modelo char(4),
precio decimal(8,2),
primary key(patente)
);
2- Ingrese algunos registros:
insert into autos
values('ACD123','Fiat 128','1970',15000);
insert into autos
values('ACG234','Renault 11','1980',40000);
insert into autos
values('BCD333','Peugeot 505','1990',80000);
insert into autos
values('GCD123','Renault Clio','1995',70000);
insert into autos
values('BCC333','Renault Megane','1998',95000);
insert into autos
values('BVF543','Fiat 128','1975',20000);
3- Seleccione todos los autos cuyo modelo se encuentre entre '1970' y '1990'
usando el operador
"between" y ordénelos por dicho campo(4 registros)
4- Seleccione todos los autos cuyo precio esté entre 50000 y 100000.
Ver solución
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:
select * from libros
where autor='Borges' or autor='Paenza';
Podemos usar "in" y simplificar la consulta:
select * from libros
where autor in('Borges','Paenza');
Para recuperar los libros cuyo autor no sea 'Paenza' ni 'Borges' usábamos:
select * from libros
where autor<>'Borges' and
autor<>'Paenza';
También podemos usar "in" anteponiendo "not":
select * from libros
where autor not in ('Borges','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.
Los valores "null" no se consideran.
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.
28 - Otros operadores relacionales (in)
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad smallint,
fechavencimiento date not null,
primary key(codigo)
);
2- Ingrese algunos registros:
insert into medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento)
values('Sertal','Roche',5.2,1,'2005-02-01');
insert into medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento)
values('Buscapina','Roche',4.10,3,'2006-03-01');
insert into medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento)
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01');
insert into medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento)
values('Paracetamol 500','Bago',1.90,20,'2008-02-01');
insert into medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento)
values('Bayaspirina','Bayer',2.10,150,'2009-12-01');
insert into medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento)
values('Amoxidal jarabe','Bayer',5.10,250,'2010-10-01');
3- Recupere los nombres y precios de los medicamentos cuyo laboratorio sea
"Bayer" o "Bago"
empleando el operador "in" (4 registros)
4- Seleccione los remedios cuya cantidad se encuentre entre 1 y 5 empleando el
operador "between" y
luego el operador "in" (2 registros)
Note que es más conveniente emplear, en este caso, el operador ""between".
Ver solución
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":
select * from libros
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.
Imaginemos que tenemos registrados estos 2 libros:
"El Aleph", "Borges";
"Antologia poetica", "J.L. Borges";
Si queremos recuperar todos los libros de "Borges" y especificamos la siguiente condición:
select * from libros
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:
select * from libros
where autor like "%Borges%";
El símbolo "%" (porcentaje) reemplaza cualquier cantidad de caracteres (incluyendo ningún
caracter). Es un caracter comodín. "like" y "not like" son operadores de comparación que señalan
igualdad o diferencia.
Para seleccionar todos los libros que comiencen con "M":
select * from libros
where titulo like 'M%';
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.
Para seleccionar todos los libros que NO comiencen con "M":
select * from libros
where titulo not like '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:
select * from libros
where autor like "%Carrol_";
"like" se emplea con tipos de datos char, varchar, date, time, timestamp. Si empleamos "like" con
tipos de datos que no son caracteres, PostgreSQL convierte (si es posible) el tipo de dato a
caracter. Por ejemplo, queremos buscar todos los libros cuyo precio se encuentre entre 10.00 y
19.99:
select titulo,precio from libros
where precio like '1_.%';
Queremos los libros que NO incluyen centavos en sus precios:
select titulo,precio from libros
where precio like '%.00';
29 - Búsqueda de patrones (like - not like)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Cree la tabla:
create table empleados(
nombre varchar(30),
documento char(8),
domicilio varchar(30),
fechaingreso date,
seccion varchar(20),
sueldo decimal(6,2),
primary key(documento)
);
2- Ingrese algunos registros:
insert into empleados(
values('Juan Perez','22333444','Colon 123','1990-10-08','Gerencia',900.50);
insert into empleados
values('Ana Acosta','23444555','Caseros 987','1995-12-
18','Secretaria',590.30);
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','2005-05-15','Sistemas',790);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento 873','1999-02-
12','Secretaria',550);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia 801','2002-09-
22','Contaduria',630.70);
insert into empleados
values('Yolanda Perez','35111222','Colon 180','1990-10-
08','Administracion',400);
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo 588','1990-05-
28','Sistemas',800);
3- Muestre todos los empleados con apellido "Perez" empleando el operador
"like" (3 registros)
4- Muestre todos los empleados cuyo domicilio comience con "Co" y tengan un
"8" (2 registros)
5- Muestre todos los nombres y sueldos de los empleados cuyos sueldos incluyen
centavos (3
registros)
6- Muestre los empleados que hayan ingresado en "1990" (3 registros)
Ver solución
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.
30 - Contar registros (count)
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad smallint,
fechavencimiento date not null,
numerolote int default null,
primary key(codigo)
);
3- Ingrese algunos registros:
insert into
medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento,numerolote)
values('Sertal','Roche',5.2,1,'2005-02-01',null);
insert into
medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento,numerolote)
values('Buscapina','Roche',4.10,3,'2006-03-01',null);
insert into
medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento,numerolote)
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01',null);
insert into
medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento,numerolote)
values('Paracetamol 500','Bago',1.90,20,'2008-02-01',null);
insert into
medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento,numerolote)
values('Bayaspirina',null,2.10,null,'2009-12-01',null);
insert into
medicamentos(nombre,laboratorio,precio,cantidad,fechavencimiento,numerolote)
values('Amoxidal jarabe','Bayer',null,250,'2009-12-15',null);
3- Muestre la cantidad de registros empleando la función "count(*)" (6
registros)
4- Cuente la cantidad de medicamentos que tienen laboratorio conocido (5
registros)
5- Cuente la cantidad de medicamentos que tienen precio distinto a "null" y
que tienen cantidad
distinto a "null", disponer alias para las columnas.
6- Cuente la cantidad de remedios con precio conocido, cuyo laboratorio
comience con "B" (2
registros)
7- Cuente la cantidad de medicamentos con número de lote distinto de "null" (0
registros)
Ver solución
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.
Ya hemos aprendido una de ellas, "count()", veamos otras.
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:
- count: se puede emplear con cualquier tipo de dato.
- min y max: con cualquier tipo de dato.
- sum y avg: sólo en campos de tipo numérico.
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
where titulo like '%PHP%';
Ahora podemos entender porque estas funciones se denominan "funciones de agrupamiento",
porque operan sobre conjuntos de registros, no con datos individuales.
Tratamiento de los valores nulos:
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".
31 - Funciones de agrupamiento (count - sum
- min - max - avg)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Cree la tabla:
create table empleados(
nombre varchar(30),
documento char(8),
domicilio varchar(30),
seccion varchar(20),
sueldo decimal(6,2),
cantidadhijos smallint,
primary key(documento)
);
2- Ingrese algunos registros:
insert into empleados
values('Juan Perez','22333444','Colon 123','Gerencia',5000,2);
insert into empleados
values('Ana Acosta','23444555','Caseros 987','Secretaria',2000,0);
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','Sistemas',4000,1);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento 873','Secretaria',2200,3);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia 801','Contaduria',3000,0);
insert into empleados
values('Yolanda Perez','35111222','Colon 180','Administracion',3200,1);
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo 588','Sistemas',4000,3);
insert into empleados
values('Martina Rodriguez','30141414','Sarmiento
1234','Administracion',3800,4);
insert into empleados
values('Andres Costa','28444555',default,'Secretaria',null,null);
3- Muestre la cantidad de empleados usando "count" (9 empleados)
4- Muestre la cantidad de empleados con sueldo no nulo de la sección
"Secretaria" (2 empleados)
5- Muestre el sueldo más alto y el más bajo colocando un alias (5000 y 2000)
6- Muestre el valor mayor de "cantidadhijos" de los empleados "Perez" (3
hijos)
7- Muestre el promedio de sueldos de todo los empleados (3400. Note que hay un
sueldo nulo y no es
tenido en cuenta)
8- Muestre el promedio de sueldos de los empleados de la sección "Secretaría"
(2100)
9- Muestre el promedio de hijos de todos los empleados de "Sistemas" (2)
Ver solución
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:
select count(*) from libros
where editorial='Planeta';
y repetirla con cada valor de "editorial":
select count(*) from libros
where editorial='Emece';
select count(*) from libros
where editorial='Paidos';
...
Pero hay otra manera, utilizando la cláusula "group by":
select editorial, count(*)
from libros
group by editorial;
La instrucción anterior solicita que muestre el nombre de la editorial y cuente la cantidad
agrupando los registros por el campo "editorial". Como resultado aparecen los nombres de las
editoriales y la cantidad de registros para cada valor del campo.
Los valores nulos se procesan como otro grupo.
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:
select CAMPO, FUNCIONDEAGREGADO
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.
select CAMPO1, CAMPO2, FUNCIONDEAGREGADO
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):
select editorial, count(precio)
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.
Para conocer el total en dinero de los libros agrupados por editorial:
select editorial, sum(precio)
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:
select editorial, avg(precio)
from libros
group by editorial;
Es posible limitar la consulta con "where".
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 pesos:
select editorial, count(*)
from libros
where precio<30
group by editorial;
32 - Agrupar registros (group by)
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
1- Cree la tabla con la siguiente estructura:
create table visitantes(
nombre varchar(30),
edad smallint,
sexo char(1) default 'f',
domicilio varchar(30),
ciudad varchar(20) default 'Cordoba',
telefono varchar(11),
mail varchar(30) default 'no tiene',
montocompra decimal (6,2)
);
2- Ingrese algunos registros:
insert into visitantes
values ('Susana Molina',35,default,'Colon 123',default,null,null,59.80);
insert into visitantes
values ('Marcos Torres',29,'m',default,'Carlos
Paz',default,'marcostorres@[Link]',150.50);
insert into visitantes
values ('Mariana Juarez',45,default,default,'Carlos
Paz',null,default,23.90);
insert into visitantes (nombre, edad,sexo,telefono, mail)
values ('Fabian Perez',36,'m','4556677','fabianperez@[Link]');
insert into visitantes (nombre, ciudad, montocompra)
values ('Alejandra Gonzalez','La Falda',280.50);
insert into visitantes (nombre, edad,sexo, ciudad, mail,montocompra)
values ('Gaston Perez',29,'m','Carlos Paz','gastonperez1@[Link]',95.40);
insert into visitantes
values ('Liliana Torres',40,default,'Sarmiento
876',default,default,default,85);
insert into visitantes
values ('Gabriela Duarte',21,null,null,'Rio
Tercero',default,'gabrielaltorres@[Link]',321.50);
3- Queremos saber la cantidad de visitantes de cada ciudad utilizando la
cláusula "group by" (4 filas devueltas)
4- Queremos la cantidad visitantes con teléfono no nulo, de cada ciudad (4
filas devueltas)
5- Necesitamos el total del monto de las compras agrupadas por sexo (3 filas)
6- Se necesita saber el máximo y mínimo valor de compra agrupados por sexo y
ciudad (6 filas)
7- Calcule el promedio del valor de compra agrupados por ciudad (4 filas)
8- Cuente y agrupe por ciudad sin tener en cuenta los visitantes que no tienen
mail (3 filas)
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Cree la tabla:
create table empleados(
nombre varchar(30),
documento char(8),
domicilio varchar(30),
seccion varchar(20),
sueldo decimal(6,2),
cantidadhijos smallint,
fechaingreso date,
primary key(documento)
);
2- Ingrese algunos registros:
insert into empleados
values('Juan Perez','22333444','Colon 123','Gerencia',5000,2,'1980-05-10');
insert into empleados
values('Ana Acosta','23444555','Caseros 987','Secretaria',2000,0,'1980-10-
12');
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','Sistemas',4000,1,'1985-05-
25');
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento
873','Secretaria',2200,3,'1990-06-25');
insert into empleados
values('Marcos Juarez','30000111','Rivadavia 801','Contaduria',3000,0,'1996-
05-01');
insert into empleados
values('Yolanda Perez','35111222','Colon 180','Administracion',3200,1,'1996-
05-01');
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo
588','Sistemas',4000,3,'1996-05-01');
insert into empleados
values('Martina Rodriguez','30141414','Sarmiento
1234','Administracion',3800,4,'2000-09-01');
insert into empleados
values('Andres Costa','28444555',default,'Secretaria',null,null,null);
3- Cuente la cantidad de empleados agrupados por sección (5 filas)
4- Calcule el promedio de hijos por sección (5 filas)
5- Cuente la cantidad de empleados agrupados por año de ingreso (6 filas)
6- Calcule el promedio de sueldo por sección de los empleados con hijos (4
filas)
Ver solución
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:
select editorial, count(*)
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:
select editorial, count(*) from libros
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 pesos:
select editorial, avg(precio) from libros
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:
select editorial, count(*) from libros
where editorial<>'Planeta'
group by editorial;
select editorial, count(*) from libros
group by editorial
having editorial<>'Planeta';
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".
No debemos confundir la cláusula "where" con la cláusula "having"; la primera establece
condiciones para la selección de registros de un "select"; la segunda establece condiciones para
la selección de registros de una salida "group by".
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":
select editorial, count(*) from libros
where precio is not null
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:
select editorial, avg(precio) from libros
group by editorial
having count(*) > 2;
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:
select editorial, max(precio) as mayor
from libros
group by editorial
having min(precio)<100 and
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.
33 - Seleccionar grupos (having)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Créela con la siguiente estructura:
create table clientes (
codigo serial,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
provincia varchar (20),
telefono varchar(11),
primary key(codigo)
);
3- Ingrese algunos registros:
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Lopez Marcos','Colon 111','Cordoba','Cordoba','null');
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba','4578585');
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Garcia Juan','Rivadavia 333','Villa del
Rosario','Cordoba','4578445');
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe',null);
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Pereyra Lucas','San Martin 555','Cruz del
Eje','Cordoba','4253685');
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe','0345252525');
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Torres Fabiola','Alem 777','Villa del
Rosario','Cordoba','4554455');
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba',null);
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba','4223366');
insert into clientes(nombre,domicilio,ciudad,provincia,telefono)
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones','0457858745');
3- Obtenga el total de los registros agrupados por ciudad y provincia (6
filas)
4- Obtenga el total de los registros agrupados por ciudad y provincia sin
considerar los que tienen
menos de 2 clientes (3 filas)
Ver solución
Segundo problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
1- Créela con la siguiente estructura:
create table visitantes(
nombre varchar(30),
edad smallint,
sexo char(1),
domicilio varchar(30),
ciudad varchar(20),
telefono varchar(11),
montocompra decimal(6,2) not null
);
2- Ingrese algunos registros:
insert into visitantes
values ('Susana Molina',28,'f',null,'Cordoba',null,45.50);
insert into visitantes
values ('Marcela Mercado',36,'f','Avellaneda
345','Cordoba','4545454',22.40);
insert into visitantes
values ('Alberto Garcia',35,'m','Gral. Paz 123','Alta
Gracia','03547123456',25);
insert into visitantes
values ('Teresa Garcia',33,'f',default,'Alta Gracia','03547123456',120);
insert into visitantes
values ('Roberto Perez',45,'m','Urquiza 335','Cordoba','4123456',33.20);
insert into visitantes
values ('Marina Torres',22,'f','Colon 222','Villa
Dolores','03544112233',95);
insert into visitantes
values ('Julieta Gomez',24,'f','San Martin 333','Alta Gracia',null,53.50);
insert into visitantes
values ('Roxana Lopez',20,'f','null','Alta Gracia',null,240);
insert into visitantes
values ('Liliana Garcia',50,'f','Paso 999','Cordoba','4588778',48);
insert into visitantes
values ('Juan Torres',43,'m','Sarmiento 876','Cordoba',null,15.30);
3- Obtenga el total de las compras agrupados por ciudad y sexo de aquellas
filas que devuelvan un
valor superior a 50 (3 filas)
4- Agrupe por ciudad y sexo, muestre para cada grupo el total de visitantes,
la suma de sus compras
y el promedio de compras, ordenado por la suma total y considerando las filas
con promedio superior
a 30 (3 filas)
Ver solución
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:
select autor from libros;
Aparecen repetidos. Para obtener la lista de autores sin repetición usamos:
select distinct autor from libros;
También podemos tipear:
select autor from libros
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:
select distinct autor from libros
where autor is not null;
Para contar los distintos autores, sin considerar el valor "null" usamos:
select count(distinct autor)
from libros;
Note que si contamos los autores sin "distinct", no incluirá los valores "null" pero si los
repetidos:
select count(autor)
from libros;
Esta sentencia cuenta los registros que tienen autor.
Podemos combinarla con "where". Por ejemplo, queremos conocer los distintos autores de la
editorial "Planeta":
select distinct autor from libros
where editorial='Planeta';
También puede utilizarse con "group by" para contar los diferentes autores por editorial:
select editorial, count(distinct autor)
from libros
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:
select distinct titulo,editorial
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.
Entonces, "distinct" elimina registros duplicados.
34 - Registros duplicados (distinct)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Créela con la siguiente estructura:
create table clientes (
codigo serial,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
provincia varchar (20),
primary key(codigo)
);
2- Ingrese algunos registros:
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Lopez Marcos','Colon 111','Cordoba','Cordoba');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Garcia Juan','Rivadavia 333','Villa del Rosario','Cordoba');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Pereyra Lucas','San Martin 555','Cruz del Eje','Cordoba');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Torres Fabiola','Alem 777','Villa del Rosario','Cordoba');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba');
insert into clientes(nombre,domicilio,ciudad,provincia)
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones');
3- Obtenga las provincias sin repetir (3 registros)
4- Cuente las distintas provincias.
5- Se necesitan los nombres de las ciudades sin repetir (6 registros)
6- Obtenga la cantidad de ciudades distintas.
7- Combine con "where" para obtener las distintas ciudades de la provincia de
Cordoba (3 registros)
8- Contamos las distintas ciudades de cada provincia empleando "group by" (3
registros)
Ver solución
Segundo problema:
La provincia almacena en una tabla llamada "inmuebles" los siguientes datos de
los inmuebles y sus
propietarios para cobrar impuestos.
1- Créela con la siguiente estructura:
create table inmuebles (
documento varchar(8) not null,
apellido varchar(30),
nombre varchar(30),
domicilio varchar(20),
barrio varchar(20),
ciudad varchar(20),
tipo char(1),--b=baldio, e: edificado
superficie decimal (8,2)
);
3- Ingrese algunos registros:
insert into inmuebles
values ('11000000','Perez','Alberto','San Martin
800','Centro','Cordoba','e',100);
insert into inmuebles
values ('11000000','Perez','Alberto','Sarmiento 245','Gral.
Paz','Cordoba','e',200);
insert into inmuebles
values ('12222222','Lopez','Maria','San Martin
202','Centro','Cordoba','e',250);
insert into inmuebles
values ('13333333','Garcia','Carlos','Paso
1234','Alberdi','Cordoba','b',200);
insert into inmuebles
values ('13333333','Garcia','Carlos','Guemes
876','Alberdi','Cordoba','b',300);
insert into inmuebles
values ('14444444','Perez','Mariana','Caseros
456','Flores','Cordoba','b',200);
insert into inmuebles
values ('15555555','Lopez','Luis','San Martin 321','Centro','Carlos
Paz','e',500);
insert into inmuebles
values ('15555555','Lopez','Luis','Lopez y Planes 853','Flores','Carlos
Paz','e',350);
insert into inmuebles
values ('16666666','Perez','Alberto','Sucre
1877','Flores','Cordoba','e',150);
3- Muestre los distintos apellidos de los propietarios, sin repetir (3
registros)
4- Muestre los distintos documentos de los propietarios, sin repetir (6
registros)
5- Cuente, sin repetir, la cantidad de propietarios de inmuebles de la ciudad
de Cordoba (5)
6- Cuente la cantidad de inmuebles con domicilio en 'San Martin', sin repetir
la ciudad (2)
7- Muestre los apellidos y nombres, sin repetir (5 registros)
Note que hay 2 personas con igual nombre y apellido que aparece una sola vez.
8- Muestre la cantidad de inmuebles que tiene cada propietario agrupando por
documento, sin repetir
barrio (6 registros)
Ver solución
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 una playa de estacionamiento que almacena cada día los datos de los vehículos que
ingresan en la tabla llamada "vehiculos" con los siguientes campos:
- patente char(6) not null,
- tipo char (1), 'a'= auto, 'm'=moto,
- 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 a la playa; 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 a la playa, 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:
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada time,
horasalida time,
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.
35 - Clave primaria compuesta
Primer problema:
Un consultorio médico en el cual trabajan 3 médicos registra las consultas de
los pacientes en una
tabla llamada "consultas".
1- La tabla contiene los siguientes datos:
- fechayhora: timestamp not null, fecha y hora de la consulta,
- medico: varchar(30), not null, nombre del médico (Perez,Lopez,Duarte),
- documento: char(8) not null, documento del paciente,
- paciente: varchar(30), nombre del paciente,
- obrasocial: varchar(30), nombre de la obra social (IPAM,PAMI, etc.).
);
2- Un médico sólo puede atender a un paciente en una fecha y hora determinada.
En una fecha y hora
determinada, varios médicos atienden a distintos pacientes. Cree la tabla
definiendo una clave
primaria compuesta:
create table consultas(
fechayhora timestamp not null,
medico varchar(30) not null,
documento char(8) not null,
paciente varchar(30),
obrasocial varchar(30),
primary key(fechayhora,medico)
);
3- Ingrese varias consultas para un mismo médico en distintas horas el mismo
día.
4- Ingrese varias consultas para diferentes médicos en la misma fecha y hora.
5- Intente ingresar una consulta para un mismo médico en la misma hora el
mismo día.
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes. En una tabla llamada "inscriptos"
almacena la
información necesaria.
1- La tabla contiene los siguientes campos:
- documento del socio alumno: char(8) not null
- nombre del socio: varchar(30),
- nombre del deporte (tenis, futbol, natación, basquet): varchar(15) not
null,
- año de inscripcion: smallint,
- matrícula: si la matrícula ha sido o no pagada ('s' o 'n').
2- Necesitamos una clave primaria que identifique cada registro. Un socio
puede inscribirse en
varios deportes en distintos años. Un socio no puede inscribirse en el mismo
deporte el mismo año.
Varios socios se inscriben en un mismo deporte en distintos años. Cree la
tabla con una clave
compuesta:
create table inscriptos(
documento char(8) not null,
nombre varchar(30),
deporte varchar(15) not null,
año date,
matricula char(1),
primary key(documento,deporte,año)
);
3- Inscriba a varios alumnos en el mismo deporte en el mismo año
4- Inscriba a un mismo alumno en varios deportes en el mismo año
5- Ingrese un registro con el mismo documento de socio en el mismo deporte en
distintos años
6- Intente inscribir a un socio alumno en un deporte en el cual ya esté
inscripto.
7- Intente actualizar un registro para que la clave primaria se repita.
Ver solución
36 - Restricción check
La restricción "check" especifica los valores que acepta un campo, evitando que se ingresen
valores inapropiados.
La sintaxis básica es la siguiente:
alter table NOMBRETABLA
add constraint NOMBRECONSTRAINT
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).
Los campos correspondientes a los precios (minorista y mayorista) se definen de tipo
decimal(5,2), es decir, aceptan valores entre -999.99 y 999.99. Podemos controlar que no se
ingresen valores negativos para dichos campos agregando una restricción "check":
alter table libros
add constraint CK_libros_precio_positivo
check (preciomin>=0 and preciomay>=0);
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.
Si la tabla contiene registros que no cumplen con la restricción que se va a establecer, la
restricción no se puede establecer, hasta que todos los registros cumplan con dicha restricción.
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:
alter table libros
add constraint CK_libros_preciominmay
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.
Si un campo permite valores nulos, "null" es un valor aceptado aunque no esté incluido en la
condición de restricción.
36 - Restricción check
Primer problema:
Una empresa tiene registrados datos de sus empleados en una tabla llamada
"empleados".
1- Créela con la siguiente estructura:
create table empleados (
documento varchar(8),
nombre varchar(30),
fechanacimiento date,
cantidadhijos smallint,
seccion varchar(20),
sueldo decimal(6,2)
);
2- Agregue una restricción "check" para asegurarse que no se ingresen valores
negativos para el
sueldo
3- Ingrese algunos registros válidos:
insert into empleados values ('22222222','Alberto
Lopez','1965/10/05',1,'Sistemas',1000);
insert into empleados values ('33333333','Beatriz
Garcia','1972/08/15',2,'Administracion',3000);
insert into empleados values ('34444444','Carlos
Caseres','1980/10/05',0,'Contaduría',6000);
4- Intente agregar otra restricción "check" al campo sueldo para asegurar que
ninguno supere el
valor 5000
La sentencia no se ejecuta porque hay un sueldo que no cumple la restricción.
5- Elimine el registro infractor y vuelva a crear la restricción
alter table empleados
add constraint CK_empleados_sueldo_maximo
check (sueldo<=5000);
6- Establezca una restricción para controlar que la fecha de nacimiento que se
ingresa no supere la
fecha actual
7- Establezca una restricción "check" para "cantidadhijos" que permita
solamente valores entre 0 y
15.
8- Vea todas las restricciones de la tabla (5 filas)
9- Intente agregar un registro que vaya contra alguna de las restricciones al
campo "sueldo".
Mensaje de error porque se infringe la restricción
"CK_empleados_sueldo_positivo".
10- Intente agregar un registro con fecha de nacimiento futura.
Mensaje de error.
11- Intente modificar un registro colocando en "cantidadhijos" el valor "21".
Mensaje de error.
Ver solución
Segundo problema:
Una playa de estacionamiento almacena los datos de los vehículos que ingresan
en la tabla llamada
"vehiculos".
1- Cree la tabla:
create table vehiculos(
numero serial,
patente char(6),
tipo char(4),
fechahoraentrada timestamp,
fechahorasalida timestamp,
primary key(numero)
);
2- Ingresamos algunos registros:
insert into vehiculos (patente,tipo,fechahoraentrada,fechahorasalida)
values('AIC124','auto','2007/01/17 8:05','2007/01/17 12:30');
insert into vehiculos (patente,tipo,fechahoraentrada,fechahorasalida)
values('CAA258','auto','2007/01/17 8:10',null);
insert into vehiculos (patente,tipo,fechahoraentrada,fechahorasalida)
values('DSE367','moto','2007/01/17 8:30','2007/01/17 18:00');
3- Agregue una restricción "check" para asegurarse que la fecha de entrada a
la playa no sea
posterior a la fecha y hora actual
4- Agregue otra restricción "check" al campo "fechahoraentrada" que establezca
que sus valores no
sean posteriores a "fechahorasalida"
5- Intente ingresar un valor que no cumpla con la primera restricción
establecida en el campo
"fechahoraentrada"
6- Intente modificar un registro para que la salida sea anterior a la entrada
Mensaje de error.
7- Vea todas las restricciones para la tabla "vehiculos":
select *
from information_schema.table_constraints
where table_name = 'empleados';
8- Vea todos los registros
Ver solución
37 - Restricción primary key
Hemos visto la restricción que se aplica a los campos con "check".
Ahora veremos las restricciones que se aplican a las tablas, que aseguran valores únicos para
cada registro.
Hay 2 tipos: 1) primary key y 2) unique.
Anteriormente, para establecer una clave primaria para una tabla empleábamos la siguiente
sintaxis al crear la tabla, por ejemplo:
create table libros(
codigo int not null,
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:
alter table NOMBRETABLA
add constraint NOMBRECONSTRAINT
primary key (CAMPO,...);
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:
alter table libros
add constraint PK_libros_codigo
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.
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
where table_name = 'libros';
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".
37 - Restricción primary key
Primer problema:
Una empresa tiene registrados datos de sus empleados en una tabla llamada
"empleados".
1- Créela con la siguiente estructura:
create table empleados (
documento varchar(8) not null,
nombre varchar(30),
seccion varchar(20)
);
2- Ingrese algunos registros, dos de ellos con el mismo número de documento:
insert into empleados
values ('22222222','Alberto Lopez','Sistemas');
insert into empleados
values ('23333333','Beatriz Garcia','Administracion');
insert into empleados
values ('23333333','Carlos Fuentes','Administracion');
3- Intente establecer una restricción "primary key" para la tabla para que el
documento no se repita
ni admita valores nulos
No lo permite porque la tabla contiene datos que no cumplen con la
restricción, debemos eliminar (o
modificar) el registro que tiene documento duplicado:
4- Establezca la restricción "primary key" del punto 3
5- Intente actualizar un documento para que se repita.
No lo permite porque va contra la restricción.
6-Intente establecer otra restricción "primary key" con el campo "nombre".
No lo permite, sólo puede haber una restricción "primary key" por tabla.
7- Intente ingresar un registro con valor nulo para el documento.
No lo permite porque la restricción no admite valores nulos.
8- Vea las restricciones de la tabla empleados (2 filas)
Ver solución
Segundo problema:
Una empresa de remises tiene registrada la información de sus vehículos en una
tabla llamada
"remis".
1- Cree la tabla con la siguiente estructura:
create table remis(
numero serial,
patente char(6),
marca varchar(15),
modelo char(4)
);
2- Ingrese algunos registros sin repetir patente:
insert into remis (patente,marca,modelo)values('ABC123','Renault 12','1990');
insert into remis (patente,marca,modelo)values('DEF456','Fiat Duna','1995');
3- Definir una restricción "primary key" para el campo "patente".
4- Establezca una restricción "primary key" para el campo "numero".
(No lo permite ya que hay una "primary key")
5- Vea la información de las restricciones
Ver solución
38 - Restricción unique
Hemos visto que las restricciones aplicadas a tablas aseguran valores únicos para cada registro.
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).
La sintaxis general es la siguiente:
alter table NOMBRETABLA
add constraint NOMBRERESTRICCION
unique (CAMPO);
Ejemplo:
alter table alumnos
add constraint UQ_alumnos_documento
unique (documento);
En el ejemplo anterior se agrega una restricción "unique" sobre el campo "documento" de la
tabla "alumnos", esto asegura que no se pueda ingresar un documento si ya existe. Esta
restricción permite valores nulos, asi que si se ingresa el valor "null" para el campo
"documento", se acepta.
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.
PostgreSQL controla la entrada de datos en inserciones y actualizaciones evitando que se
ingresen valores duplicados.
38 - Restricción unique
Primer problema:
Una empresa de remises tiene registrada la información de sus vehículos en una
tabla llamada
"remis".
1- Cree la tabla con la siguiente estructura:
create table remis(
numero serial,
patente char(6),
marca varchar(15),
modelo char(4)
);
2- Ingrese algunos registros, 2 de ellos con patente repetida y alguno con
patente nula:
insert into remis(patente,marca,modelo) values('ABC123','Renault
clio','1990');
insert into remis(patente,marca,modelo) values('DEF456','Peugeot
504','1995');
insert into remis(patente,marca,modelo) values('DEF456','Fiat Duna','1998');
insert into remis(patente,marca,modelo) values('GHI789','Fiat Duna','1995');
insert into remis(patente,marca,modelo) values(null,'Fiat Duna','1995');
3- Intente agregar una restricción "unique" para asegurarse que la patente del
remis no tomará
valores repetidos.
No se puede porque hay valores duplicados.
4- Elimine el registro con patente duplicada y establezca la restricción.
Note que hay 1 registro con valor nulo en "patente".
5- Intente ingresar un registro con patente repetida (no lo permite)
6- Ingresar un registro con valor nulo para el campo "patente".
Lo permite.
7- Muestre la información de las restricciones
Ver solución
39 - Eliminar restricciones (alter table - drop
constraint)
Para eliminar una restricción, la sintaxis básica es la siguiente:
alter table NOMBRETABLA
drop constraint NOMBRERESTRICCION;
Para eliminar la restricción "CK_libros_precio_positivo" de la tabla libros tipeamos:
alter table libros
drop constraint CK_libros_precio_positivo;
Cuando eliminamos una tabla, todas las restricciones que fueron establecidas en ella, se eliminan
también.
39 - Eliminar restricciones (alter table - drop
constraint)
Primer problema:
Una playa de estacionamiento almacena cada día los datos de los vehículos que
ingresan en la tabla
llamada "vehiculos".
1- Cree la tabla:
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada timestamp not null,
horasalida timestamp
);
2- Agregue una restricción "primary key" que incluya los campos "patente" y
"horallegada"
3- Ingrese un vehículo:
insert into vehiculos values('SDR456','a','2005/10/10 10:10',null);
4- Intente ingresar un registro repitiendo la clave primaria:
insert into vehiculos values('SDR456','m','2005/10/10 10:10',null);
No se permite.
5- Ingrese un registro repitiendo la patente pero no la hora de llegada:
insert into vehiculos values('SDR456','m','2005/10/10 12:10',null);
6- Ingrese un registro repitiendo la hora de llegada pero no la patente:
insert into vehiculos values('SDR111','m','2005/10/10 10:10',null);
7- Vea todas las restricciones para la tabla "vehiculos"
8- Elimine la restricción "primary key".
9- Vea si se han eliminado
Ver solución
40 - Indice de una tabla.
Para facilitar la obtención de información de una tabla se utilizan índices.
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.
Una tabla se indexa por un campo (o varios).
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.
El objetivo de un indice es acelerar la recuperación de información.
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.
Los índices se usan para varias operaciones:
- para buscar registros rápidamente.
- para recuperar registros de otras tablas empleando "join".
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.
Hay distintos tipos de índices, a saber:
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.
En las siguientes lecciones aprenderemos sobre cada uno de ellos.
Los nombres de índices aceptan todos los caracteres.
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.
41 - Típos de índices (create y drop)
Dijimos que hay 3 tipos de índices:
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.
Vamos a trabajar con nuestra tabla "libros".
create table libros(
codigo int not null,
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:
create index I_libros_editorial on libros(editorial);
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.
Crearemos un índice único por los campos titulo y editorial:
create unique index I_libros_tituloeditorial on libros(titulo,editorial);
Para eliminar un índice usamos "drop index". Ejemplo:
drop index I_libros_editorial;
drop index I_libros_tituloeditorial;
Se elimina un índice con "drop index" seguido de su nombre.
Podemos eliminar los índices creados, pero no el creado automáticamente con la clave primaria.
41 - Típos de índices (create y drop)
Primer problema:
1- Cree la tabla con la siguiente estructura:
create table agenda(
apellido varchar(30),
nombre varchar(20) not null,
domicilio varchar(30),
telefono varchar(11),
mail varchar(30),
);
2- Ingrese los siguientes registros:
insert into agenda values('Perez','Juan','Sarmiento
345','4334455','juancito@[Link]');
insert into agenda values('Garcia','Ana','Urquiza
367','4226677','anamariagarcia@[Link]');
insert into agenda values('Lopez','Juan','Avellaneda
900',null,'juancitoLopez@[Link]');
insert into agenda values('Juarez','Mariana','Sucre
123','0525657687','marianaJuarez2@[Link]');
insert into agenda values('Molinari','Lucia','Peru
1254','4590987','molinarilucia@[Link]');
insert into agenda values('Ferreyra','Patricia','Colon 1534','4585858',null);
insert into agenda values('Perez','Susana','San Martin 333',null,null);
insert into agenda values('Perez','Luis','Urquiza
444','0354545256','perezluisalberto@[Link]');
insert into agenda values('Lopez','Maria','Salta
314',null,'lopezmariayo@[Link]');
3- Cree un índice común por el campo apellido.
4- Cree un índice único por el mail.
5- Borre los dos índices.
Ver solución
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).
Si el limit supera la cantidad de registros de la tabla, se limita hasta el último registro.
Ejemplo:
select * from libros limit 4 offset 0;
Muestra los primeros 4 registros, 0,1,2 y 3.
Si tipeamos:
select * from libros limit 4 offset 5;
recuperamos 4 registros, desde el 5 al 8.
Si se coloca solo la cláusula limit retorna tantos registros como el valor indicado, comenzando
desde 0. Ejemplo:
select * from libros limit 8;
Muestra los primeros 8 registros.
Es conveniente utilizar la cláusula order by cuando utilizamos limit y offset, por ejemplo:
select * from libros order by codigo limit 8;
42 - Cláusulas limit y offset del comando
select
Primer problema:
Trabaje con la tabla "agenda" que registra la información referente a sus
amigos.
1- Cree la tabla con la siguiente estructura:
create table agenda(
apellido varchar(30),
nombre varchar(20) not null,
domicilio varchar(30),
telefono varchar(11),
mail varchar(30)
);
2- Ingrese 5 registros.
3- Realice una consulta limitando la salida a sólo 3 registros.
4- Muestre los registros desde el 2 al 4.
5- Muestre 4 registros a partir del 2 ordenado por apellido.
Ver solución
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:
create table libros(
codigo serial,
titulo varchar(40) not null,
autor varchar(30) not null default 'Desconocido',
codigoeditorial smallint not null,
precio decimal(5,2),
primary key (codigo)
);
create table editoriales(
codigo serial,
nombre varchar(20) not null,
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".
Al recuperar los datos de los libros con la siguiente instrucción:
select * from libros;
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:
select * from libros
join editoriales
on [Link]=[Link];
Resumiendo: si distribuimos la información en varias tablas evitamos la redundancia de datos y
ocupamos menos espacio físico en el disco. 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.
Hay tres tipos de combinaciones. En los siguientes capítulos explicamos cada una de ellas.
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.
Hay tres tipos de combinaciones:
1. combinaciones internas (inner join o join),
2. combinaciones externas y
3. 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.
La sintaxis básica es la siguiente:
select CAMPOS
from TABLA1
join TABLA2
on CONDICIONdeCOMBINACION;
Ejemplo:
select * from libros
join editoriales
on codigoeditorial=[Link];
Analicemos la consulta anterior.
- especificamos los campos que aparecerán en el resultado en la lista de selección;
- indicamos el nombre de la tabla luego del "from" ("libros");
- 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,
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.
Para simplificar la sentencia podemos usar un alias para cada tabla:
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.
44 - Combinación interna (inner join)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes",
también tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Créelas con las siguientes estructuras:
create table clientes (
codigo serial,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia smallint not null,
primary key(codigo)
);
create table provincias(
codigo serial,
nombre varchar(20),
primary key (codigo)
);
2- Ingrese algunos registros para ambas tablas:
insert into provincias (nombre) values('Cordoba');
insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Lopez Marcos','Colon 111','Córdoba',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Pereyra Lucas','San Martin 555','Cruz del Eje',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Torres Fabiola','Alem 777','Ibera',3);
3- Obtenga los datos de ambas tablas, usando alias
4- Obtenga la misma información anterior pero ordenada por nombre de
provincia.
5- Recupere los clientes de la provincia "Santa Fe" (2 registros devueltos)
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes. Almacena la información en una
tabla llamada
"inscriptos" que incluye el documento, el nombre, el deporte y si la matricula
esta paga o no y una
tabla llamada "inasistencias" que incluye el documento, el deporte y la fecha
de la inasistencia.
1 - Cree las tablas:
create table inscriptos(
nombre varchar(30),
documento char(8),
deporte varchar(15),
matricula char(1), --'s'=paga 'n'=impaga
primary key(documento,deporte)
);
create table inasistencias(
documento char(8),
deporte varchar(15),
fecha date
);
2- Ingrese algunos registros para ambas tablas:
insert into inscriptos values('Juan Perez','22222222','tenis','s');
insert into inscriptos values('Maria Lopez','23333333','tenis','s');
insert into inscriptos values('Agustin Juarez','24444444','tenis','n');
insert into inscriptos values('Marta Garcia','25555555','natacion','s');
insert into inscriptos values('Juan Perez','22222222','natacion','s');
insert into inscriptos values('Maria Lopez','23333333','natacion','n');
insert into inasistencias values('22222222','tenis','2006-12-01');
insert into inasistencias values('22222222','tenis','2006-12-08');
insert into inasistencias values('23333333','tenis','2006-12-01');
insert into inasistencias values('24444444','tenis','2006-12-08');
insert into inasistencias values('22222222','natacion','2006-12-02');
insert into inasistencias values('23333333','natacion','2006-12-02');
3- Muestre el nombre, el deporte y las fechas de inasistencias, ordenado por
nombre y deporte.
Note que la condición es compuesta porque para identificar los registros de la
tabla "inasistencias"
necesitamos ambos campos.
4- Obtenga el nombre, deporte y las fechas de inasistencias de un determinado
inscripto en un
determinado deporte (3 registros)
5- Obtenga el nombre, deporte y las fechas de inasistencias de todos los
inscriptos que pagaron la
matrícula(4 registros)
Ver solución
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.
Si queremos saber qué registros de una tabla NO encuentran correspondencia en la otra, es decir,
no existe valor coincidente en la segunda, necesitamos otro tipo de combinación, "outer join"
(combinación externa).
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.
Vamos a estudiar las primeras.
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".
En el siguiente ejemplo solicitamos el título y nombre de la editorial de los libros:
select titulo,nombre
from editoriales as e
left join 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 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
from TABLAIZQUIERDA
left join TABLADERECHA
on CONDICION;
En el siguiente ejemplo solicitamos el título y el nombre la editorial, la sentencia es similar a la
anterior, la diferencia está en el orden de las tablas:
select titulo,nombre
from libros as l
left join editoriales as e
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
left join libros as l
on [Link]=codigoeditorial
where codigoeditorial is not null;
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
left join libros as l
on [Link]=codigoeditorial
where codigoeditorial is null;
45 - Combinación externa izquierda (left
join)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes",
también tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Cree las tablas:
create table clientes (
codigo serial,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia smallint not null,
primary key(codigo)
);
create table provincias(
codigo serial,
nombre varchar(20),
primary key (codigo)
);
2- Ingrese algunos registros para ambas tablas:
insert into provincias (nombre) values('Cordoba');
insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Lopez Marcos','Colon 111','Córdoba',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Torres Fabiola','Alem 777','La Plata',4);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Garcia Luis','Sucre 475','Santa Rosa',5);
3- Muestre todos los datos de los clientes, incluido el nombre de la provincia
4- Realice la misma consulta anterior pero alterando el orden de las tablas
5- Muestre solamente los clientes de las provincias que existen en
"provincias" (5 registros)
6- Muestre todos los clientes cuyo código de provincia NO existe en
"provincias" ordenados por
nombre del cliente (2 registros)
7- Obtenga todos los datos de los clientes de "Cordoba" (3 registros)
Ver solución
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.
En el siguiente ejemplo solicitamos el título y nombre de la editorial de los libros empleando un
"right join":
select titulo,nombre
from libros as l
right join 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 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
left join libros as l
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:
select CAMPOS
from TABLAIZQUIERDA
right join TABLADERECHA
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
right join editoriales as e
on [Link]=codigoeditorial
where codigoeditorial is not null;
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
where codigoeditorial is null;
46 - Combinación externa derecha (right
join)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes",
también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1-Cree las tablas:
create table clientes (
codigo serial,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia smallint not null,
primary key(codigo)
);
create table provincias(
codigo serial,
nombre varchar(20),
primary key (codigo)
);
2- Ingrese algunos registros para ambas tablas:
insert into provincias (nombre) values('Cordoba');
insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Lopez Marcos','Colon 111','Córdoba',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Torres Fabiola','Alem 777','La Plata',4);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values ('Garcia Luis','Sucre 475','Santa Rosa',5);
3- Muestre todos los datos de los clientes, incluido el nombre de la provincia
empleando un "right
join".
4- Obtenga la misma salida que la consulta anterior pero empleando un "left
join".
5- Empleando un "right join", muestre solamente los clientes de las provincias
que existen en
"provincias" (5 registros)
6- Muestre todos los clientes cuyo código de provincia NO existe en
"provincias" ordenados por
ciudad (2 registros)
Ver solución
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
full join libros as l
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".
47 - Combinación externa completa (full join)
Primer problema:
Un club dicta clases de distintos deportes. Almacena la información en una
tabla llamada "deportes"
en la cual incluye el nombre del deporte y el nombre del profesor y en otra
tabla llamada
"inscriptos" que incluye el documento del socio que se inscribe, el deporte y
si la matricula está
paga o no.
1- Cree las tablas:
create table deportes(
codigo serial,
nombre varchar(30),
profesor varchar(30),
primary key (codigo)
);
create table inscriptos(
documento char(8),
codigodeporte smallint not null,
matricula char(1) --'s'=paga 'n'=impaga
);
2- Ingrese algunos registros para ambas tablas:
insert into deportes(nombre,profesor) values('tenis','Marcelo Roca');
insert into deportes(nombre,profesor) values('natacion','Marta Torres');
insert into deportes(nombre,profesor) values('basquet','Luis Garcia');
insert into deportes(nombre,profesor) values('futbol','Marcelo Roca');
insert into inscriptos values('22222222',3,'s');
insert into inscriptos values('23333333',3,'s');
insert into inscriptos values('24444444',3,'n');
insert into inscriptos values('22222222',2,'s');
insert into inscriptos values('23333333',2,'s');
insert into inscriptos values('22222222',4,'n');
insert into inscriptos values('22222222',5,'n');
3- Muestre todos la información de la tabla "inscriptos", y consulte la tabla
"deportes" para
obtener el nombre de cada deporte (6 registros)
4- Empleando un "left join" con "deportes" obtenga todos los datos de los
inscriptos (7 registros)
5- Obtenga la misma salida anterior empleando un "rigth join".
6- Muestre los deportes para los cuales no hay inscriptos, empleando un "left
join" (1 registro)
7- Muestre los documentos de los inscriptos a deportes que no existen en la
tabla "deportes" (1
registro)
8- Emplee un "full join" para obtener todos los datos de ambas tablas,
incluyendo las inscripciones
a deportes inexistentes en "deportes" y los deportes que no tienen inscriptos
(8 registros)
Ver solución
48 - Combinaciones cruzadas (cross join)
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.
La sintaxis básica es ésta:
select CAMPOS
from TABLA1
cross join TABLA2;
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":
select [Link] as platoprincipal, [Link] as postre
from comidas as c
cross join postres as p;
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.
48 - Combinaciones cruzadas (cross join)
Primer problema:
Una agencia matrimonial almacena la información de sus clientes de sexo
femenino en una tabla
llamada "mujeres" y en otra la de sus clientes de sexo masculino llamada
"varones".
1- Cree las tablas:
create table mujeres(
nombre varchar(30),
domicilio varchar(30),
edad int
);
create table varones(
nombre varchar(30),
domicilio varchar(30),
edad int
);
2- Ingrese los siguientes registros:
insert into mujeres values('Maria Lopez','Colon 123',45);
insert into mujeres values('Liliana Garcia','Sucre 456',35);
insert into mujeres values('Susana Lopez','Avellaneda 98',41);
insert into varones values('Juan Torres','Sarmiento 755',44);
insert into varones values('Marcelo Oliva','San Martin 874',56);
insert into varones values('Federico Pereyra','Colon 234',38);
insert into varones values('Juan Garcia','Peru 333',50);
3- La agencia necesita la combinación de todas las personas de sexo femenino
con las de sexo
masculino. Use un "cross join" (12 registros)
4- Realice la misma combinación pero considerando solamente las personas
mayores de 40 años (6
registros)
5- Forme las parejas pero teniendo en cuenta que no tengan una diferencia
superior a 10 años (8
registros)
Ver solución
Segundo problema:
Una empresa de seguridad almacena los datos de sus guardias de seguridad en
una tabla llamada
"guardias". también almacena los distintos sitios que solicitaron sus
servicios en una tabla llamada "tareas".
1- Cree las tablas:
create table guardias(
documento char(8),
nombre varchar(30),
sexo char(1), /* 'f' o 'm' */
domicilio varchar(30),
primary key (documento)
);
create table tareas(
codigo serial,
domicilio varchar(30),
descripcion varchar(30),
horario char(2), /* 'AM' o 'PM'*/
primary key (codigo)
);
2- Ingrese los siguientes registros:
insert into guardias values('22333444','Juan Perez','m','Colon 123');
insert into guardias values('24333444','Alberto Torres','m','San Martin
567');
insert into guardias values('25333444','Luis Ferreyra','m','Chacabuco 235');
insert into guardias values('23333444','Lorena Viale','f','Sarmiento 988');
insert into guardias values('26333444','Irma Gonzalez','f','Mariano Moreno
111');
insert into tareas(domicilio,descripcion,horario)
values('Colon 1111','vigilancia exterior','AM');
insert into tareas(domicilio,descripcion,horario)
values('Urquiza 234','vigilancia exterior','PM');
insert into tareas(domicilio,descripcion,horario)
values('Peru 345','vigilancia interior','AM');
insert into tareas(domicilio,descripcion,horario)
values('Avellaneda 890','vigilancia interior','PM');
3- La empresa quiere que todos sus empleados realicen todas las tareas.
Realice una "cross join" (20 registros)
4- En este caso, la empresa quiere que todos los guardias de sexo femenino
realicen las tareas de
"vigilancia interior" y los de sexo masculino de "vigilancia exterior".
Realice una "cross join"
con un "where" que controle tal requisito (10 registros)
Ver solución
49 - Autocombinación
Dijimos que es posible combinar una tabla consigo misma.
Un pequeño restaurante tiene almacenadas sus comidas en una tabla llamada "comidas" que
consta de los siguientes campos:
- nombre varchar(20),
- precio decimal (4,2) y
- 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:
select [Link] as platoprincipal,
[Link] as postre,
[Link]+[Link] as total
from comidas as c1
cross join comidas as c2;
En la consulta anterior aparecen filas duplicadas, para evitarlo debemos emplear un "where":
select [Link] as platoprincipal,
[Link] as postre,
[Link]+[Link] as total
from comidas as c1
cross join comidas as c2
where [Link]='plato' and
[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".
También se puede realizar una autocombinación con "join":
select [Link] as platoprincipal,
[Link] as postre,
[Link]+[Link] as total
from comidas as c1
join comidas as c2
on [Link]<>[Link]
where [Link]='plato' and
[Link]='postre';
Para que no aparezcan filas duplicadas se agrega un "where".
49 - Autocombinación
Primer problema:
Una agencia matrimonial almacena la información de sus clientes en una tabla
llamada "clientes".
1- Cree la tabla:
create table clientes(
nombre varchar(30),
sexo char(1),--'f'=femenino, 'm'=masculino
edad int,
domicilio varchar(30)
);
2- Ingrese los siguientes registros:
insert into clientes values('Maria Lopez','f',45,'Colon 123');
insert into clientes values('Liliana Garcia','f',35,'Sucre 456');
insert into clientes values('Susana Lopez','f',41,'Avellaneda 98');
insert into clientes values('Juan Torres','m',44,'Sarmiento 755');
insert into clientes values('Marcelo Oliva','m',56,'San Martin 874');
insert into clientes values('Federico Pereyra','m',38,'Colon 234');
insert into clientes values('Juan Garcia','m',50,'Peru 333');
3- La agencia necesita la combinación de todas las personas de sexo femenino
con las de sexo
masculino. Use un "cross join" (12 registros)
4- Obtenga la misma salida anterior pero realizando un "join".
5- Realice la misma autocombinación que el punto 3 pero agregue la condición
que las parejas no
tengan una diferencia superior a 5 años (5 registros)
Ver solución
Segundo problema:
Varios clubes de barrio se organizaron para realizar campeonatos entre ellos.
La tabla llamada
"equipos" guarda la información de los distintos equipos que jugarán.
1- Cree la tabla:
create table equipos(
nombre varchar(30),
barrio varchar(20),
domicilio varchar(30),
entrenador varchar(30)
);
2- Ingrese los siguientes registros:
insert into equipos values('Los tigres','Gral. Paz','Sarmiento 234','Juan
Lopez');
insert into equipos values('Los leones','Centro','Colon 123','Gustavo
Fuentes');
insert into equipos values('Campeones','Pueyrredon','Guemes 346','Carlos
Moreno');
insert into equipos values('Cebollitas','Alberdi','Colon 1234','Luis
Duarte');
3- Cada equipo jugará con todos los demás 2 veces, una vez en cada sede.
Realice un "cross join"
para combinar los equipos teniendo en cuenta que un equipo no juega consigo
mismo (12 registros)
4- Obtenga el mismo resultado empleando un "join".
5- Realice un "cross join" para combinar los equipos para que cada equipo
juegue con cada uno de
los otros una sola vez (6 registros)
Ver solución
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:
select nombre as editorial,
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:
select nombre as editorial,
max(precio) as mayorprecio
from editoriales as e
left join libros as l
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.
50 - Combinaciones y funciones de
agrupamiento
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos
datos de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus
productos y en otra tabla llamada "ciudades" los nombres de las ciudades.
1- Cree las tablas:
create table visitantes(
nombre varchar(30),
edad smallint,
sexo char(1) default 'f',
domicilio varchar(30),
codigociudad smallint not null,
mail varchar(30),
montocompra decimal (6,2)
);
create table ciudades(
codigo serial,
nombre varchar(20),
primary key(codigo)
);
2- Ingrese algunos registros:
insert into ciudades(nombre) values('Cordoba');
insert into ciudades(nombre) values('Carlos Paz');
insert into ciudades(nombre) values('La Falda');
insert into ciudades(nombre) values('Cruz del Eje');
insert into visitantes values
('Susana Molina', 35,'f','Colon 123', 1, null,59.80);
insert into visitantes values
('Marcos Torres', 29,'m','Sucre 56', 1, 'marcostorres@[Link]',150.50);
insert into visitantes values
('Mariana Juarez', 45,'f','San Martin 111',2,null,23.90);
insert into visitantes values
('Fabian Perez',36,'m','Avellaneda 213',3,'fabianperez@[Link]',0);
insert into visitantes values
('Alejandra Garcia',28,'f',null,2,null,280.50);
insert into visitantes values
('Gaston Perez',29,'m',null,5,'gastonperez1@[Link]',95.40);
insert into visitantes values
('Mariana Juarez',33,'f',null,2,null,90);
3- Cuente la cantidad de visitas por ciudad mostrando el nombre de la ciudad
(3 filas)
4- Muestre el promedio de gastos de las visitas agrupados por ciudad y sexo (4
filas)
5- Muestre la cantidad de visitantes con mail, agrupados por ciudad (3 filas)
6- Obtenga el monto de compra más alto de cada ciudad (3 filas)
Ver solución
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.
Podemos combinar varios tipos de join en una misma sentencia:
select titulo,[Link],[Link]
from autores as a
right join libros as l
on codigoautor=[Link]
left join editoriales as e on codigoeditorial=[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.
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".
51 - Combinación de más de dos tablas
Primer problema:
Un club dicta clases de distintos deportes. En una tabla llamada "socios"
guarda los datos de los
socios, en una tabla llamada "deportes" la información referente a los
diferentes deportes que se
dictan y en una tabla denominada "inscriptos", las inscripciones de los socios
a los distintos
deportes.
Un socio puede inscribirse en varios deportes el mismo año. Un socio no puede
inscribirse en el
mismo deporte el mismo año. Distintos socios se inscriben en un mismo deporte
en el mismo año.
1- Cree las tablas con las siguientes estructuras:
create table socios(
documento char(8) not null,
nombre varchar(30),
domicilio varchar(30),
primary key(documento)
);
create table deportes(
codigo serial,
nombre varchar(20),
profesor varchar(15),
primary key(codigo)
);
create table inscriptos(
documento char(8) not null,
codigodeporte smallint not null,
anio char(4),
matricula char(1),--'s'=paga, 'n'=impaga
primary key(documento,codigodeporte,anio)
);
2- Ingrese algunos registros en "socios":
insert into socios values('22222222','Ana Acosta','Avellaneda 111');
insert into socios values('23333333','Betina Bustos','Bulnes 222');
insert into socios values('24444444','Carlos Castro','Caseros 333');
insert into socios values('25555555','Daniel Duarte','Dinamarca 44');
3- Ingrese algunos registros en "deportes":
insert into deportes(nombre,profesor) values('basquet','Juan Juarez');
insert into deportes(nombre,profesor) values('futbol','Pedro Perez');
insert into deportes(nombre,profesor) values('natacion','Marina Morales');
insert into deportes(nombre,profesor) values('tenis','Marina Morales');
4- Inscriba a varios socios en el mismo deporte en el mismo año:
insert into inscriptos values ('22222222',3,'2006','s');
insert into inscriptos values ('23333333',3,'2006','s');
insert into inscriptos values ('24444444',3,'2006','n');
5- Inscriba a un mismo socio en el mismo deporte en distintos años:
insert into inscriptos values ('22222222',3,'2005','s');
insert into inscriptos values ('22222222',3,'2007','n');
6- Inscriba a un mismo socio en distintos deportes el mismo año:
insert into inscriptos values ('24444444',1,'2006','s');
insert into inscriptos values ('24444444',2,'2006','s');
7- Ingrese una inscripción con un código de deporte inexistente y un documento
de socio que no
exista en "socios":
insert into inscriptos values ('26666666',0,'2006','s');
8- Muestre el nombre del socio, el nombre del deporte en que se inscribió y el
año empleando
diferentes tipos de join.
9- Muestre todos los datos de las inscripciones (excepto los códigos)
incluyendo aquellas
inscripciones cuyo código de deporte no existe en "deportes" y cuyo documento
de socio no se
encuentra en "socios".
10- Muestre todas las inscripciones del socio con documento "22222222".
Ver solución
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:
libros: codigo (clave primaria), titulo, autor, codigoeditorial, precio y
editoriales: codigo (clave primaria), nombre.
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.
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":
alter table NOMBRETABLA1
add constraint NOMBRERESTRICCION
foreign key (CAMPOCLAVEFORANEA)
references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA);
Analicémosla:
- NOMBRETABLA1 referencia el nombre de la tabla a la cual le aplicamos la restricción,
- NOMBRERESTRICCION es el nombre que le damos a la misma,
- 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,
- luego de "references" indicamos el nombre de la tabla referenciada y el campo que es clave
primaria en la misma, a la cual hace referencia la clave foránea. La tabla referenciada debe tener
definida una restricción "primary key" o "unique"; si no la tiene, aparece un mensaje de error.
Para agregar una restricción "foreign key" al campo "codigoeditorial" de "libros", tipeamos:
alter table libros
add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales(codigo);
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).
Actúa en eliminaciones y actualizaciones. Si intentamos eliminar un registro o modificar un
valor de clave primaria de una tabla si una clave foránea hace referencia a dicho registro,
PostgreSQL no lo permite. Por ejemplo, si intentamos eliminar una editorial a la que se hace
referencia en "libros", aparece un mensaje de error.
Esta restricción (a diferencia de "primary key" y "unique") no crea índice automáticamente.
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".
Una tabla puede tener varias restricciones "foreign key".
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.
53 - Restricciones (foreign key)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes",
también tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Cree las tablas "clientes" y "provincias":
create table clientes (
codigo serial,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia smallint,
primary key(codigo)
);
create table provincias(
codigo serial,
nombre varchar(20),
primary key(codigo)
);
En este ejemplo, el campo "codigoprovincia" de "clientes" es una clave
foránea, se emplea para
enlazar la tabla "clientes" con "provincias".
2- Intente agregar una restricción "foreign key" a la tabla "clientes" que
haga referencia al campo
"codigo" de "provincias" (No se puede porque "provincias" no tiene restricción
"primary key" "unique")
3- Establezca una restricción "primary key" al campo "codigo" de "provincias"
4- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values('Perez Juan','San Martin 123','Carlos Paz',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values('Acosta Ana','Avellaneda 333','Posadas',3);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values('Luisa Lopez','Juarez 555','La Plata',6);
5- Intente agregar la restricción "foreign key" del punto 2 a la tabla
"clientes"
No se puede porque hay un registro en "clientes" cuyo valor de
"codigoprovincia" no existe en
"provincias".
6- Elimine el registro de "clientes" que no cumple con la restricción y
establezca la restricción
nuevamente.
7- Intente agregar un cliente con un código de provincia inexistente en
"provincias".
No se puede.
8- Intente eliminar el registro con código 3, de "provincias".
No se puede porque hay registros en "clientes" al cual hace referencia.
9- Elimine el registro con código "4" de "provincias".
Se permite porque en "clientes" ningún registro hace referencia a él.
10- Intente modificar el registro con código 1, de "provincias".
No se puede porque hay registros en "clientes" al cual hace referencia.
Ver solución
54 - Restricciones foreign key en la misma
tabla
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.
Veamos un ejemplo en el cual definimos esta restricción 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.
La estructura de la tabla es la siguiente:
create table afiliados(
numero serial,
documento char(8) not null,
nombre varchar(30),
afiliadotitular int,
primary key (documento),
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":
alter table afiliados
add constraint FK_afiliados_afiliadotitular
foreign key (afiliadotitular)
references afiliados (numero);
La sintaxis es la misma, excepto que la tabla se autoreferencia.
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.
Si intentamos eliminar un afiliado que es titular de otros afiliados, no se podrá hacer.
54 - Restricciones foreign key en la misma
tabla
Primer problema:
Una empresa registra los datos de sus clientes en una tabla llamada
"clientes". Dicha tabla contiene un campo
que hace referencia al cliente que lo recomendó denominado "referenciadopor".
Si un cliente
no ha sido referenciado por ningún otro cliente, tal campo almacena "null".
1- Creemos la tabla:
create table clientes(
codigo int,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
referenciadopor int,
primary key(codigo)
);
2- Ingresamos algunos registros:
insert into clientes values (50,'Juan Perez','Sucre 123','Cordoba',null);
insert into clientes values(90,'Marta Juarez','Colon 345','Carlos Paz',null);
insert into clientes values(110,'Fabian Torres','San Martin
987','Cordoba',50);
insert into clientes values(125,'Susana Garcia','Colon 122','Carlos Paz',90);
insert into clientes values(140,'Ana Herrero','Colon 890','Carlos Paz',9);
3- Intente agregar una restricción "foreign key" para evitar que en el campo
"referenciadopor" se
ingrese un valor de código de cliente que no exista.
No se permite porque existe un registro que no cumple con la restricción que
se intenta establecer.
4- Cambie el valor inválido de "referenciadopor" del registro que viola la
restricción por uno
válido.
5- Agregue la restricción "foreign key" que intentó agregar en el punto 3.
6- Intente agregar un registro que infrinja la restricción.
No lo permite.
7- Intente modificar el código de un cliente que está referenciado en
"referenciadopor".
No se puede.
8- Intente eliminar un cliente que sea referenciado por otro en
"referenciadopor".
No se puede.
9- Cambie el valor de código de un cliente que no referenció a nadie.
10- Elimine un cliente que no haya referenciado a otros.
Ver solución
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").
En el siguiente ejemplo creamos la tabla "libros" con la restricción respectiva:
create table editoriales(
codigo serial,
nombre varchar(20),
primary key (codigo)
);
create table libros(
codigo serial,
titulo varchar(40),
autor varchar(30),
codigoeditorial smallint references editoriales(codigo),
primary key(codigo)
);
En el ejemplo anterior creamos:
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.
56 - Restricciones foreign key (acciones)
Continuamos con la restricción "foreign key".
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.
- "cascade": indica que si eliminamos o actualizamos un valor de la clave primaria en la tabla
referenciada (TABLA2), los registros coincidentes en la tabla principal (TABLA1), también se
eliminen o modifiquen; es decir, si eliminamos o modificamos un valor de campo definido con
una restricción "primary key" o "unique", dicho cambio se extiende al valor de clave externa de
la otra tabla (integridad referencial en cascada).
- "set null": Establece con el valor null en el campo de la clave foránea.
- "set default": Establece el valor por defecto en el campo de la clave foránea.
La sintaxis completa para agregar esta restricción a una tabla es la siguiente:
alter table TABLA1
add constraint NOMBRERESTRICCION
foreign key (CAMPOCLAVEFORANEA)
references TABLA2(CAMPOCLAVEPRIMARIA)
on delete OPCION
on update OPCION;
Sintetizando, si al agregar una restricción foreign key:
- no se especifica acción para eliminaciones (o se especifica "no_action"), y se intenta eliminar
un registro de la tabla referenciada (editoriales) cuyo valor de clave primaria (codigo) existe en
la tabla principal (libros), la acción no se realiza.
- 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).
- no se especifica acción para actualizaciones (o se especifica "no_action"), y se intenta
modificar un valor de clave primaria (codigo) de la tabla referenciada (editoriales) que existe en
el campo clave foránea (codigoeditorial) de la tabla principal (libros), la acción no se realiza.
- se especifica "cascade" para actualizaciones ("on update cascade") y se modifica un valor de
clave primaria (codigo) de la tabla referenciada (editoriales) que existe en la tabla principal
(libros), PostgreSQL actualiza el registro de la tabla referenciada (editoriales) y todos los
registros coincidentes en la tabla principal (libros).
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:
alter table libros
add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales(codigo)
on update cascade
on delete cascade;
Si luego de establecer la restricción anterior, eliminamos una editorial de "editoriales" de las
cuales hay libros, se elimina dicha editorial y todos los libros de tal editorial. Y si modificamos
el valor de código de una editorial de "editoriales", se modifica en "editoriales" y todos los
valores iguales de "codigoeditorial" de libros también se modifican.
56 - Restricciones foreign key (acciones)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes",
también tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Cree las tablas "clientes" y "provincias":
create table clientes (
codigo serial,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia smallint,
primary key(codigo)
);
create table provincias(
codigo serial,
nombre varchar(20),
primary key(codigo)
);
3- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values('Perez Juan','San Martin 123','Carlos Paz',1);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
values('Acosta Ana','Avellaneda 333','Posadas',3);
3- Establezca una restricción "foreign key" especificando la acción "en
cascade" para
actualizaciones y "no_action" para eliminaciones.
4- Intente eliminar el registro con código 3, de "provincias".
No se puede porque hay registros en "clientes" al cual hace referencia y la
opción para
eliminaciones se estableció como "no action".
5- Modifique el registro con código 3, de "provincias".
6- Verifique que el cambio se realizó en cascada, es decir, que se modificó en
la tabla "provincias" y en "clientes":
select *from provincias;
select *from clientes;
7- Intente modificar la restricción "foreign key" para que permita eliminación
en cascada.
Mensaje de error, no se pueden modificar las restricciones.
8- Intente eliminar la tabla "provincias".
No se puede eliminar porque una restricción "foreign key" hace referencia a
ella.
Ver solución
57 - Unión
El operador "union" combina el resultado de dos o más instrucciones "select" en un único
resultado.
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".
Se deben especificar los nombres de los campos en la primera instrucción "select".
Puede emplear la cláusula "order by".
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:
select nombre, domicilio from alumnos
union
select nombre, domicilio from profesores;
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".
57 - Unión
Primer problema:
Un supermercado almacena en una tabla denominada "proveedores" los datos de
las compañías que le
proveen de mercaderías; en una tabla llamada "clientes", los datos de los
comercios que le compran y
en otra tabla "empleados" los datos de los empleados.
1- Cree las tablas:
create table proveedores(
codigo serial,
nombre varchar (30),
domicilio varchar(30),
primary key(codigo)
);
create table clientes(
codigo serial,
nombre varchar (30),
domicilio varchar(30),
primary key(codigo)
);
create table empleados(
documento char(8) not null,
nombre varchar(20),
apellido varchar(20),
domicilio varchar(30),
primary key(documento)
);
2- Ingrese algunos registros:
insert into proveedores(nombre,domicilio) values('Bebida cola','Colon 123');
insert into proveedores(nombre,domicilio) values('Carnes Unica','Caseros
222');
insert into proveedores(nombre,domicilio) values('Lacteos Blanca','San Martin
987');
insert into clientes(nombre,domicilio) values('Supermercado
Lopez','Avellaneda 34');
insert into clientes(nombre,domicilio) values('Almacen Anita','Colon 987');
insert into clientes(nombre,domicilio) values('Garcia Juan','Sucre 345');
insert into empleados values('23333333','Federico','Lopez','Colon 987');
insert into empleados values('28888888','Ana','Marquez','Sucre 333');
insert into empleados values('30111111','Luis','Perez','Caseros 956');
3- El supermercado quiere enviar una tarjeta de salutación a todos los
proveedores, clientes y
empleados y necesita el nombre y domicilio de todos ellos. Emplee el operador
"union" para obtener
dicha información de las tres tablas.
4- Agregue una columna con un literal para indicar si es un proveedor, un
cliente o un empleado y
ordene por dicha columna.
Ver solución
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.
Las subconsultas se DEBEN incluir entre paréntesis.
Puede haber subconsultas dentro de subconsultas.
Se pueden emplear subconsultas:
- 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).
Hay tres tipos básicos de subconsultas:
1. las que retornan un solo valor escalar que se utiliza con un operador de comparación o en lugar
de una expresión.
2. las que retornan una lista de valores, se combinan con "in", o los operadores "any", "some" y
"all".
3. los que testean la existencia con "exists".
Reglas a tener en cuenta al emplear subconsultas:
- la lista de selección de una subconsulta que va luego de un operador de comparación puede
incluir sólo una expresión o campo (excepto si se emplea "exists" y "in").
- 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".
- "distinct" no puede usarse con subconsultas que incluyan "group by".
- una subconsulta puede estar anidada dentro del "where" o "having" de una consulta externa o
dentro de otra subconsulta.
- si una tabla se nombra solamente en un subconsulta y no en la consulta externa, los campos no
serán incluidos en la salida (en la lista de selección de la consulta externa).
59 - Subconsultas como expresión
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
where CAMPO OPERADOR (SUBCONSULTA);
select CAMPO OPERADOR (SUBCONSULTA)
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,
precio-(select max(precio) from libros) as diferencia
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.
Queremos saber el título, autor y precio del libro más costoso:
select titulo,autor, precio
from libros
where precio=
(select max(precio) from libros);
Note que el campo del "where" de la consulta exterior es compatible con el valor retornado por la
expresión de la subconsulta.
Se pueden emplear en "select", "insert", "update" y "delete".
Para actualizar un registro empleando subconsulta la sintaxis básica es la siguiente:
update TABLA set CAMPO=NUEVOVALOR
where CAMPO= (SUBCONSULTA);
Para eliminar registros empleando subconsulta empleamos la siguiente sintaxis básica:
delete from TABLA
where CAMPO=(SUBCONSULTA);
Recuerde que la lista de selección de una subconsulta que va luego de un operador de
comparación puede incluir sólo una expresión o campo (excepto si se emplea "exists" o "in").
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".
59 - Subconsultas como expresión
Primer problema:
Un profesor almacena el documento, nombre y la nota final de cada alumno de su
clase en una tabla
llamada "alumnos".
1- Créela
create table alumnos(
documento char(8),
nombre varchar(30),
nota decimal(4,2),
primary key(documento)
);
2-Ingrese algunos registros:
insert into alumnos values('30111111','Ana Algarbe',5.1);
insert into alumnos values('30222222','Bernardo Bustamante',3.2);
insert into alumnos values('30333333','Carolina Conte',4.5);
insert into alumnos values('30444444','Diana Dominguez',9.7);
insert into alumnos values('30555555','Fabian Fuentes',8.5);
insert into alumnos values('30666666','Gaston Gonzalez',9.70);
3- Obtenga todos los datos de los alumnos con la nota más alta, empleando
subconsulta.
2 registros.
4- Realice la misma consulta anterior pero intente que la consulta interna
retorne, además del
máximo valor de precio, el título.
Mensaje de error, porque la lista de selección de una subconsulta que va luego
de un operador de
comparación puede incluir sólo un campo o expresión (excepto si se emplea
"exists" o "in").
5- Muestre los alumnos que tienen una nota menor al promedio, su nota, y la
diferencia con el
promedio.
3 registros.
6- Cambie la nota del alumno que tiene la menor nota por 4.
1 registro modificado.
7- Elimine los alumnos cuya nota es menor al promedio.
3 registros eliminados.
Ver solución
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.
La sintaxis básica es la siguiente:
...where EXPRESION in (SUBCONSULTA);
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
where autor='Richard Bach');
La subconsulta (consulta interna) retorna una lista de valores de un solo campo (codigo) que la
consulta exterior luego emplea al recuperar los datos.
Podemos reemplazar por un "join" la consulta anterior:
select distinct nombre
from editoriales as e
join libros
on codigoeditorial=[Link]
where autor='Richard Bach';
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.
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
where codigo not in
(select codigoeditorial
from libros
where autor='Richard Bach');
60 - Subconsultas con in
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes",
también tiene una tabla
"ciudades" donde registra los nombres de las ciudades.
1- Cree la tabla "clientes" (codigo, nombre, domicilio, ciudad, codigociudad)
y "ciudades" (codigo,
nombre). Agregue una restricción "primary key" para el campo "codigo" de ambas
tablas):
create table ciudades(
codigo serial,
nombre varchar(20),
primary key (codigo)
);
create table clientes (
codigo serial,
nombre varchar(30),
domicilio varchar(30),
codigociudad smallint not null,
primary key(codigo)
);
2- Ingrese algunos registros para ambas tablas:
insert into ciudades (nombre) values('Cordoba');
insert into ciudades (nombre) values('Cruz del Eje');
insert into ciudades (nombre) values('Carlos Paz');
insert into ciudades (nombre) values('La Falda');
insert into ciudades (nombre) values('Villa Maria');
insert into clientes(nombre,domicilio,codigociudad) values ('Lopez
Marcos','Colon 111',1);
insert into clientes(nombre,domicilio,codigociudad) values ('Lopez
Hector','San Martin 222',1);
insert into clientes(nombre,domicilio,codigociudad) values ('Perez Ana','San
Martin 333',2);
insert into clientes(nombre,domicilio,codigociudad) values ('Garcia
Juan','Rivadavia 444',3);
insert into clientes(nombre,domicilio,codigociudad) values ('Perez
Luis','Sarmiento 555',3);
insert into clientes(nombre,domicilio,codigociudad) values ('Gomez Ines','San
Martin 666',4);
insert into clientes(nombre,domicilio,codigociudad) values ('Torres
Fabiola','Alem 777',5);
insert into clientes(nombre,domicilio,codigociudad) values ('Garcia
Luis','Sucre 888',5);
3- Necesitamos conocer los nombres de las ciudades de aquellos clientes cuyo
domicilio es en calle
"San Martin", empleando subconsulta.
3 registros.
4- Obtenga la misma salida anterior pero empleando join.
5- Obtenga los nombre de las ciudades de los clientes cuyo apellido no
comienza con una letra
específica, empleando subconsulta.
2 registros.
6- Pruebe la subconsulta del punto 5 separada de la consulta exterior para
verificar que retorna
una lista de valores de un solo campo.
Ver solución
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".
El tipo de datos que se comparan deben ser compatibles.
La sintaxis básica es:
...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
where autor='Borges' and
codigoeditorial = any
(select [Link]
from editoriales as e
join libros as l
on codigoeditorial=[Link]
where [Link]='Richard Bach');
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:
VALORESCALAR OPERADORDECOMPARACION all (SUBCONSULTA);
Queremos saber si TODAS las editoriales que publicaron libros de "Borges" coinciden con
TODAS las editoriales que publicaron libros de "Richard Bach":
select titulo
from libros
where autor='Borges' and
codigoeditorial = all
(select [Link]
from editoriales as e
join libros as l
on codigoeditorial=[Link]
where [Link]='Richard Bach');
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.
Veamos otro ejemplo con un operador de comparación diferente:
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
where autor='Borges' and
precio > any
(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.
Veamos la diferencia si empleamos "all" en lugar de "any":
select titulo,precio
from libros
where autor='borges' and
precio > all
(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 cumple la condición, es decir, si es mayor a TODOS los precios de
"Richard Bach" (o al mayor), se lista.
Emplear "= any" es lo mismo que emplear "in".
Emplear "<> all" es lo mismo que emplear "not in".
Recuerde que solamente las subconsultas luego de un operador de comparación al cual es
seguido por "any" o "all") pueden incluir cláusulas "group by".
61 - Subconsultas any - some - all
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una
tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte
en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el
año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Cree las tablas:
create table socios(
numero serial,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);
create table inscriptos (
numerosocio int not null,
deporte varchar(20) not null,
cuotas smallint,
primary key(numerosocio,deporte)
);
2- Ingrese algunos registros:
insert into socios(documento,nombre,domicilio) values('23333333','Alberto
Paredes','Colon 111');
insert into socios(documento,nombre,domicilio) values('24444444','Carlos
Conte','Sarmiento 755');
insert into socios(documento,nombre,domicilio) values('25555555','Fabian
Fuentes','Caseros 987');
insert into socios(documento,nombre,domicilio) values('26666666','Hector
Lopez','Sucre 344');
insert into inscriptos values(1,'tenis',1);
insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);
3- Muestre el número de socio, el nombre del socio y el deporte en que está
inscripto con un join de
ambas tablas.
4- Muestre los socios que serán compañeros en tenis y también en natación
(empleando
subconsulta)
3 filas devueltas.
5- Vea si el socio 1 se ha inscripto en algún deporte en el cual se haya
inscripto el socio 2.
3 filas.
6- Obtenga el mismo resultado anterior pero empleando join.
7- Muestre los deportes en los cuales el socio 2 pagó más cuotas que ALGUN
deporte en los que se
inscribió el socio 1.
2 registros.
8- Muestre los deportes en los cuales el socio 2 pagó más cuotas que TODOS los
deportes en que se
inscribió el socio 1.
1 registro.
9- Cuando un socio no ha pagado la matrícula de alguno de los deportes en que
se ha inscripto, se
lo borra de la inscripción de todos los deportes. Elimine todos los socios que
no pagaron ninguna
cuota en algún deporte.
7 registros.
Ver solución
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
where [Link]=[Link]) as cantidad,
(select sum([Link]*cantidad)
from Detalles as d
where [Link]=[Link]) as total
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.
A este tipo de subconsulta se la denomina consulta correlacionada. La consulta interna se evalúa
tantas veces como registros tiene la consulta externa, se realiza la subconsulta para cada registro
de la consulta externa. El campo de la tabla dentro de la subconsulta ([Link]) se compara con
el campo de la tabla externa.
En este caso, específicamente, la consulta externa pasa un valor de "numero" a la consulta
interna. La consulta interna toma ese valor y determina si existe en "detalles", si existe, la
consulta interna devuelve la suma. El proceso se repite para el registro de la consulta externa, la
consulta externa pasa otro "numero" a la consulta interna y PostgreSQL repite la evaluación.
62 - Subconsultas correlacionadas
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una
tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte
en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el
año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Cree las tablas:
create table socios(
numero serial,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);
create table inscriptos (
numerosocio int not null,
deporte varchar(20) not null,
cuotas smallint,
primary key(numerosocio,deporte)
);
2- Ingrese algunos registros:
insert into socios(documento,nombre,domicilio) values('23333333','Alberto
Paredes','Colon 111');
insert into socios(documento,nombre,domicilio) values('24444444','Carlos
Conte','Sarmiento 755');
insert into socios(documento,nombre,domicilio) values('25555555','Fabian
Fuentes','Caseros 987');
insert into socios(documento,nombre,domicilio) values('26666666','Hector
Lopez','Sucre 344');
insert into inscriptos values(1,'tenis',1);
insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);
3- Se necesita un listado de todos los socios que incluya nombre y domicilio,
la cantidad de
deportes a los cuales se ha inscripto, empleando subconsulta.
4 registros.
4- Se necesita el nombre de todos los socios, el total de cuotas que debe
pagar (10 por cada
deporte) y el total de cuotas pagas, empleando subconsulta.
4 registros.
5- Obtenga la misma salida anterior empleando join.
Ver solución
63 - Subconsultas (Exists y No Exists)
Los operadores "exists" y "not exists" se emplean para determinar si hay o no datos en una lista
de valores.
Estos operadores pueden emplearse con subconsultas correlacionadas para restringir el resultado
de una consulta exterior a los registros que cumplen la subconsulta (consulta interior). Estos
operadores retornan "true" (si las subconsultas retornan registros) o "false" (si las subconsultas
no retornan registros).
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.
La sintaxis básica es la siguiente:
... where exists (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
(select *from Detalles as d
where [Link]=[Link]
and [Link]='lapiz');
Puede obtener el mismo resultado empleando una combinación.
Podemos buscar los clientes que no han adquirido el artículo "lapiz" empleando "if not exists":
select cliente,numero
from facturas as f
where not exists
(select *from Detalles as d
where [Link]=[Link]
and [Link]='lapiz');
63 - Subconsultas (Exists y No Exists)
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una
tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte
en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el
año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Cree las tablas:
create table socios(
numero serial,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);
create table inscriptos (
numerosocio int not null,
deporte varchar(20) not null,
cuotas smallint,
primary key(numerosocio,deporte)
);
2- Ingrese algunos registros:
insert into socios(documento,nombre,domicilio) values('23333333','Alberto
Paredes','Colon 111');
insert into socios(documento,nombre,domicilio) values('24444444','Carlos
Conte','Sarmiento 755');
insert into socios(documento,nombre,domicilio) values('25555555','Fabian
Fuentes','Caseros 987');
insert into socios(documento,nombre,domicilio) values('26666666','Hector
Lopez','Sucre 344');
insert into inscriptos values(1,'tenis',1);
insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);
3- Emplee una subconsulta con el operador "exists" para devolver la lista de
socios que se
inscribieron en 'natacion'.
3 registros.
4- Busque los socios que NO se han inscripto en 'natacion' empleando "not
exists".
1 registro.
5- Muestre todos los datos de los socios que han pagado todas las cuotas.
1 registro.
Ver solución
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.
select distinct [Link]
from libros as l1
where [Link] in
(select [Link]
from libros as l2
where [Link] <> [Link]);
En el ejemplo anterior empleamos una subconsulta correlacionada y las consultas interna y
externa emplean la misma tabla. La subconsulta devuelve una lista de valores por ello se emplea
"in" y sustituye una expresión en una cláusula "where".
Con el siguiente "join" se obtiene el mismo resultado:
select distinct [Link]
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
where titulo<>'El aleph' and
precio =
(select precio
from libros
where titulo='El aleph');
La subconsulta retorna un solo valor.
Buscamos los libros cuyo precio supere el precio promedio de los libros por editorial:
select [Link],[Link],[Link]
from libros as l1
where [Link] >
(select avg([Link])
from libros as l2
where [Link]= [Link]);
Por cada valor de l1, se evalúa la subconsulta, si el precio es mayor que el promedio.
64 - Subconsulta simil autocombinación
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una
tabla llamada "deportes"
en la cual almacena el nombre del deporte, el nombre del profesor que lo
dicta, el día de la semana
que se dicta y el costo de la cuota mensual.
1- Cree la tabla:
create table deportes(
nombre varchar(15),
profesor varchar(30),
dia varchar(10),
cuota decimal(5,2)
);
2- Ingrese algunos registros. Incluya profesores que dicten más de un curso:
insert into deportes values('tenis','Ana Lopez','lunes',20);
insert into deportes values('natacion','Ana Lopez','martes',15);
insert into deportes values('futbol','Carlos Fuentes','miercoles',10);
insert into deportes values('basquet','Gaston Garcia','jueves',15);
insert into deportes values('padle','Juan Huerta','lunes',15);
insert into deportes values('handball','Juan Huerta','martes',10);
3- Muestre los nombres de los profesores que dictan más de un deporte
empleando subconsulta.
4- Obtenga el mismo resultado empleando join.
5- Buscamos todos los deportes que se dictan el mismo día que un determinado
deporte (natacion)
empleando subconsulta.
6- Obtenga la misma salida empleando "join".
Ver solución
65 - Subconsulta en lugar de una tabla
Se pueden emplear subconsultas que retornen un conjunto de registros de varios campos 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]
from (TABLADERIVADA) as ALIAS;
La tabla derivada es una subsonsulta.
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
where [Link]=[Link]) as total
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
join (select f.*,
(select sum([Link]*cantidad)
from Detalles as d
where [Link]=[Link]) as total
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
tablas, sino una tabla propiamente dicha y una tabla derivada, que es en realidad una subconsulta.
65 - Subconsulta en lugar de una tabla
Primer problema:
Un club dicta clases de distintos deportes. En una tabla llamada "socios"
guarda los datos de los
socios, en una tabla llamada "deportes" la información referente a los
diferentes deportes que se
dictan y en una tabla denominada "inscriptos", las inscripciones de los socios
a los distintos
deportes.
Un socio puede inscribirse en varios deportes el mismo año. Un socio no puede
inscribirse en el
mismo deporte el mismo año. Distintos socios se inscriben en un mismo deporte
en el mismo año.
1- Cree las tablas con las siguientes estructuras:
create table socios(
documento char(8) not null,
nombre varchar(30),
domicilio varchar(30),
primary key(documento)
);
create table deportes(
codigo serial,
nombre varchar(20),
profesor varchar(15),
primary key(codigo)
);
create table inscriptos(
documento char(8) not null,
codigodeporte smallint not null,
año char(4),
matricula char(1),--'s'=paga, 'n'=impaga
primary key(documento,codigodeporte,año)
);
2- Ingrese algunos registros en las 3 tablas:
insert into socios values('22222222','Ana Acosta','Avellaneda 111');
insert into socios values('23333333','Betina Bustos','Bulnes 222');
insert into socios values('24444444','Carlos Castro','Caseros 333');
insert into socios values('25555555','Daniel Duarte','Dinamarca 44');
insert into deportes(nombre,profesor) values('basquet','Juan Juarez');
insert into deportes(nombre,profesor) values('futbol','Pedro Perez');
insert into deportes(nombre,profesor) values('natacion','Marina Morales');
insert into deportes(nombre,profesor) values('tenis','Marina Morales');
insert into inscriptos values ('22222222',3,'2006','s');
insert into inscriptos values ('23333333',3,'2006','s');
insert into inscriptos values ('24444444',3,'2006','n');
insert into inscriptos values ('22222222',3,'2005','s');
insert into inscriptos values ('22222222',3,'2007','n');
insert into inscriptos values ('24444444',1,'2006','s');
insert into inscriptos values ('24444444',2,'2006','s');
3- Realice una consulta en la cual muestre todos los datos de las
inscripciones, incluyendo el
nombre del deporte y del profesor.
Esta consulta es un join.
4- Utilice el resultado de la consulta anterior como una tabla derivada para
emplear en lugar de una
tabla para realizar un "join" y recuperar el nombre del socio, el deporte en
el cual está inscripto,
el año, el nombre del profesor y la matrícula.
Ver solución
66 - Subconsulta (update - delete)
Dijimos que podemos emplear subconsultas en sentencias "insert", "update", "delete", además de
"select".
La sintaxis básica para realizar actualizaciones con subconsulta es la siguiente:
update TABLA set CAMPO=NUEVOVALOR
where CAMPO= (SUBCONSULTA);
Actualizamos el precio de todos los libros de editorial "Emece":
update libros set precio=precio+(precio*0.1)
where codigoeditorial=
(select codigo
from editoriales
where nombre='Emece');
La subconsulta retorna un único valor. También podemos hacerlo con un join.
La sintaxis básica para realizar eliminaciones con subconsulta es la siguiente:
delete from TABLA
where CAMPO in (SUBCONSULTA);
Eliminamos todos los libros de las editoriales que tiene publicados libros de "Juan Perez":
delete from libros
where codigoeditorial in
(select [Link]
from editoriales as e
join libros
on codigoeditorial=[Link]
where autor='Juan Perez');
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.
66 - Subconsulta (update - delete)
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una
tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte
en el cual se inscribe
y si la matricula está o no paga, y una tabla denominada "socios" en la que
guarda los datos
personales de cada socio.
1- Cree las tablas:
create table socios(
numero serial,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);
create table inscriptos (
numerosocio int not null,
deporte varchar(20) not null,
matricula char(1),-- 'n' o 's'
primary key(numerosocio,deporte)
);
2- Ingrese algunos registros:
insert into socios(documento,nombre,domicilio) values('23333333','Alberto
Paredes','Colon 111');
insert into socios(documento,nombre,domicilio) values('24444444','Carlos
Conte','Sarmiento 755');
insert into socios(documento,nombre,domicilio) values('25555555','Fabian
Fuentes','Caseros 987');
insert into socios(documento,nombre,domicilio) values('26666666','Hector
Lopez','Sucre 344');
insert into inscriptos values(1,'tenis','s');
insert into inscriptos values(1,'basquet','s');
insert into inscriptos values(1,'natacion','s');
insert into inscriptos values(2,'tenis','s');
insert into inscriptos values(2,'natacion','s');
insert into inscriptos values(2,'basquet','n');
insert into inscriptos values(2,'futbol','n');
insert into inscriptos values(3,'tenis','s');
insert into inscriptos values(3,'basquet','s');
insert into inscriptos values(3,'natacion','n');
insert into inscriptos values(4,'basquet','n');
3- Actualizamos la cuota ('s') de todas las inscripciones de un socio
determinado (por documento)
empleando subconsulta.
4- Elimine todas las inscripciones de los socios que deben alguna matrícula.
5 registros eliminados.
Ver solución
67 - Subconsulta (insert)
Aprendimos que una subconsulta puede estar dentro de un "select", "update" y "delete"; también
puede estar dentro de un "insert".
Podemos ingresar registros en una tabla empleando un "select".
La sintaxis básica es la siguiente:
insert into TABLAENQUESEINGRESA (CAMPOSTABLA1)
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.
Ingresamos registros en la tabla "aprobados" seleccionando registros de la tabla "alumnos":
insert into aprobados (documento,nota)
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".
67 - Subconsulta (insert)
Primer problema:
Un comercio que vende artículos de librería y papelería almacena la
información de sus ventas en una
tabla llamada "facturas" y otra "clientes".
1-Cree las tablas:
create table clientes(
codigo serial,
nombre varchar(30),
domicilio varchar(30),
primary key(codigo)
);
create table facturas(
numero int not null,
fecha date,
codigocliente int not null,
total decimal(6,2),
primary key(numero)
);
2-Ingrese algunos registros:
insert into clientes(nombre,domicilio) values('Juan Lopez','Colon 123');
insert into clientes(nombre,domicilio) values('Luis Torres','Sucre 987');
insert into clientes(nombre,domicilio) values('Ana Garcia','Sarmiento 576');
insert into clientes(nombre,domicilio) values('Susana Molina','San Martin
555');
insert into facturas values(1200,'2007-01-15',1,300);
insert into facturas values(1201,'2007-01-15',2,550);
insert into facturas values(1202,'2007-01-15',3,150);
insert into facturas values(1300,'2007-01-20',1,350);
insert into facturas values(1310,'2007-01-22',3,100);
3- El comercio necesita una tabla llamada "clientespref" en la cual quiere
almacenar el nombre y
domicilio de aquellos clientes que han comprado hasta el momento más de 500
pesos en mercaderías.
Créela la tabla:
create table clientespref(
nombre varchar(30),
domicilio varchar(30)
);
4- Ingrese los registros en la tabla "clientespref" seleccionando registros de
la tabla "clientes" y
"facturas".
5- Vea los registros de "clientespref":
Ver solución
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.
Las vistas permiten:
- ocultar información: permitiendo el acceso a algunos datos y manteniendo oculto el resto de la
información que no se incluye en la vista. El usuario solo puede consultar la vista.
- 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.
- mejorar el rendimiento: se puede evitar tipear instrucciones repetidamente almacenando en una
vista el resultado de una consulta compleja que incluya información de varias tablas.
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.
Una vista se define usando un "select".
La sintaxis básica parcial para crear una vista es la siguiente:
create view NOMBREVISTA as
SENTENCIAS SELECT
from TABLA;
El contenido de una vista se muestra con un "select":
select *from NOMBREVISTA;
En el siguiente ejemplo creamos la vista "vista_empleados", que es resultado de una
combinación en la cual se muestran 4 campos:
create view vista_empleados as
select (apellido||' '||[Link]) as nombre,sexo,
[Link] as seccion, cantidadhijos
from empleados as e
join secciones as s
on codigo=seccion
Para ver la información contenida en la vista creada anteriormente tipeamos:
select *from vista_empleados;
Podemos realizar consultas a una vista como si se tratara de una tabla:
select seccion,count(*) as cantidad
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.
Otra sintaxis es la siguiente:
create view NOMBREVISTA (NOMBRESDEENCABEZADOS)
as
SENTENCIASSELECT
from TABLA;
Creamos otra vista de "empleados" denominada "vista_empleados_ingreso" que almacena la
cantidad de empleados por año:
create view vista_empleados_ingreso (fecha,cantidad)
as
select extract(year from fechaingreso),count(*)
from empleados
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.
Las vistas se crean en la base de datos activa.
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.
Se pueden construir vistas sobre otras vistas.
68 - Vistas
Primer problema:
Un club dicta cursos de distintos deportes. Almacena la información en varias
tablas.
El director no quiere que los empleados de administración conozcan la
estructura de las tablas ni
algunos datos de los profesores y socios, por ello se crean vistas a las
cuales tendrán acceso.
1- Crear las tablas:
create table socios(
documento char(8) not null,
nombre varchar(40),
domicilio varchar(30),
primary key (documento)
);
create table profesores(
documento char(8) not null,
nombre varchar(40),
domicilio varchar(30),
primary key (documento)
);
create table cursos(
numero serial,
deporte varchar(20),
dia varchar(15),
documentoprofesor char(8),
primary key (numero)
);
create table inscriptos(
documentosocio char(8) not null,
numero smallint not null,
matricula char(1),
primary key (documentosocio,numero)
);
2- Ingrese algunos registros para todas las tablas:
insert into socios values('30000000','Fabian Fuentes','Caseros 987');
insert into socios values('31111111','Gaston Garcia','Guemes 65');
insert into socios values('32222222','Hector Huerta','Sucre 534');
insert into socios values('33333333','Ines Irala','Bulnes 345');
insert into profesores values('22222222','Ana Acosta','Avellaneda 231');
insert into profesores values('23333333','Carlos Caseres','Colon 245');
insert into profesores values('24444444','Daniel Duarte','Sarmiento 987');
insert into profesores values('25555555','Esteban Lopez','Sucre 1204');
insert into cursos(deporte,dia,documentoprofesor)
values('tenis','lunes','22222222');
insert into cursos(deporte,dia,documentoprofesor)
values('tenis','martes','22222222');
insert into cursos(deporte,dia,documentoprofesor)
values('natacion','miercoles','22222222');
insert into cursos(deporte,dia,documentoprofesor)
values('natacion','jueves','23333333');
insert into cursos(deporte,dia,documentoprofesor)
values('natacion','viernes','23333333');
insert into cursos(deporte,dia,documentoprofesor)
values('futbol','sabado','24444444');
insert into cursos(deporte,dia,documentoprofesor)
values('futbol','lunes','24444444');
insert into cursos(deporte,dia,documentoprofesor)
values('basquet','martes','24444444');
insert into inscriptos values('30000000',1,'s');
insert into inscriptos values('30000000',3,'n');
insert into inscriptos values('30000000',6,null);
insert into inscriptos values('31111111',1,'s');
insert into inscriptos values('31111111',4,'s');
insert into inscriptos values('32222222',8,'s');
3- Cree una vista en la que aparezca el nombre y documento del socio, el
deporte, el día y el nombre del profesor.
4- Muestre la información contenida en la vista.
5- Realice una consulta a la vista donde muestre la cantidad de socios
inscriptos en cada deporte
ordenados por cantidad.
6- Muestre (consultando la vista) los cursos (deporte y día) para los cuales
no hay inscriptos.
7- Muestre los nombres de los socios que no se han inscripto en ningún curso
(consultando la vista)
8- Muestre (consultando la vista) los profesores que no tienen asignado ningún
deporte aún.
9- Muestre (consultando la vista) el nombre y documento de los socios que
deben matrículas.
10- Consulte la vista y muestre los nombres de los profesores y los días en
que asisten al club para
dictar sus clases.
11- Muestre la misma información anterior pero ordenada por día.
12- Muestre todos los socios que son compañeros en tenis los lunes.
Ver solución
69 - Vistas (eliminar)
Para quitar una vista se emplea "drop view":
drop view NOMBREVISTA;
Si se intenta eliminar una tabla a la que hace referencia una vista, la tabla no se elimina, hay que
eliminar la vista previamente.
Solo el propietario puede eliminar una vista.
Eliminamos la vista denominada "vista_empleados":
drop view vista_empleados;
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:
create sequence NOMBRESECUENCIA
start with VALORENTERO
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.
- "maxvalue" define el valor máximo para la secuencia. Si se omite, por defecto es
9223372036854775807.
- "minvalue" establece el valor mínimo de la secuencia. Si se omite será
-9223372036854775808.
- 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.
Si no se especifica ninguna cláusula, excepto el nombre de la secuencia, por defecto, comenzará
en 1, se incrementará en 1, el mínimo valor será -9223372036854775808, el máximo será
9223372036854775807 y "nocycle".
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":
create sequence sec_codigolibros
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:
create sequence sec_numerosocios
start with 2
increment by 5
cycle;
La secuencia anterior, "sec_numerosocios", incrementa sus valores en 5 y al llegar al máximo
valor recomenzará la secuencia desde el valor mínimo.
Dijimos que las secuencias son tablas; por lo tanto se accede a ellas mediante consultas,
empleando "select".
select * from sec_numerosocios;
Tenemos una función que nos retorna el próximo valor de la secuencia:
select nextval('sec_numerosocios');
select nextval('sec_numerosocios');
Imprime un 2 y un 3.
El valor retornado "nextval" pueden usarse cuando definimos una tabla.
Veamos un ejemplo completo:
Creamos una secuencia para el código de la tabla "libros", especificando el valor máximo, el
incremento y que no sea circular:
create sequence sec_codigolibros
minvalue 1000
maxvalue 999999
increment by 1;
Creamos la tabla libros y asociamos a la columna codigo la secuenca sec_codigolibros:
create table libros(
codigo nextval('sec_codigolibros'),
titulo varchar(30),
autor varchar(30),
editorial varchar(15),
primary key (codigo)
);
Ingresamos un registro en "libros":
insert into libros(titulo,autor,editorial) values
('El aleph', 'Borges','Emece');
Ingresamos otro registro en "libros":
insert into libros(titulo,autor,editorial) values
('Matematica estas ahi', 'Paenza','Nuevo siglo');
Luego si imprimimos los dos registros podemos comprobar que el campo codigo almacena el
valor 1000 y 1001 respectivamente.
Para eliminar una secuencia empleamos "drop sequence". Sintaxis:
drop sequence NOMBRESECUENCIA;
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):
drop sequence NOMBRESECUENCIA cascade;
Si la secuencia no existe aparecerá un mensaje indicando tal situación.
Podemos modificar una secuencia con la siguiente sintaxis:
alter sequence NOMBRESECUENCIA
start with VALORENTERO
increment by VALORENTERO
maxvalue VALORENTERO
minvalue VALORENTERO
cycle;
70 - Secuencias (create sequence- alter
sequence - nextval - drop sequence)
Primer problema:
Una empresa registra los datos de sus empleados en una tabla llamada
"empleados".
1 - Cree la secuencia "sec_legajoempleados" estableciendo el valor mínimo (1),
máximo (999),
valor inicial (100), valor de incremento (2) y no circular.
2- Cree la tabla:
create table empleados(
legajo bigint default nextval('sec_legajoempleados'),
documento char(8) not null,
nombre varchar(30) not null,
primary key(legajo)
);
3 - Ingrese algunos registros:
insert into empleados(documento,nombre)
values ('22333444','Ana Acosta');
insert into empleados(documento,nombre)
values ('23444555','Betina Bustamante');
insert into empleados(documento,nombre)
values ('24555666','Carlos Caseros');
insert into empleados(documento,nombre)
values ('25666777','Diana Dominguez');
insert into empleados(documento,nombre)
values ('26777888','Estela Esper');
4 - Recupere los registros de la tabla empleados.
5 - Efectue un select de la secuencia.
6 - Elimine la secuencia y la tabla asociada a dicha secuencia.
Ver solución
Segundo problema:
Una empresa organiza un curso de computación (dispone de dos aulas), almacenar
en una tabla
inscriptos los datos del estudiante. Cada vez que se inscribe un alumno
asignarlo a un aula en
forma alternada (primero a la 1 y luego a la 2, luego nuevamente a la 1 y así
sucesivamente)
1 - Crear una secuencia sec_codigoaulainscriptos (valor inicial 1, incremento
1, valor máximo 2 y
debe ser circular)
2 - Crear la tabla inscriptos:
create table inscriptos(
documento char(8) not null,
nombre varchar(30) not null,
codigocurso int default nextval('sec_codigoaulainscriptos'),
primary key(documento)
);
3 - Insertar algunos registros:
insert into inscriptos(documento,nombre) values ('20000000','Rodriguez
Pablo');
insert into inscriptos(documento,nombre) values ('30000000','Mercado Ana');
insert into inscriptos(documento,nombre) values ('40000000','Morello Luis');
insert into inscriptos(documento,nombre) values ('50000000','Prado Juan');
insert into inscriptos(documento,nombre) values ('60000000','Solis Maria');
4 - Imprimir todos los alumnos del curso 1.
5 - Imprimir todos los alumnos del curso 2.
Ver solución
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.
La sintaxis básica para crear una función es:
create or replace function [nombre de la función]([parámetros]) returns [tipo
de dato que retorna]
as
[definición de la función]
language [lenguaje utilizado]
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
C
Alguno de los valores anteriores debemos indicarlo en la directiva 'language'.
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.
Luego la sintaxis para implementar una función SQL:
create or replace function [nombre de la función]([parámetros]) returns [tipo
de dato que retorna]
as
[comandos sql]
language sql
Como primer problema implementaremos una función que reciba dos enteros y retorne la suma
de los mismos:
create or replace function sumar(integer,integer) returns integer
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.
Para llamar luego a esta función lo hacemos por ejemplo en un select:
select sumar(3,4);
Podemos acceder perfectamente a una o más tablas en la función. Confeccionaremos una función
que acceda a la tabla usuarios:
create table usuarios (
nombre varchar(30),
clave varchar(10)
);
y rescate la clave de un usuario que le pasamos como parámetro:
create or replace function retornarclave(varchar) returns varchar
as
'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');
72 - Funciones SQL
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(5,2),
cantidad smallint,
primary key(codigo)
);
2- Ingrese algunos registros:
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Sertal','Roche',5.2,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Buscapina','Roche',4.10,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal 500','Bayer',15.60,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Paracetamol 500','Bago',1.90,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Bayaspirina','Bayer',2.10,150);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal jarabe','Bayer',5.10,250);
3- Implementar una función que retorne el precio promedio de la tabla
medicamentos.
4- Imprimir el precio promedio de los medicamentos.
5- Imprimir los medicamentos que tienen un precio mayor al promedio.
Ver solución
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:
create or replace function [nombre de la función]([parámetros]) returns void
as
[comandos sql]
language sql
Confeccionaremos una función que cargue cuatro registros en la tabla usuarios:
create or replace function cargarusuarios() returns void
as
$$
insert into usuarios (nombre, clave) values ('Marcelo','Boca');
insert into usuarios (nombre, clave) values ('JuanPerez','Juancito');
insert into usuarios (nombre, clave) values ('Susana','River');
insert into usuarios (nombre, clave) values ('Luis','River');
$$
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:
create or replace function cargarusuarios() returns void
as
'
insert into usuarios (nombre, clave) values (''Marcelo'',''Boca'');
insert into usuarios (nombre, clave) values (''JuanPerez'',''Juancito'');
insert into usuarios (nombre, clave) values (''Susana'',''River'');
insert into usuarios (nombre, clave) values (''Luis'',''River'');
'
language sql;
Debemos disponer dos comillas simples en lugar de una.
Luego para llamar la función lo hacemos:
select cargarusuarios();
73 - Función SQL que no retorna dato
(void)
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(5,2),
cantidad smallint,
primary key(codigo)
);
2- Ingrese algunos registros:
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Sertal','Roche',5.2,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Buscapina','Roche',4.10,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal 500','Bayer',15.60,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Paracetamol 500','Bago',1.90,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Bayaspirina','Bayer',2.10,150);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal jarabe','Bayer',5.10,250);
3- Implementar una función que reciba el código de un medicamento y proceda a
borrarlo.
La función no retorna dato.
4- Proceder a llamar a la función.
5- Imprimir la tabla medicamentos.
Ver solución
74 - Función SQL que retorna un dato
compuesto.
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:
create table libros(
codigo serial,
titulo varchar(40) not null,
autor varchar(20) default 'Desconocido',
editorial varchar(20),
precio decimal(6,2),
primary key (codigo)
);
insert into libros (titulo,autor,editorial,precio)
values('El aleph','Borges','Emece',25.33);
insert into libros (titulo,autor,editorial,precio)
values('Java en 10 minutos','Mario Molina','Siglo XXI',50.65);
insert into libros (titulo,autor,editorial,precio)
values('Alicia en el pais de las maravillas','Lewis Carroll','Emece',19.95);
insert into libros (titulo,autor,editorial,precio)
values('Alicia en el pais de las maravillas','Lewis Carroll','Planeta',15);
Luego al definir la función indicamos el nombre de la tabla como dato que devuelve:
create or replace function retornarlibro(int) returns libros
as
'select * from libros where codigo=$1 ;'
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:
(3,"Alicia en el pais de las maravillas","Lewis Carroll",Emece,19.95)
74 - Función SQL que retorna un dato
compuesto.
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo serial,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(5,2),
cantidad smallint,
primary key(codigo)
);
2- Ingrese algunos registros:
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Sertal','Roche',5.2,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Buscapina','Roche',4.10,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal 500','Bayer',15.60,100);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Paracetamol 500','Bago',1.90,200);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Bayaspirina','Bayer',2.10,150);
insert into medicamentos (nombre,laboratorio,precio,cantidad)
values('Amoxidal jarabe','Bayer',5.10,250);
3- Implementar una función que retorne el registro completo del medicamento
más caro.
4- Proceder a llamar a la función.
Ver solución