Bases de Datos 1 - RUA - Universidad de Alicante

Anuncio
práctica
Bases de Datos 1
Eva Gómez Ballester
Paloma Moreda Pozo
Patricio Martínez Barco
José Clavel Cerro
Ernesto Pérez López
Armando Suárez Cueto
Dpto. de Lenguajes y
Sistemas Informáticos
Escuela Politécnica Superior
Universidad de Alicante
http://www.dlsi.ua.es/asignaturas/bd1/bd1.html
índice
sesión 0_______________________________________________ 5
select 1 _______________________________________________ 9
BD Proveedores _______________________________________ 13
select 2 ______________________________________________ 21
select 3 ______________________________________________ 27
select fecha___________________________________________ 31
create _______________________________________________ 33
manipulación 1 ________________________________________ 41
manipulación 2 ________________________________________ 47
manipulación 3 ________________________________________ 53
conjuntos ____________________________________________ 59
funciones_____________________________________________ 63
group by _____________________________________________ 67
group by - having ______________________________________ 71
subselect _____________________________________________ 75
subselect - exists ______________________________________ 81
adicionales 1 __________________________________________ 83
adicionales 2 __________________________________________ 85
adicionales 3 __________________________________________ 87
adicionales 4 __________________________________________ 89
adicionales 5 __________________________________________ 91
adicionales 6 __________________________________________ 93
adicionales 7 __________________________________________ 95
sesión 0
ENTORNO ORACLE
Objetivos:
• Adquirir la destreza mínima para trabajar en el entorno ORACLE iSQLplus.
Contenidos
•
•
•
•
•
•
•
Concepto de Base de Datos y Tabla.
Entrar en ORACLE SQL.
Manejo de menús.
Selección de Base de Datos.
Tipos de datos.
Ayuda en línea.
Salvar y recuperar órdenes SQL.
Concepto de Base de Datos y Relación (Tabla)
Una base de datos es un conjunto de información interrelacionada que representa un sistema
de información particular, y está compuesta por relaciones, o más comúnmente tablas, que
almacenan los datos referentes a un objeto o a una interrelación entre objetos.
Así, si queremos mantener mediante un gestor de bases de datos información docente, lo que
haremos (en este caso en particular) será crear una base de datos que englobe tres tablas:
PROFESORES, ASIGNATURAS e IMPARTE. Cada tabla tendrá sus columnas, que representan los
correspondientes atributos de la entidad o claves ajenas que permiten relacionar varias tablas
entre sí. La BD que gestione esta información se llamará Ejemplo, y las tablas contenidas en ella
se presentan en el siguiente cuadro.
Base de Datos: Ejemplo
PROFESORES ( dni : varchar(10), nombre : varchar(40), categoria : char(4), ingreso : date )
Clave primaria: dni
ASIGNATURAS ( codigo : char(5), descripcion : varchar(35), creditos : number(3,1),
creditosp : number(3,1) )
Clave primaria: codigo
IMPARTE ( dni : varchar2(10), asignatura : char(5) )
Clave primaria: (dni, asignatura)
Clave ajena: dni → PROFESORES
Clave ajena: asignatura → ASIGNATURAS
5
Extensiones de Ejemplo:
ASIGNATURAS
codigo descripcion
creditos creditosp
HI
FBD
DGBD
PC
FP
4.5
6.0
6.0
6.0
9.0
HISTORIA DE LA INFORMATICA
FUNDAMENTOS DE LAS BASES DE DATOS
DISEÑO Y GESTION DE BASES DE DATOS
PROGRAMACION CONCURRENTE
FUNDAMENTOS DE LA PROGRAMACION
1.5
3.0
1.5
4.5
IMPARTE
PROFESORES
dni
nombre
categoria ingreso
dni
asignatura
21111222
21222333
21333444
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
TEU
TEU
ASO6
21111222
21111222
21333444
FBD
DGBD
PC
01/10/1993
16/06/1989
16/06/1992
iSQLplus
Oracle es un sistema de gestión de bases de datos relacional. Dicho gestor está instalado en
un servidor al que se accede por red desde un navegador o un cliente Windows.
Desde el navegador, accediendo a la dirección http://oraculo.eps.ua.es:5560/isqlplus, aparece
la pantalla de identificación. Para la mayoría de las sesiones, la información a introducir en el
formulario es:
Usuario: alumno
Contraseña: alumno
Conexión: oracle
Una vez el sistema permite la conexión, disponemos de un área donde introducir órdenes SQL
cuyo resultado se obtiene pulsando el botón “Ejecutar”. Podemos probar con la siguiente consulta:
select * from profesores
resultado:
dni
21111222
21222333
21333444
nombre
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
categoria
TEU
TEU
ASO6
Tipos de datos
En general, la utilización de varias tablas necesita que ellas se puedan relacionar por una
columna común, en este caso dni de profesor, para la relación entre imparte y profesor, y codigo
de asignatura, para la relación entre asignatura e imparte. Nótese, sin embargo, que en la tabla
imparte el código de asignatura se llama asignatura y en la tabla asignaturas codigo. En realidad,
tales atributos son “comunes” porque el dominio es el mismo para ambos y se pueden comparar.
Los dominios vienen definidos por los tipos de datos que ofrece el SGBD.
Los tipos de datos que acompañan en el esquema de BD a cada columna en cada tabla
determinan los valores que pueden tomar éstas. Son de capital importancia a la hora de relacionar
tablas en una sentencia select, puesto que sólo podremos comparar columnas con idéntico tipo de
datos, o a la hora de manipular datos, dado que, como veremos en próximas sesiones, cada tipo
de datos presenta unos requisitos específicos para su manipulación.
6
Algunos de los tipos de datos que nos podemos encontrar en ORACLE son:
VARCHAR2(n) Cadena de caracteres de longitud variable con un máximo de n
CHAR(n)
LONG
NUMBER(p,s)
RAW(n)
LONG RAW
DATE
(1<=n<=4000)
Cadena de caracteres de longitud fija de longitud n (1<=n<=2000)
Cadena de caracteres de longitud variable hasta 2 gigabytes, o 231-1 bytes
Números con precisión p y escala s (1<=p<=38) (-84<=s<=127)
Cadena de caracteres binarios de longitud n (1<=n<=2000)
Cadena de caracteres binarios de longitud variable hasta 2 gigabytes
Datos de tipo fecha, con la forma dd/mm/yyyy(día, mes y año). Los valores
date deben manejarse encerrados entre comillas simples. Rango válido desde 1
de enero de 4712 AC hasta el 31 de diciembre de 4712 DC.
INFORMACIÓN ADICIONAL
Ayuda en línea.
Direcciones con ayuda Oracle disponible:
•
www.oracle.com
•
www.redcientifica.com/
En general, es bastante fácil encontrar información en internet por medio de cualquier
buscador.
Obtener información sobre una tabla de la BD
Ejecutar DESC nombreTabla o DESCRIBE nombreTabla para mostrar información de la
tabla nombreTabla: ( el nombre de cada columna, si los valores nulos se permiten o no (NULL or
NOT NULL) en esa columna, tipo de dato de la columna, por ejemplo, NUMBER, CHAR,
VARCHAR2, LONG, DATE, RAW, o LONG RAW, y la precisión de la columna si el tipo de dato lo
requiere).
Otras informaciones disponibles en el catálogo del sistema (el comando DESCRIBE se basa en
algunas de las tablas que se utilizan aquí) son:
select distinct table_name, column_name from all_cons_columns
where OWNER='BD1TABLAS';
select * from all_cons_columns where OWNER='BD1TABLAS';
select OWNER, TABLE_NAME, COLUMN_NAME, DATA_TYPE, DATA_LENGTH,
DATA_PRECISION, DATA_SCALE from all_tab_columns where
OWNER='BD1TABLAS';
Donde BD1TABLAS es un usuario (el propietario, en este caso, de la BD PROVEEDORES)
Para que los datos se muestren en pantalla sin saltos de línea, se puede dar formato a las
columnas con las siguientes órdenes, (es permanente para toda la sesión, sólo se ejecutan una
vez; si se quiere otro formato, hay que volver a ejecutarlas con las modificaciones oportunas)
COLUMN
COLUMN
COLUMN
COLUMN
OWNER FORMAT a20
CONSTRAINT_NAME FORMAT A20
TABLE_NAME FORMAT A15
COLUMN_NAME FORMAT A20
7
COLUMN POSITION FORMAT 99
COLUMN DATA_TYPE FORMAT A15
Y también:
SET LINESIZE 600 (para evitar que la filas de salida,
incluída la cabecera, ocupen , más de una línea)
SET PAGESIZE 200 (para evitar cabeceras tantas cabeceras)
Sobre guardar órdenes en disco
En la máquina se dispone de un disco duro local que se puede utilizar para guardar y recuperar
ficheros generados por el alumno. No obstante, no se garantiza que los datos ahí guardados
permanezcan de una sesión para otra. Por lo tanto, si se quieren guardar datos con seguridad es
preferible hacerlo en un disco removible, o bien utilizando los servicios de disco virtual de la EPS o
el Campus Virtual.
8
select 1
SQL - SELECT
Objetivos:
• Introducir al alumno en el SQL y la orden SELECT.
• Comentar el esquema lógico propuesto.
Contenidos:
• Sistema de información propuesto.
• La orden SELECT-FROM-WHERE.
• Proyecciones, Selecciones.
• Tipos de datos.
• ORDER BY
Se proporciona información sobre las consultas más sencillas a realizar sobre una BD.
LA ORDEN SELECT-FROM-WHERE
Sintaxis general de la orden select
SELECT [ DISTINCT ] listaColumnas
FROM listaTablas
[ WHERE condición ]
[ GROUP BY listaColumnas
[ HAVING condición ] ]
[ ORDER BY listaColumnas [ ASC | DESC ] ]
Select-From
Para realizar consultas sobre una base de datos vamos a utilizar la orden SELECT de SQL. Con
la sintaxis que se muestra en el punto anterior seremos capaces de formular cualquier
requerimiento (consulta) sobre las tablas que componen una determinada BD. En este momento
veremos la expresión mínima de la orden, formada por dos cláusulas, select y from, que
obligatoriamente tendremos que especificar en cada consulta que realicemos.
Supongamos que sobre la base de datos Ejemplo (cuyo esquema y contenido se presentaron
en la sesión anterior) queremos obtener todos los datos acerca de los profesores. Debemos, en
primer lugar, seleccionar la base de datos, y ejecutamos (en el Query-language) la siguiente
orden
select * from profesores
resultado:
dni
21111222
21222333
21333444
nombre
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
categoria
TEU
TEU
ASO6
9
Al especificar en la lista de atributos un asterisco le indicamos al SGBD que deseamos la
información de todas las columnas definidas para la tabla PROFESORES.
Si deseamos conocer a qué categorías pertenecen los profesores que se encuentran en la BD:
select categoria from profesores
resultado:
categoria
TEU
TEU
ASO6
Podemos especificar tantas columnas como queramos:
select nombre, categoria from profesores
nombre
resultado:
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
categoria
TEU
TEU
ASO6
Para evitar la salida de filas duplicadas podemos utilizar el modificador DISTINCT:
select distinct categoria from profesores
resultado:
categoria
TEU
ASO6
Nótese, sin embargo, que las dos órdenes siguientes obtienen el mismo resultado, puesto que
la duplicación se refiere a filas completas y no a una columna en particular:
select distinct dni, categoria from profesores
select dni, categoria from profesores
resultado:
dni
21111222
21222333
21333444
categoria
TEU
TEU
ASO6
La cláusula WHERE
Con la orden select-from obtenemos la información de las columnas requeridas de toda la
tabla. Si únicamente queremos información de aquellas filas que cumplen una determinada
condición utilizaremos la cláusula where.
Pretendemos obtener el nombre de los profesores titulares:
select nombre from profesores where categoria = 'TEU'
resultado:
10
nombre
EVA GOMEZ
MANUEL PALOMAR
En la construcción de tales condiciones podemos utilizar las conectivas lógicas AND, OR, y
NOT, así como los paréntesis para alterar la evaluación de izquierda a derecha. También, los
operadores de comparación >, <, >=, <=, <>
Nombre de los profesores que son titulares o asociados a 6 horas:
select nombre from profesores
where categoria = 'TEU' or categoria = 'ASO6'
nombre
resultado:
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
La cláusula ORDER BY
Podemos ordenar la salida producida por nuestra orden select por valores ascendentes o
descendentes de una columna en particular.
Nombre de las asignaturas ordenadas de menor a mayor número de créditos:
select creditos, descripcion from asignaturas order by creditos
resultado:
creditos
4.5
6
6
6
9
descripcion
Historia de la Informática
Fundamentos de las Bases de Datos
Diseño y Gestión de Bases de Datos
Programación Concurrente
Fundamentos de la Programación
Si no se indica nada la ordenación será ascendente.
El mismo requerimiento anterior pero en orden descendente y de aquellas que tienen más de
4.5 créditos:
select creditos, descripcion from asignaturas
where creditos > 4.5
order by creditos desc
resultado:
creditos
9
6
6
6
descripcion
Fundamentos de la Programación
Fundamentos de las Bases de Datos
Diseño y Gestión de Bases de Datos
Programación Concurrente
Puede aplicarse más de un criterio de ordenación:
select creditos, descripcion from asignaturas order by creditos, descripcion
resultado:
creditos
4.5
6
6
6
9
descripcion
Historia de la Informática
Diseño y Gestión de Bases de Datos
Fundamentos de las Bases de Datos
Programación Concurrente
Fundamentos de la Programación
11
Constantes
Se pueden explicitar constantes en la orden select de forma que dicho valor aparezca en
todas las filas:
select 'La asignatura ', descripcion, ' tiene ', creditos, ' creditos'
from asignaturas
order by creditos
resultado:
'laasignatura'
La asignatura
La asignatura
La asignatura
La asignatura
La asignatura
12
descripcion
HISTORIA DE LA INFORMATICA
FUNDAMENTOS DE LAS BASES DE DATOS
DISEÑO Y GESTION DE BASES DE DATOS
PROGRAMACION CONCURRENTE
FUNDAMENTOS DE LA PROGRAMACION
'tiene' creditos 'créditos’
tiene
4.5 créditos
tiene
6
créditos
tiene
6
créditos
tiene
6
créditos
tiene
9
créditos
BD Proveedores
LA BASE DE DATOS
PROVEEDORES
Objetivos:
• Ser capaz de interpretar un esquema de base de datos relacional (concretamente, el
propuesto para las prácticas de la asignatura: Proveedores)
Se detalla el esquema lógico que describe la BD de PROVEEDORES, ya creada y a
disposición del alumno, intentando que comprenda su significado, el sistema real que
pretende representar. El esquema lógico es la referencia que permite construir las órdenes
select con las que interrogar a la BD. Las extensiones de cada relación se incluyen como
ayuda para comprobar la corrección de las órdenes select utilizadas.
13
LA BASE DE DATOS PROVEEDORES
TABLA
VENDEDOR
COLUMNAS
( numvend NUMBER(4),
nomvend VARCHAR2(30),
nombrecomer VARCHAR2(30),
telefono CHAR(11),
calle VARCHAR2(30),
ciudad VARCHAR2(20),
provincia VARCHAR2(20) )
( numpieza VARCHAR2(16),
nompieza VARCHAR2(30),
preciovent NUMBER(9,2))
RESTRICCIONES
Clave Primaria: (numvend)
PRECIOSUM
( numpieza VARCHAR2(16),
numvend NUMBER(4),
preciounit NUMBER(9,2),
diassum NUMBER(3),
descuento NUMBER(2))
Clave Primaria: (numpieza, numvend)
Clave Ajena: (numpieza)→ PIEZA,
Clave Ajena: (numvend)→ VENDEDOR
PEDIDO
( numpedido NUMBER(5),
numvend NUMBER(4),
fecha DATE )
Clave Primaria: (numpedido)
Clave Ajena: (numvend)→ VENDEDOR
LINPED
( numpedido NUMBER(5),
numlinea NUMBER(2),
numpieza VARCHAR2(16),
preciocompra NUMBER(9,2),
cantpedida NUMBER(4),
fecharecep DATE,
cantrecibida NUMBER(4))
Clave Primaria: (numpedido, numlinea)
Clave Ajena: (numpedido)→ PEDIDO
Clave Ajena: (numpieza)→ PIEZA
INVENTARIO
( numpieza VARCHAR2(16),
numbin NUMBER(10),
cantdisponible NUMBER(5),
fecharecuento DATE,
periodorecuen NUMBER(2),
cantminima NUMBER(5) )
Clave Primaria: (numbin)
Clave Alternativa: (numpieza)
Clave Ajena: (numpieza)→ PIEZA
PIEZA
Clave Primaria: (numpieza)
La base de datos pretende reflejar la política de compras de una empresa de distribución. Se
compran (tablas PEDIDO y LINPED) ciertas mercancías a los distintos proveedores (tabla
VENDEDOR) y son vendidas posteriormente al público o a otros distribuidores (que no hemos
considerado en la BD)
Básicamente, las tareas que se pretenden mecanizar son las siguientes (entre paréntesis
aparecen las tablas directamente relacionadas con cada una):
•
Lista de suministradores (vendedor).
Los datos de los proveedores que nos suministran la mercadería que, posteriormente,
es vendida al público en general.
•
Catálogo de venta (pieza)
Las piezas que distribuye nuestra empresa y el precio de venta al público de las
mismas.
14
•
Lista de precios de suministro (preciosum, vendedor, pieza).
Conocer los precios a los que los proveedores nos podrían suministrar las piezas. Es
información histórica cuyo origen no nos preocupa. No se debe confundir esta
información con la de los pedidos: los artículos almacenado en preciosum puede que
no se hayan pedido nunca y, si se ha hecho, que hayan sido comprados a un precio
distinto porque se negociara en ese instante con cualquiera de los suministradores.
•
Control de pedidos (pedido, linped, vendedor, pieza).
De aquellas mercancías que se solicitan a los proveedores, controlar si se han servido
en el tiempo estimado y en la cantidad pedida.
Cada pedido consta de:
• Cabecera de pedido (tabla pedido), donde se especifica qué vendedor nos ha
suministrado el pedido completo, y la fecha en que se realizó el pedido.
• Líneas de pedido (tabla linped), donde un conjunto de líneas pertenecientes a un
mismo pedido se numeran desde la número 1 en adelante. Contiene el código de
pieza que sirvió el proveedor, la cantidad que se le pidió y la cantidad que
realmente ha servido a nuestra empresa y la fecha en la que se recibió, así como el
precio al que se le compro (puede ser diferente al estipulado en preciosum).
Sólo aquellas piezas que aparezcan en una línea de pedido han sido solicitadas al
correspondiente vendedor y, si la cantidad recibida es mayor que cero, habrán sido
recibidas por la empresa en esa cantidad.
•
Control de existencias (inventario, pieza).
Mediante la confección de un inventario, donde cada entrada, que corresponde a un
único artículo, es el recuento real de existencias.
15
tabla VENDEDOR
numvend
1
2
3
4
5
6
7
8
9
10
11
12
13
8001
8002
8003
100
101
102
200
55
201
nomvend
AGAPITO LAFUENTE
DEL CORRAL
LUCIANO BLAZQUEZ
VAZQUEZ
GODOFREDO MARTIN
MARTINEZ
JUANITO REINA
PRINCESA
JUANITO REINA
PRINCESA
MANOLO PIEDRA
POMEZ
MANUEL PEREZ
RODRIGUEZ
LUISA PINTO HEREDIA
CHEMA PAMUNDI
GUSTAVO DE BASICA
MARIO DUQUE
LIZONDO
JOSE ANTONIO
MARTINEZ JUAN
MANUEL GOMEZ
SANTISTEBAN
JUAN RODRIGUEZ
JUAN
JUAN MARTINEZ
GARCIA
LUIS RODRIGUEZ
SALA
PEDRO GRACIA
MORALES
SALVADOR PLA
GARCIA
SOLEDAD MARTINEZ
ORTEGA
SEVERINO MARTIN
MARTINEZ
LUIS GARCIA
SATORRE
MANUEL ORTUÑO
LAFUENTE
nombrecomer
telefono
calle
Ciudad
provincia
MECEMSA
96-5782401
Avda. Valencia 3205
ALICANTE
ALICANTE
HARW S.A.
96-3232321
GENERAL LACY, 15 2
B
ALICANTE
ALICANTE
MECEMSA
96-4141722
AVDA. VALENCIA 3372
ALICANTE
ALICANTE
HARW S.A.
903-696969
LO ANGELE
LOS EU'S
LA DEAQUI
98-5363636
GIJON
ASTURIAS
HUMP S.A.
96-5660727
AVIACION 92, 3 I
SAN VICENTE
ALICANTE
DONDEQUIERAS,
1000, 13F
S. FRANCISCO DE
ASIS, 10 1
SOFTHARD
DISTRIBUIDORA S.A.
LA MEJOR S.A.
OLE ESPAÑA, S.A.
OLE ESPAÑA, S.A.
98-5696969
ARZOBISPO LOACES
999-2014455
BANESTOESSOFT S.L.
OXFORD BLUES
QUINTANAR DE LA
ORDE
NEW ORLEANS
RIVAS VACIAMADRID
RIVAS VACIAMADRID
LOUISSIANA
MADRID
MADRID
98-0101010
MOROS, 19
GIJON
ASTURIAS
OLE ESPAÑA, S.A.
3667788
COLON, 21
VALENCIA
VALENCIA
OLE ESPAÑA, S.A.
3667789
COLON, 21
VALENCIA
VALENCIA
ALMORADI
ALICANTE
HALA S.A.
HARW S.A.
3334455
CISCAR, 5
VALENCIA
VALENCIA
HARW S.A.
3335588
SALAMANCA, 102
VALENCIA
VALENCIA
SALAMANCA, 100
VALENCIA
VALENCIA
SOFT S.A.
TABAC & SOFT
5661100
MAYOR, 44
SAN VICENTE
ALICANTE
ASX. S.A.
87879998
PEREZ GALDOS, 54
ALICANTE
ALICANTE
SEVESOFT
5779988
GENERAL LACY, 17
ALICANTE
ALICANTE
HARW S.A.
5889944
POETA ALONSO, 12
ALICANTE
ALICANTE
HALA S.A.
5660788
MAYOR, 64
SAN VICENTE
ALICANTE
tabla PIEZA
numpieza
A-1001-L
C-1002-H
C-1002-J
C-400-Z
DD-0001-210
DD-0001-30
DK144-0001
DK144-0002-P
FD-0001-144
FD-0002-720
M-0001-C
M-0002-C
M-0003-C
O-0001-PP
O-0002-PP
P-0001-33
T-0001-IBM
T-0002-AT
T-0003-AT
X-0001-PC
16
TOLEDO
nompieza
MOUSE ADL 3B
FILTRO PANTALLA X200
DISCO DURO WESTERN DIG 210M 28
DISCO DURO 30M SEAGATE
DISKETTE 1.44 PANASONIC
PACK DISKETTE 144 PANASONIC
FLOPPY 1.44 IBM
FLOPPY 720K IBM
MONITOR SYNCMASTER 3 COLOR
MONITOR COLOR SONY BT
MONITOR IBM 3570 COLOR
PEGATINAS CONCIERTO JEVI
PACK PEGATINAS CONCIERTO JEVI
PLACA INTEL 33Mz
TECLADO XT IBM
TECLADO AT SUSUSU
TECLADO AT HP
TECLADO ESTANDAR PC
preciovent
7,00
4,00
7,00
18,00
250,00
200,00
1,10
10,00
180,00
150,00
170,00
350,00
400,00
20,00
100,00
350,00
110,00
55,00
120,00
70,00
tabla PEDIDO
numpedido
1
2
3
4
5
6
7
numvend
1
1
2
2
1
5
8002
fecha
05/05/1992
11/10/1992
15/10/1992
16/10/1992
22/10/1992
22/08/1995
02/10/1992
tabla LINPED
numpedido
1
1
1
1
1
2
2
3
3
4
5
6
6
7
numlinea
1
2
3
4
5
1
2
1
2
1
1
1
2
1
numpieza
M-0001-C
P-0001-33
FD-0001-144
DD-0001-210
T-0002-AT
DK144-0002-P
T-0002-AT
DD-0001-210
P-0001-33
O-0002-PP
T-0002-AT
O-0001-PP
O-0002-PP
C-400-Z
preciocompra
300,00
210,00
135,00
150,00
31,00
5,45
30,00
146,00
210,00
99,00
15,00
15,00
99,00
7,00
cantpedida
10
20
20
20
22
100
1
15
3
10
15
1000
2000
45
fecharecep
10/05/1992
10/05/1992
10/05/1992
10/05/1992
17/10/1992
15/10/1992
15/10/1992
17/10/1992
17/10/1992
17/10/1992
11/06/1993
25/08/1995
25/08/1995
09/10/1992
cantrecibida
10
18
20
20
22
101
1
15
3
10
13
1000
1998
8
tabla INVENTARIO
numpieza
DD-0001-30
P-0001-33
O-0002-PP
M-0001-C
M-0003-C
DD-0001-210
FD-0001-144
numbin
1
2
3
4
5
6
7
cantdisponible
120
10
110
15
2
10
10
fecharecuento
15/10/1990
15/10/1992
15/10/1992
15/10/1992
20/10/1992
12/11/1992
12/11/1992
periodorecuen
1
1
2
1
2
2
cantminima
15
5
3
2
0
1
0
17
tabla PRECIOSUM
numpieza
A-1001-L
A-1001-L
A-1001-L
A-1001-L
C-1002-H
C-1002-J
C-400-Z
C-400-Z
DD-0001-210
DD-0001-210
DD-0001-210
DD-0001-30
DK144-0001
DK144-0002-P
DK144-0002-P
FD-0001-144
FD-0001-144
FD-0001-144
FD-0002-720
M-0001-C
M-0001-C
M-0002-C
M-0002-C
M-0003-C
M-0003-C
M-0003-C
O-0001-PP
O-0001-PP
O-0001-PP
O-0002-PP
O-0002-PP
O-0002-PP
O-0002-PP
P-0001-33
P-0001-33
P-0001-33
P-0001-33
P-0001-33
T-0001-IBM
T-0001-IBM
T-0001-IBM
T-0002-AT
T-0002-AT
T-0002-AT
T-0002-AT
T-0002-AT
T-0002-AT
T-0003-AT
T-0003-AT
18
numvend
3
4
100
1
1
1
1
8002
1
2
101
1
1
1
2
1
102
55
1
1
3
9
1
3
4
1
5
55
1
2
5
101
1
2
1
4
3
5
2
100
1
1
2
4
5
100
201
1
3
preciounit
5,00
4,90
4,00
2,00
0,50
1,50
8,50
7,00
150,00
170,00
140,00
120,00
0,56
5,60
5,50
130,00
136,00
120,00
60,00
155,00
180,00
300,00
150,00
350,00
280,00
200,00
19,50
15,00
15,00
99,00
98,75
80,00
75,00
210,00
250,00
280,00
250,00
280,00
90,00
95,00
90,00
30,00
35,00
25,00
33,00
34,00
30,00
77,50
81,45
diassum
1
1
3
3
2
2
4
3
3
5
15
4
3
3
5
3
3
10
3
3
7
1
10
2
7
7
1
7
1
1
1
10
1
5
3
7
2
3
5
5
15
3
5
7
3
2
1
3
descuento
5
15
12
14
7
13
10
15
5
15
15
12
10
10
7
5
5
CONSULTAS SELECT1
1.
Obtener todos los números de piezas de las piezas de la base de datos.
2.
Nombre de todas las piezas con un precio de venta menor que 1000.
3.
Número, nombre y precio de venta de las piezas de precio de venta mayor que 10 o
menor que 1 euros, ordenadas de menor a mayor precio.
4.
Para cada pieza de la que se conozca algún suministrador, obtener el número de pieza y
el descuento, en orden descendente del valor de descuento.
5.
Nombre de los vendedores con número de vendedor menor que 6.
6.
Modificar el requerimiento anterior para eliminar duplicados.
7.
Número y nombre de los vendedores con número de vendedor menor que 6.
8.
Obtener todos los números de los vendedores de los que se sepa que pueden suministrar
alguna pieza.
9.
Vendedores de la provincia de Alicante.
10. Nombre y empresa de los vendedores de la Comunidad Valenciana.
11. Números de vendedores y días que tardarían en suministrar la pieza 'P-0001-33'
12. Códigos de pieza solicitados en el pedido 1, ordenados de mayor a menor precio de
compra.
13. Números de pedido y números de vendedor, para los pedidos solicitados el 15 de octubre
de 1992.
14. Códigos de pieza de los que se sabe que algún vendedor nos podría hacer descuento.
15. Códigos de pieza, de posible suministrador y precio de suministro, ordenados por código
de vendedor y código de pieza.
19
20
select 2
CONSULTAS SOBRE
VARIAS TABLAS
Objetivos:
• Poder relacionar distintas tablas de la BD para obtener información más compleja.
Contenidos
• Utilización de más de una tabla.
• Nombres cualificados de atributo.
• Sinónimos temporales de tabla.
• Tipos de datos: dominios.
• Resolución de requerimientos
UTILIZACIÓN DE MÁS DE UNA TABLA
Para la resolución de la mayoría de requerimientos es necesario trabajar con información que
se obtiene de relacionar varias tablas. La forma de especificar qué tablas vamos a consultar es
construir una lista de nombres de tablas en la cláusula FROM.
Si seleccionamos la BD Ejemplo, podemos preguntar por el nombre de los profesores y la
descripción de las asignaturas que imparten; esta información se encuentra almacenada en la
tabla imparte, que relaciona las claves primarias de cada una de las tablas asociadas por tal
relación.
select nombre, descripcion
from asignaturas, imparte, profesores
where
profesores.dni = imparte.dni
and asignatura = codigo
resultado:
nombre
EVA GOMEZ
EVA GOMEZ
RAFAEL ROMERO
descripcion
Fundamentos de las Bases de Datos
Diseño y Gestión de Bases de Datos
Programación Concurrente
En primer lugar, solicitamos nombre (del profesor) y descripcion (de la asignatura). El primer
atributo se encuentra en la tabla profesores, y el segundo en la de asignaturas. La relación entre
ambas tablas se encuentra en la tabla imparte, que asocia dni de profesor con codigo de
asignatura que imparte. Así, para obtener la información que precisamos, necesitamos involucrar
a las tres tablas al mismo tiempo.
Podemos pensar, por clarificar el mecanismo por el que se obtiene este resultado, que el SGBD
recorre la tabla de profesores, tupla por tupla, y busca el valor de dni de cada una en la tabla
imparte. Si encuentra tal valor, en esa tupla de imparte en que lo ha encontrado, aparecerá el
código de asignatura, en la columna nominada como asignatura; buscando en la tercera tabla,
asignaturas, obtendrá la descripcion y finalmente mostrará en pantalla el nombre y la descripción
que le corresponde.
21
Nótese que no aparece MANUEL PALOMAR, o la asignatura HISTORIA DE LA INFORMÁTICA,
puesto que ni el primero (en nuestra BD) imparte asignatura alguna, ni la segunda es impartida
por ningún profesor (de los conocidos por nuestro sistema).
¿Qué pasaría si no utilizáramos la cláusula where para enlazar las tablas? Supongamos el
siguiente requerimiento:
select asignatura, nombre
from profesores, imparte
resultado:
asignatura
FBD
FBD
FBD
DGBD
DGBD
DGBD
PC
PC
PC
nombre
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
Si no indicamos nada en la cláusula where la información que obtenemos es simplemente la
combinación de cada tupla con todas las demás: si hay 3 tuplas en imparte y otras 3 en
profesores, la cardinalidad de la relación resultante es 3 x 3 = 9 tuplas. Si en la cláusula from
pusiéramos, además, la tabla asignaturas, el resultado final tendría 3 x 3 x 5 = 45 tuplas.
Veamos en detalle como funciona la orden select-from-where para el caso de la siguiente
consulta (códigos de asignaturas y nombre de los profesores que las imparten)1:
select asignatura, nombre
from profesores, imparte
where profesores.dni = imparte.dni
resultado:
asignatura
FBD
DGBD
PC
nombre
EVA GOMEZ
EVA GOMEZ
RAFAEL ROMERO
El SGBD primero combinaría todas las tuplas con todas de las tablas especificadas en el from:
dni
21111222
21222333
21333444
21111222
21222333
21333444
21111222
21222333
21333444
1
nombre
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
categoria
TEU
TEU
ASO6
TEU
TEU
ASO6
TEU
TEU
ASO6
ingreso
01/10/1993
16/06/1989
16/06/1992
01/10/1993
16/06/1989
16/06/1992
01/10/1993
16/06/1989
16/06/1992
dni
21111222
21111222
21111222
21111222
21111222
21111222
21333444
21333444
21333444
asignatura
FBD
FBD
FBD
DGBD
DGBD
DGBD
PC
PC
PC
Esto no es necesariamente real, una de las ventajas de utilizar un SGBD es que las consultas se
procesan de manera eficiente y de forma totalmente transparente para el usuario.
22
Por lo especificado por la where eliminaría aquellas tuplas que no cumplieran la condición, y
nos quedaría:
dni
21111222
21111222
21333444
nombre
EVA GOMEZ
EVA GOMEZ
RAFAEL ROMERO
categoria
TEU
TEU
ASO6
ingreso
01/10/1993
01/10/1993
16/06/1992
dni
21111222
21111222
21333444
asignatura
FBD
DGBD
PC
Y por último, las columnas especificadas en la select determinarían el resultado final:
asignatura nombre
FBD
DGBD
PC
EVA GOMEZ
EVA GOMEZ
RAFAEL ROMERO
NOMBRES CUALIFICADOS DE ATRIBUTO
Si observamos la sentencia select anterior, al comparar los dni que aparecen en profesores y
en imparte hemos utilizado el nombre de la tabla a la que pertenecen cada uno, profesores.dni e
imparte.dni.
Si en el conjunto de columnas de todas las tablas que se especifican en la cláusula from
existen varias con nombres iguales, deberemos especificar en todo momento la tabla de la que
queremos extraer la información. Caso de no existir ambigüedad, no es necesario utilizar el
nombre de la tabla; ni asignatura ni codigo se utilizan en otras tablas.
Si deseamos conocer el dni y el nombre de los profesores que imparten alguna asignatura,
buscaremos en imparte los dni de los profesores (son los que tienen al menos una asignatura
asignada), y con este valor obtendremos el nombre en profesores.
select dni, nombre from profesores, imparte
where profesores.dni = imparte.dni
resultado:
ERROR
Al especificar que nos muestre en pantalla el dni del profesor, el SGBD entra en conflicto
puesto que no sabe si nos referimos al de la tabla profesores o al de la tabla imparte. Utilizaremos
el nombre completo de la columna (es indiferente, en este caso, de qué tabla):
select profesores.dni, nombre from profesores, imparte
where profesores.dni = imparte.dni
resultado:
dni
21111222
21111222
21333444
nombre
EVA GOMEZ
EVA GOMEZ
RAFAEL ROMERO
Se recuerda que la ocurrencia EVA GOMEZ está relacionada con dos asignaturas, y es por eso que aparece duplicada
en este resultado. La forma de evitar tuplas idénticas ya se mostró en la sesión anterior.
23
SINÓNIMOS TEMPORALES DE TABLA
Para facilitar la escritura de las sentencias select (entre otros posibles motivos) se pueden
utilizar alias temporales, nombres alternativos de las tablas. Se especifican en la lista de tablas del
from, antes de la “,” que separa el nombre de la tabla en cuestión de la siguiente.
select distinct p.dni, nombre
from profesores p, imparte i
where p.dni = i.dni
resultado:
dni
21111222
21333444
nombre
EVA GOMEZ
RAFAEL ROMERO
CONSULTAS SELECT2
1.
Obtener el número de pieza junto con el nombre de todas las provincias desde las que
puede sernos suministrada, en orden descendente del número de pieza.
2.
Modificar el requerimiento anterior para eliminar duplicados.
3.
Lista el nombre y número de las piezas.
4.
Obtener el nombre y número de proveedores de la provincia de Valencia.
5.
Obtener el nombre y número de proveedores de la provincia de Valencia a los que se les
ha solicitado un pedido.
6.
Obtener los números de línea y su precio de compra del pedido número 1.
7.
Obtener todas las piezas que se recuenten el 15 /10/1992.
8.
Obtener número y nombre de todas las piezas recibidas el 1 de Mayo de 1992.
9.
Precio unitario de suministro del número de pieza A-1001-L y el vendedor 100.
10. Nombres de proveedores que puedan suministrarnos la pieza numero A-1001-L
11. Obtener nombre, teléfono, y ciudad del vendedor que puede suministrarnos piezas con
valor mayor de 100.
12. Obtener los vendedores que pueden suministrarnos piezas con un descuento de más de
10%.
13. Obtener los números de pedido del vendedor número 1.
14. Obtener los vendedores ordenados alfabéticamente en orden descendente.
15. Ídem en orden ascendente.
16. Obtener los números de pieza de las que conozcamos algún vendedor que nos la pueda
suministrar.
17. Número y nombre de las piezas que puedan suministrarnos el vendedor número 2 y el 4
(no necesariamente que las puedan suministrar los dos).
18. Piezas que nos puedan suministar los vendedores de la empresa Harw S.A.
24
19. Número, nombre y precio de venta de las piezas que han sido compradas en un pedido
servido por el vendedor 1.
20. Número y nombre de vendedor, y pieza que ha sido comprada a un precio mayor que el
estipulado en la lista de precios de suministro.
21. Número de pieza y número y nombre de vendedor de aquellas piezas cuyo precio de
venta es mayor que 50 o su descuento de suministro es mayor que 10.
22. Pedidos y datos del vendedor cuya fecha de pedido no sea el 22 de octubre de 1992.
23. Precios a los que nos pueden ser suministradas las piezas DD-0001-210 y FD-0001-144, y
número y nombre de los vendedores que las podrían suministrar a esos precios.
25
26
select 3
EXPRESIONES DE
SELECCIÓN DE FILAS
Objetivos:
• Comparaciones de cadenas de caracteres.
Contenidos
• BETWEEN, IN
• LIKE, subcadenas.
Construcción de expresiones de selección de filas utilizando rangos, listas, y funciones de
comparación de cadenas de caracteres.
RANGOS
Expresiones del tipo 10 <= x <= 100 se pueden construir utilizando el operador de
construcción de rangos BETWEEN.
La sintaxis de tal subexpresión de la cláusula where es la siguiente:
expresión [NOT] BETWEEN expresión AND expresión
Por ejemplo, deseamos conocer los créditos y descripción de las asignaturas cuyo número de
créditos está entre 5 y 8.
select creditos, descripcion from asignaturas where creditos between 5 and 8
resultado:
creditos
6
6
6
descripcion
Fundamentos de las Bases de Datos
Diseño y Gestión de Bases de Datos
Programación Concurrente
LISTAS
Mediante el operador IN se puede buscar un determinado valor en una lista construida usando
constantes.
expresión [NOT] IN (listaValores)
27
Descripción de las asignaturas FBD y DGBD:
select descripcion from asignaturas where codigo in ('FBD', 'DGBD')
resultado:
descripcion
Fundamentos de las Bases de Datos
Diseño y Gestión de Bases de Datos
Nombre de los profesores que no imparten HI, FBD o DGBD:
select nombre from profesores p, imparte i
where p.dni = i.dni and asignatura not in ('HI', 'FBD', 'DGBD')
resultado:
nombre
RAFAEL ROMERO
Fijémonos en que MANUEL PALOMAR, que no imparte ninguna de las asignaturas objeto de la
búsqueda, tampoco aparece en la tabla resultado puesto que su dni no aparece en la tabla
IMPARTE.
SUBCADENAS DE CARACTERES
Podemos preguntar por subcadenas dentro de columnas de tipo carácter. Para ello utilizaremos
los operadores LIKE o MATCHES, que soportan la siguiente sintaxis:
columna [NOT] LIKE 'cadena'
La cadena de caracteres cadena admite los comodines % y _ , equivalentes en uso a los
comodines de MS-DOS * y ?, es decir, el primero indica una cadena de caracteres de cualquier
longitud, y el segundo un carácter cualquiera.
Profesores que atiendan al nombre de 'RAFA':
select * from profesores
where nombre like 'RAFA%'
resultado:
dni
21333444
nombre
RAFAEL ROMERO
Código de las asignaturas de 'Bases de Datos'
select codigo from asignaturas
where descripcion like '%BASES DE DATOS%'
resultado:
28
codigo
FBD
DGBD
categoria
ASO6
Código de las asignaturas, siendo tal código de 2 caracteres:
select codigo from asignaturas
where codigo like '__ '
(2 subrayados seguidos de 3 espacios en blanco: codigo es un CHAR(5)
resultado:
codigo
HI
PC
FP
VALORES NULOS
Podemos interrogar a la BD de datos en busca de valores desconocidos
(información faltante) mediante el operador IS NULL, cuya sintaxis es:
columna IS [NOT] NULL
Código y créditos de las asignaturas de las que conocemos su número de créditos:
select codigo, creditos from asignaturas
where creditos is not null
resultado:
codigo
creditos
HI
FBD
DGBD
PC
FP
4.5
6
6
6
9
RESUMEN DE OPERADORES
Recopilamos todos los operadores y conectivas lógicas vistos hasta ahora para la construcción
de expresiones condicionales:
=
>
<
>=
<=
<>
IS NULL
AND
OR
NOT
BETWEEN
IN
LIKE {%,_}
29
CONSULTAS SELECT3
1.
Obtener el nombre de las piezas que puedan ser suministradas por aquellos proveedores
cuyo nombre empiece por S.
2.
Obtener el nombre de las piezas que puedan ser suministradas por proveedores cuyo
nombre empiece por S, y se llamen de apellido2 Martínez o Martín.
3.
Obtener los nombres de los vendedores de las provincias de Valencia, Castellón o
Alicante.
4.
Nombres de vendedores que empieza su nombre por J.
5.
Nombres de vendedores que termina su nombre por Z.
6.
Nombres de vendedores que se apellidan López.
7.
Nombre de vendedores que el nombre empieza por M seguido de cualquier carácter
simple, una R y cualquier cadena de n caracteres.
8.
Obtener los vendedores de la provincia de Valencia o Alicante que su nombre empieza por
J o por M y tienen un número de vendedor entre 1 y 100.
9.
Listar los nombres y números de vendedores así como el número y nombre de las piezas
que pueden suministrar, para los vendedores de la provincia de Valencia o Alicante.
10. Obtener los nombres de pieza que pueden suministrar los vendedores de apellido 'García'.
11. Piezas3 que sabemos que nos puede suministrar algún vendedor.
12. Obtener todos los vendedores que tengan teléfono.
13. Listar las piezas con un descuento entre 1 y 10 cuyo nombre contenga una O y que se las
hayamos solicitado a proveedores cuyo número oscile entre el 1 y el 1000.
14. Obtener los nombres de vendedores en orden alfabético.
15. Obtener nombre de vendedores y nombre de piezas que pueden suministrar ordenado en
orden alfabético.
16. Obtener todos los nombres de piezas que pueda suministrar el vendedor 100, el 300 y/o
el 400 con un precio de venta entre 10 y 1000, y un precio unitario entre 1 y 500.
17. Obtener el número de pieza y el precio de los monitores.
18. Nombre de las piezas que pueden sernos suministradas desde la Comunidad Valenciana.
19. Obtener los vendedores que viven en la calle Ciscar o Salamanca y de la Empresa Harw
S.A.
20. Obtener nombres de vendedores y números de pieza que nos pueden suministrar, de
aquellos vendedores cuyo apellido comienza por Martín, y ordenados alfabéticamente.
2
Evidentemente, la BD no diferencia entre nombre y apellido primero y segundo, por lo que se ha de
tratar como subcadenas dentro del valor del atributo.
3
Cuando no se especifica un atributo concreto, se entiende que se pide toda la información disponible
en la BD de los objetos solicitados.
30
select fecha
FUNCIONES DE FECHA4
Objetivos:
• Construir condiciones de selección de filas utilizando atributos de tipo fecha.
Contenidos
• TO_CHAR()
• TO_DATE()
• SYSDATE
• ADD_MONTHS()
• MONTHS_BETWEEN()
FUNCIONES DE FECHA
Se presentan a continuación distintas funciones de manejo de fechas y hora, que se pueden
utilizar tanto en la lista de columnas que aparecerán en la tabla resultado de la select como en la
construcción de expresiones de la where.
En general, la comparación entre fechas se hace directamente. Por ejemplo:
select nombre from profesores where ingreso < '23/12/1989';
select nombre from profesores where ingreso < '23/12/1989'’
resultado:
nombre
MANUEL PALOMAR
Pero si necesitamos hacer transformaciones sobre un determinado dato (extraer parte de una
fecha, cambiar el formato de visualización, calcular días, etc.) entonces debemos ayudarnos de
estas funciones.
TO_CHAR(fecha [, formato])
Convierte la fecha de tipo DATE a un valor VARCHAR2
en el formato especificado en "formato"
Convierte la cadena de caracteres "cadena" de tipo
TO_DATE(cadena [, formato]) CHAR a un valor de tipo DATE con el formato
especificado en "formato"
SYSDATE Devuelve la fecha actual del sistema
ADD_MONTHS(fecha,n) Devuelve la fecha especificada con n meses más
MONTHS_BETWEEN(fecha1,fecha2) Devuelve los meses transcurridos entre fecha1 y fecha2
4
Aunque todas las demás sesiones de prácticas cumplen con el estándar SQL, los tipos de datos de
fecha y hora y las funciones que los manejan no suelen estar igualmente implementadas en todos los
SGBD, por lo que esta sesión es únicamente aplicable a Oracle.
31
FORMATOS DE FECHA
Las funciones TO_CHAR() y TO_DATE() admiten distintos formatos de fecha que se pueden
construir según una máscara especificada por el usuario. Dicha máscara es una cadena de
caracteres entre comillas simples en la que se pueden utilizar los siguientes:
ELEMENTO
- / ' . ; : 'texto'
D
DAY
DD
DY
MM
MON
MONTH
Q
YYYY
Y,YYY
YY
SIGNIFICADO
Marcas de puntuación y texto fijo que se reproduce en el resultado
Día de la semana (1-7)
Nombre del día de la semana
Día del mes (1-31)
Día del año (1-366)
Mes (1-12)
Nombre abreviado del mes
Nombre completo del mes
Cuatrimestre del año (1-4)
Año con 4 dígitos
Año con punto de millar
Año con 2 dígitos
Por ejemplo:
select nombre, to_char (ingreso,'DD') from profesores where to_char(ingreso,'DD') < 15
select * from profesores where to_char(ingreso,'MM') < 6
select * from profesores where ingreso = sysdate
Para obtener el número de días entre dos fechas basta con utilizar la operación resta
select nombre, sysdate-ingreso from profesores
CONSULTAS SELECT FECHA
1.
Obtener el número de pieza de las piezas que se recuenten el 15/10/92.
2.
Números de pieza de las piezas que se recuentan entre el 1 de Octubre de 1992 y el 31
de Octubre de 1992.
3.
Número y fecha de los pedidos solicitados en el segundo semestre del 92.
4.
Nombre de los vendedores que sirvieron piezas en la primera quincena de mayo del 92,
ordenado alfabéticamente.
5.
Número, nombre de vendedor y mes en que se les solicitó un pedido de discos duros.
6.
Años en que se ha efectuado algún recuento.
7.
Número y descripción de las piezas que sirvieron los proveedores los días 10 de cada mes.
8.
Número y descripción de las piezas que sirvieron los proveedores en el 95 y cuyo precio
de compra es superior al precio de suministro que ellos ofertaban.
9.
Número de pieza, descripción, fecha de recepción, cantidad recibida, de las piezas
recibidas en el 95 y de precio de venta entre 50 y 100 euros.
32
create
DEFINICIÓN DE DATOS
Objetivos:
• Introducir al alumno a la definición de datos.
Contenidos
• Las órdenes CREATE TABLE y DROP TABLE
• Restricciones
• La orden INSERT (1)
• Información sobre las restricciones de una tabla
IMPORTANTE
Para ésta y las sesiones que traten de crear y borrar tablas, e insertar, modificar o eliminar
datos, es necesario entrar al sistema con un usuario con permisos suficientes y diferente para
cada puesto (si dos alumnos entraran con el mismo usuario estarían trabajando en el mismo
espacio de trabajo y colisionarían al crear y mantener sus tablas). Por ello, se debe iniciar la
sesión como:
usuario:
bdixx
contraseña: bdixx
servicio:
oracle
donde xx es el número del ordenador en el aula (01, 02, ..., 10, 11, ... 25 ...)
Dado que el número de usuarios es limitado, al terminar cada grupo de prácticas, los usuarios
serán “limpiados” por lo que los datos manejados durante la sesión serán borrados y no estarán
disponibles para las semanas siguientes.
LA ORDEN CREATE TABLE
La definición de tablas es el primer paso en la creación de una base de datos. El conjunto de
descripciones de tablas conforma el esquema de base de datos y representa a un sistema de
información concreto.
Supongamos que vamos a implementar un esquema de base de datos relacional de profesores,
asignaturas (sólo es un listado de profesores y asignaturas, sin relaciones entre ellos). En primer
lugar debemos decidir cuáles son los atributos de cada uno de ellos y sus tipos de datos:
PROFESORES
(DNI: varchar2(10),
nombre: varchar2(40),
categoria: char(4),
ingreso: datetime)
ASIGNATURAS
(codigo: char(5),
descripcion: varchar2(35),
creditos: number(3,1)
creditosp: number(3,1))
Para cumplir con las restricciones del modelo relacional, además, debemos elegir las claves
primarias adecuadas5: DNI para profesores y codigo para asignaturas. Obviamente, la forma que
tienen estas tablas ha sido una decisión nuestra como diseñadores de esta base de datos
concreta, en otra situación hubiéramos, probablemente, decidido definir otros atributos y otras
tablas.
La orden CREATE TABLE nos permite crear cada una de las tablas necesarias para nuestra
base de datos:
CREATE TABLE nombreTabla ( {listaColumnas} [,{restricciones}] )
La lista de columnas, en su forma más sencilla, es un conjunto de expresiones (tantas como
columnas deseemos, y separadas por comas) del tipo:
columna tipoDatos[,columna tipoDatos[, ...]]
RESTRICCIONES
Las restricciones son reglas, que normalmente se establecen en el momento de crear una
tabla, para garantizar la integridad de los datos.
Básicamente, las restricciones obligan a cumplirse ciertas reglas cuando una fila es insertada,
borrada o modificada, de forma que la operación se llevará a efecto sólo si se cumplen las
restricciones definidas en la tabla.
Podemos contemplar los siguientes tipos de restricciones de integridad de datos:
•
NOT NULL: especifica que la columna no puede contener un valor nulo.
•
PRIMARY KEY: identifica de manera única a cada fila de la tabla mediante una o varias
columas, estas columnas que forman la clave primaria no pueden tener valores nulos.
•
FOREIGN KEY: establece una relación entre una(s) columna(s) de la tabla y otra(s)
columna(s) de la tabla referenciada, siendo esta última(s) columna(s) la PRIMARY KEY.
•
CHECK: especifica una condición que se debe evaluar a “cierto”.
De las restricciones, sólo vamos a utilizar, de momento, la clave primaria, que puede contener
tantas columnas como se necesiten:
PRIMARY KEY (columna[,columna[, ...]])
5
Todos los SGBDR permiten crear tablas sin restricciones de clave primaria, pero un correcto diseño de
bases de datos incluirá claves ajenas que no se pueden definir si no existen sus correspondientes
claves primarias. Las claves ajenas se introducen en la siguiente sesión.
35
Por ejemplo:
create table profesores (DNI varchar2(10), nombre varchar2(40), categoria char(4),
ingreso date, primary key (DNI));6
create table asignaturas (codigo char(5), descripcion varchar2(35), creditos number(3,1)
creditosp number(3,1), primary key (codigo))7
resultado:
1 tabla creada
1 tabla creada
Ahora ya podemos ejecutar una consulta sobre cualquiera de estas dos tablas:
select * from profesores
resultado: ninguna fila seleccionada
El resultado de la creación es una tabla vacía, sin filas, lista para insertar datos en ellas (orden
insert, a continuación). Al crear una tabla, el resultado es persistente, la tabla no “desaparece”
cuando nos desconectamos del servidor (tampoco los datos que almacenamos en ella). Si
queremos borrar una tabla debemos ordenárselo al SGBD mediante la orden DROP TABLE:
DROP TABLE nombreTabla
Por ejemplo:
drop table asignaturas
resultado:
1 tabla borrada
Al utilizar esta orden nótese que también se eliminan los datos (las filas) que pudiera contener.
Ahora podríamos volver a crear la tabla (sin filas), con los mismos o diferentes atributos, y volver
a borrarla, y...
LA ORDEN INSERT
Para introducir datos nuevos en una base de datos vamos a utilizar la orden INSERT de SQL.
Con la sintaxis que se muestra a continuación seremos capaces de introducir datos nuevos en
cualquiera de las tablas que componen una determinada BD. En principio, veremos la expresión
mínima de la orden, formada por dos cláusulas, into y values.
INSERT INTO nombreTabla
VALUES ( listaExpresiones )
Supongamos que en la base de datos anterior queremos dar de alta un nuevo profesor. Si
dicho profesor tiene como dni el “55555555”, nombre “PATRICIO MARTÍNEZ”, categoría “TU” y
fecha de incorporación “01/01/2000”, deberíamos ejecutar la siguiente orden.
6
Para facilitar su uso, los nombres de tabla y las columnas no deben incluir acentos o caracteres no
habituales
7
El “punto y coma” es necesario para informar a Oracle de que una orden ha de ejecutarse y que, a
continuación, se va a ejecutar otra orden distinta. Si sólo se escribe una orden no hace falta este
caracter. No obstante, por la implementación del cliente Worksheet, se aconseja terminar todas las
órdenes con punto y coma, incluso si sólo es una.
36
Insert into profesores values (‘55555555’,’PATRICIO MARTINEZ’,’TU’,’01/01/2000’);
resultado:
1 fila creada
Sólo se puede indicar una tabla en la que introducir datos, no se permite una lista de nombres
de tabla para introducir datos en varias tablas a la vez. Para introducir datos en n tablas, habrá
que ejecutar n sentencias INSERT.
insert into profesores, asignaturas
values (‘55555555’,’PATRICIO MARTINEZ’,’TU’, ’01/01/2000’,
‘BdI’,’BASES DE DATOS I’,6,0);
resultado:
ERROR falta la palabra clave values
Lo mismo ocurre con las filas, sólo se puede indicar una lista de valores. Esto quiere decir que
hay que ejecutar una orden insert por cada una de las filas que queramos almacenar en una tabla
insert into profesores
values (‘66’,’ERNESTO PEREZ’,’ASO6’, ’10/10/2001’);
resultado:
1 fila creada
Resultado
El resultado que devuelve una orden INSERT, será siempre el número de filas insertadas, en el
caso de que la ejecución haya sido correcta. Para los casos en que la ejecución de la sentencia
viole alguna restricción de la BD y por tanto, su ejecución no sea correcta, el resultado indicará
cuál es la restricción violada.
El SGBD, cada vez que insertamos un nuevo dato en una tabla, se encarga de verificar las
restricciones activas, en nuestro caso las claves primarias, que como sabemos, no admiten valores
duplicados, ni valores nulos.
insert into profesores
values (‘66’,’PEPITO’,’XXX’, ’11/11/2006’);
resultado: ERROR restricción única (BDI.SYS_C0033923) 8 violada
VALUES
Si no se va a dar valor a todas las columnas de la tabla se deberá indicar las columnas a las
que se les dará valor. Así, si por ejemplo, sólo supiéramos el dni y el nombre del profesor que
queremos dar de alta, ejecutaríamos la sentencia siguiente
Insert into profesores (dni, nombre) values (‘88888888’, ‘ARMANDO SUAREZ’);
resultado:
1 fila creada
Es recomendable acostumbrarse a poner siempre las columnas a las que se va a dar valor,
sean o no todas las de la tabla. Las razones que lo aconsejan son:
8
Nombre de la restricción.
37
• No habrá que fijarse en si se va a dar valor a todas o sólo a alguna de las columnas para
acomodar la sintaxis de la sentencia INSERT.
• Si por alguna razón se modifica la estructura de una tabla, es decir, se añaden columnas
nuevas, y tenemos costumbre de no indicar las columnas cuando se inserta valor a
todas, con la modificación dejarán de funcionar las sentencias que tuviéramos escritas.
Existe la posibilidad de hacer uso del valor NULL. Puesto que NULL es la ausencia de valor, si lo
asignamos como valor a una columna de una tabla, lo que estaremos haciendo es indicar que esa
columna no tiene valor. La siguiente sentencia realiza la misma operación que la anterior.
Insert into profesores (dni,nombre,categoria,ingreso)
values (‘88888888’,’ARMANDO SUAREZ’, NULL, NULL);
resultado:
1 fila creada
La lista de valores se asigna a la lista de columnas, de forma que la primera columna toma el
primer valor, la segunda el segundo y así sucesivamente. Es decir, las dos sentencias siguientes
realizan exactamente la misma operación, aunque el orden de asignación es diferente.
Insert into profesores (dni,nombre,categoria)
values (‘88888888’,’ARMANDO SUAREZ’, NULL);
resultado:
1 fila creada
Insert into profesores (categoria,dni,nombre)
values (NULL, ‘88888888’,’ARMANDO SUAREZ’);
resultado:
1 fila creada
Ésto apoya aún más el hecho de que sea aconsejable poner siempre la lista de columnas, ya
que aún dando valor a todas las columnas de la tabla, si no las indicamos, la lista de valores
deberá seguir el orden que esas columnas tienen internamente en la tabla. Es decir, estaremos
obligados a mirar las columnas y su orden, para poder establecer el orden adecuado en la lista de
valores.
INFORMACIÓN SOBRE UNA TABLA
Recordemos que ejecutar DESC nombreTabla o DESCRIBE nombreTabla, muestra
información sobre las columnas que componen la tabla, el orden interno de las mismas en la
tabla, y sus tipos de datos.
INFORMACIÓN SOBRE LAS RESTRICCIONES
DE UNA TABLA
En el momento de crear una restricción, además de especificar las reglas que se deben
cumplir, podemos dar un nombre a la misma. Para establecer los nombres de las restricciones, se
suele seguir el siguiente convenio: ser nombres descriptivos y empezar, por ejemplo, por PK_ si se
trata de una Primary Key o por FK_ si se trata de una Foreign Key o por C_ si se trata de una
CHECK.
No vamos a profundizar más en los nombres de las restricciones ni en la sintaxis para crearlos,
pero sí que debemos saber que si no especificamos ningún nombre, Oracle asigna un nombre
único a cada restricción con el formato SYS_Cn, siendo n un valor entero.
38
La sentecia DESC sólo muestra, a nivel de restricción, si una columna determinada admite o
no nulos, pero no facilita ninguna información sobre otro tipo de restricciones.
Para obtener la información relativa a otras restricciones definidas sobre una tabla se deberá
ejecutar una consulta, sobre la tabla USER_CONSTRAINTS, del tipo siguiente:
select constraint_name, constraint_type, search_condition
from user_constraints where table_name =’nombreTabla’ 9 ;
Donde
• Constraint_name es el nombre de la restricción.
• Constraint_type puede tomar distintos valores, P indica que la restricción es de clave
primaria, R que es ajena y C una check.
• Search_condition es la condición impuesta en caso de que la restricción sea de tipo
check.
Si, por ejemplo, quisiéramos saber las restricciones definidas sobre la tabla IMPARTE,
ejecutaríamos la siguiente consulta
select constraint_name, constraint_type, search_condition
from user_constraints
where table_name =’IMPARTE’;
resultado:
9
(1)
CONSTRAINT_NAME
-----------------------------SYS_C0058701
SYS_C0058702
SYS_C0058703
C SEARCH_CONDITION
- ----------------P
R
R
nombreTabla debe indicarse en mayúsculas.
39
ÓRDENES CREATE
1.
Crea una tabla de nombre XX con 2 columnas, col1 de tipo integer, y col2 de tipo char(3),
con col1 como clave primaria.
2.
consulta la tabla
3.
inserta en la tabla la fila (1,’AA’)
4.
ejecuta insert into XX values (‘BB’,2)
5.
insert en la tabla la fila (2,’BB’)
6.
consulta la tabla XX
7.
cierra la sesión de Worksheet e identifícate de nuevo (“salte y vuelve a entrar”)
8.
comprueba que, efectivamente, los datos siguen estando ahí
9.
borra la tabla XX
10. consulta la tabla XX
11. crea una tabla YY con 3 columnas col1(integer), col2(char(2)) y col3(varchar2(10)), cuya
clave primaria sea (col1, col2)
12. inserta los siguientes datos y consulta la tabla para ver los datos almacenados
(1,’AA’,’primera’)
(2,’AA’,’segunda’)
(2,’BB’,’tercera’)
(1,’AA’,’cuarta’)
(NULL,NULL,’quinta’)
(NULL,’CC’,’sexta’)
(3,NULL,’séptima’)
(0,’’,’octava’)10
(3,’AA’,NULL)
13. crea un listín de teléfonos con los siguientes datos: apodo, nombre, teléfono; rellénala
con datos (4 filas será suficiente)
14. modifica la tabla anterior, añádele una columna más, grado de amistad, y vuelve a
rellenarla de datos
15. crea una lista de la compra y rellénala de datos
10
40
“cero”, “dos comillas simples”,”octava”
manipulación 1
MANIPULACIÓN DE
DATOS (1)
Objetivos:
• Introducir al alumno en el concepto de clave ajena, influencia de las mismas en las
sentencias Insert y Delete.
Contenidos
• La orden INSERT (2). Insertar las filas resultantes de una SELECT.
• La orden DELETE. Borrar todas las filas de una tabla. Borrar determinadas filas.
• Creación de tablas con claves ajenas.
• Influencia de las claves ajenas en la sentencia INSERT y DELETE.
Supongamos que en la BD Ejemplo existiera una tabla llamada OPTATIVAS que contuviera los
códigos y los créditos de aquellas asignaturas de carácter optativo.
Vamos a crear dicha tabla, eligiendo como clave primaria el código de la asignatura y poniendo
además otra restricción, que todas las filas tengan un valor no nulo en la columna créditos
create table optativas (asignatura char (5), creditos number(3,1) not null,
primary key (asignaturas))
LA ORDEN INSERT
Existe la posibilidad de insertar el resultado de una SELECT, en lugar de indicar la lista concreta
de valores a insertar. Esto nos permite insertar varias filas en una tabla con una sola operación,
en concreto, tantas filas como tuplas devuelva la SELECT.
INSERT INTO nombreTabla [ ( listaColumnas ) ] consulta
Supongamos que serán optativas todas las asignaturas que tengan menos de 9 créditos. Se
trata de introducir los códigos de dichas asignaturas en la tabla OPTATIVAS.
En este caso, como ya tenemos las asignaturas en la tabla ASIGNATURAS, tenemos dos
opciones. Una opción es, hacer la SELECT e ir haciendo las INSERT una a una, copiando los datos
de las filas obtenidas. Otra opción es insertar en una sola operación el resultado de la SELECT en
la tabla OPTATIVAS.
Insert into optativas (asignatura, creditos)
select codigo, creditos from asignaturas where creditos < 9;
41
resultado:
4 filas creadas
La SELECT deberá seleccionar tantas columnas como columnas pongamos en la lista de
columnas de la parte insert y los tipos de datos de las columnas seleccionadas deberán coincidir
con los tipos de datos de las columnas en las que se van a insertar esos valores.
Insert into optativas (asignatura) select codigo, creditos from asignaturas where creditos < 9;
resultado:
ERROR demasiados valores
Insert into optativas (asignatura,creditos) select codigo from asignaturas where creditos < 9;
resultado:
ERROR no hay suficientes valores
Insert into optativas (asignatura,creditos) select dni,ingreso from profesores;
resultado:
ERROR tipos de dato inconsistentes
Insert into optativas (asignatura) select codigo from asignaturas where creditos < 4;
resultado:ERROR no se puede realizar una inserción NULL en (BDI.OPTATIVAS.CREDITOS)
En esta última sentencia la restricción NOT NULL sobre la columna creditos impide que se
realice la inserción de filas, para asegurar la integridad de los datos, evitando que se pongan
valores nulos en esa columna.
Por otra parte, es importante fijarse en que la sintaxis de la sentencia INSERT no permite
utilizar a la vez una lista de valores y el resultado de una consulta.
Insert into imparte (dni, asignatura)
values (‘55555555’,select codigo from asignaturas);
resultado:
ERROR falta una expresión
Pero sí dentro de la propia orden select:
Insert into imparte (dni, asignatura)
select ‘55555555’,codigo from asignaturas;
resultado:
4 filas creadas
LA ORDEN DELETE
La sentencia DELETE nos permite borrar las filas contenidas en una tabla.
DELETE [FROM] nombreTabla
[WHERE condición]
No se pueden borrar filas de varias tablas a la vez en una misma sentencia. Para borrar filas de
varias tablas habrá que ejecutar tantas sentencias DELETE como de tablas queramos borrar.
Delete from asignaturas a, imparte i where a.codigo = i.asignatura and i.dni=’21111222’;
resultado:
42
ERROR comando SQL no terminado correctamente
CLÁUSULA WHERE
Si no se especifica ninguna condición, la sentencia causará el borrado de todas las filas de la
tabla.
Delete from asignaturas;
resultado:
5 filas suprimidas
En el caso de que se indique alguna condición, se borrarán sólo aquellas filas de la tabla que
cumplan la condición o condiciones impuestas. Así, la siguiente sentencia, a diferencia de la
anterior que borra todas las filas de la tabla asignaturas, hará que se borren sólo las asignaturas
que tengan menos de 5 créditos.
Delete from asignaturas where creditos < 5;
resultado:
1 fila suprimida
La condición indicada en la cláusula where puede ser tan complicada como se desee. Por
ejemplo, la sentencia siguiente borra aquellas asignaturas que son impartidas por profesores con
categoría de TEU.
Delete from asignaturas where codigo in
(select asignatura from imparte i, profesores p
where i.dni = p.dni and p.categoria=’TEU’);
Resultado:
1 fila suprimida
CREACIÓN DE TABLAS CON CLAVES AJENAS
Relacionemos ahora las tablas PROFESORES y ASIGNATURAS mediante la tabla IMPARTE, de
forma que para cada profesor que tenga docencia, se indique en la tabla IMPARTE su dni junto
con el código de la asignatura que imparta. Cada profesor tendrá tantas filas, en esta nueva tabla,
como asignaturas imparta.
IMPARTE ( dni : varchar2(10), asignatura : char(5) )
Clave primaria: (dni, asignatura)
Clave ajena: dni → PROFESORES
Clave ajena: asignatura → ASIGNATURAS
Evidentemente, se deberá exigir que el valor que tenga la columna dni exista en la tabla
PROFESORES, de la misma manera cada código de asignatura deberá existir en la tabla
ASIGNATURAS, esto es lo que se conoce como integridad referencial y se consigue mediante las
denominadas claves ajenas:.
columna REFERENCES tabla
La sentencia de creación de esta tabla, junto con sus restricciones de clave primaria y claves
ajenas es
create table imparte (
dni varchar2(10)
references profesores,
asignatura char(5) references asignaturas,
primary key (dni,asignatura )
);
Con esta sintaxis a nivel de columna, cada clave ajena sólo puede estar formada por una sola columna.
43
Veamos otra sintaxis para definir claves ajenas, mediante las palabras reservadas FOREIGN
KEY, que nos permite designar varias columnas como clave ajena.
FOREIGN KEY (columna[,columna[, ...]]) REFERENCES tabla
Con esta sintaxis, vamos a escribir una sentencia equivalente a la anterior
create table imparte (
dni varchar2(10), asignatura char(5),
primary key (dni,asignatura ),
foreign key (dni) references profesores (dni),
foreign key (asignatura) references asignaturas (codigo)
);
Sea cual sea la sintaxis elegida para su definición, las columnas que conforman la clave ajena
han de coincidir en número (y orden) y tipo de datos con la clave primaria de la tabla a la que se
va a hacer referencia.
Una restricción de integridad referencial designa una columna o combinación de columnas
como clave ajena de una tabla (la tabla hija) y establece una relación entre ella y la clave primaria
de otra tabla (la tabla padre11). Por ejemplo, en la última línea de la sentencia, la clave ajena
asignatura hace referencia a la clave primaria codigo de la tabla padre asignaturas.
Toda clave ajena, si no tiene un valor nulo, debe tener un valor que coincida con un valor
existente en la tabla padre.
CLAVES AJENAS: influencia en el INSERT
En una tabla con claves ajenas, sólo se podrán insertar aquellas filas cuyas claves ajenas
existan en la correspondiente tabla padre.
En el siguiente ejemplo la inserción no es posible pues no existe la asignatura ‘AAA’.
insert into imparte (dni, asignatura) values ('55555555','AAA');
resultado: ERROR restricción de integridad (BDI.SYS_C0058700) violada - clave principal
no encontrada
insert into imparte (dni, asignatura) values ('21333444','FP');
resultado:
1 fila creada
CLAVES AJENAS: influencia en el DELETE
Sólo se podrán borrar aquellas filas que no estén siendo referenciadas, a través de ninguna
clave ajena, desde otra tabla. Si por ejemplo tenemos que la asignatura BDA es impartida por el
profesor con dni 21111222, no se podrá borrar la asignatura si antes no se eliminan las líneas
correspondientes a esa asignatura en la tabla imparte.
Delete from asignaturas where codigo = ‘FBD’;
resultado:
ERROR:restricción de integridad (BDI.SYS_C0058700) violada - registro
secundario encontrado
11
44
La tabla padre puede ser la misma tabla hija
Para poder realizar esta operación, será necesario primero eliminar las filas de imparte que
hagan referencia a esa asignatura. Una vez que la asignatura ya no está siendo referenciada
desde ninguna otra tabla, puede ser eliminada.
Delete from imparte where asignatura = ‘FBD’;
resultado:
1 fila suprimida
Delete from asignaturas where codigo = ‘FBD’;
Resultado:
1 fila suprimida
EJERCICIOS MANIPULACIÓN1
Si alguna de las sentencias no se puede realizar, explica el motivo del error
1.
Partiendo del ejercicio 13 de la sesión anterior, deberemos tener la sentencia de creación
de la tabla LISTIN, con las siguientes columnas: apodo, nombre, telefono, grado. Como
clave primaria podemos elegir apodo. También tendremos las sentencias insert para
incorporar algunas filas. Ejecutemos todo ello para tener la tabla LISTIN con algunas filas.
2.
Crear la tabla AMISTAD con las columnas grado y descripcion , para reflejar los diferentes
grados de amistad y su descripción: amigo, colega, etc. Por lo pronto vamos a crear sólo
la tabla. Sin incorporar datos.
3.
Borremos la tabla LISTIN. Y volvamos a crearla, pero añadiendo una restricción: que la
columna grado sea clave ajena que referencie a AMISTAD.
4.
Ejecutemos las sentencias del punto 1 para insertar algunas filas en LISTIN.
5.
Mirando detenidamente las anteriores sentencias hagamos SÓLO los insert NECESARIOS
en la tabla AMISTAD.
6.
Volvamos a ejecutar las sentencias del punto 4.
7.
Crear un nuevo grado de amistad en AMISTAD.
8.
Borremos TODAS las filas de AMISTAD. Mira las filas de AMISTAD y explica que sucede.
9.
Borremos ahora sólo una fila, la última que hemos añadido.
10. Borremos de AMISTAD la fila que más referencias tenga, hagamos una select de LISTIN y
contemos visualmente.
11. Borremos las filas necesarias del LISTIN que nos permitan ejecutar el punto 10.
12. Volvamos a ejecutar el punto 10.
45
46
manipulación 2
MANIPULACIÓN DE
DATOS (2)
Objetivos:
• Introducir al alumno en la orden UPDATE.
• Practicar con la integridad referencial.
Contenidos
• Actualizar los valores existentes en tablas de la base de datos.
• Actualizar los valores existentes en tablas de la base de datos a través de subconsultas.
LA ORDEN UPDATE
La sentencia UPDATE nos permite modificar la información contenida en una tabla.
UPDATE nombreTabla [aliasTabla]
SET columna=expresion
[WHERE condición]
No se pueden modificar varias tablas a la vez en una misma sentencia. Para modificar los
valores de varias tablas varias habrá que ejecutar tantas sentencias UPDATE como de tablas
queramos modificar.
Update asignaturas a, imparte i set creditos= 2
where a.codigo = i.asignatura and i.dni=’21111222’;
resultado:
ERROR falta la palabra clave SET
CLÁUSULA SET
En la cláusula SET se especifican las columnas de la tabla cuyos valores se desean modificar y
los nuevos valores que se van a asignar a dichas columnas. Por ejemplo, la siguiente sentencia
hace que la columna créditos de la tabla asignaturas pase a tener valor 0.
Update asignaturas set creditos = 0;
resultado:
4 filas actualizadas
Cuando se desea modificar más de una columna se indicará la lista de columnas y valores
separadas por comas. En el ejemplo que se muestra a continuación, a la columna créditos se le
asigna el valor 4 y a la columna créditosp el valor 2.
Update asignaturas set creditos=4, creditosp=2;
Resultado:
4 filas modificadas
Debe existir concordancia entre los tipos de datos de las columnas y el de los valores
asignados a las mismas.
47
Update asignaturas set creditos=’01/01/2002’, creditosp=2;
Resultado:
ERROR número no válido
CLÁUSULA WHERE
Si no se especifica ninguna condición, la sentencia causará la modificación de todas las filas de
la tabla.
Update profesores set ingreso=’01/01/2003’;
resultado:
3 filas modificadas
En el caso de que se indique alguna condición, se modificarán sólo aquellas filas de la tabla
que cumplan la condición o condiciones impuestas. Así, la siguiente sentencia, a diferencia de la
anterior que modifica todas las filas de la tabla profesores, hará que se modifique la fecha de
ingreso sólo a aquellos profesores cuya categoría sea TEU.
Update profesores set ingreso=’01/01/2003’ where categoria = ‘TEU’;
resultado:
2 filas modificadas
La condición indicada en la cláusula where puede ser tan complicada como se desee. Por
ejemplo, la sentencia siguiente modifica los créditos de las asignaturas que son impartidas por
profesores con categoría de TEU.
Update asignaturas set creditos = 0 where codigo in
(select asignatura from imparte i, profesores p
where i.dni = p.dni and p.categoria=’TEU’);
Resultado:
1 fila modificada
MODIFICACIÓN DE MÁS DE UNA FILA
Existe la posibilidad de modificar la información contenida en una tabla asignando como nuevo
valor o valores, el resultado de una consulta.
UPDATE nombreTabla [aliasTabla]
SET { {columna=expresion|columna=subconsulta} |
listaColumnas=subconsulta}
[WHERE condición]
El resultado de la consulta puede asignarse a una única columna o a una lista de columnas. En
el primer caso, la sentencia SELECT sólo devolverá un valor (una fila y una columna) el cual debe
coincidir en tipo de dato y longitud con el tipo de dato y longitud de la columna a la cual
asignamos el valor.
Update imparte set asignatura=’BDA’,
dni = (select dni from profesores where categoria=’ASO6’)
where asignatura like ‘%BD%’;
resultado:
1 fila actualizada
Si la restricción de que la consulta devuelva una fila y una columna no se cumple no se realiza
la actulización.
Update imparte set asignatura=’BDA’,
48
dni = (select dni from profesores)
where asignatura like ‘%BD%’;
resultado:
ERROR la subconsulta devuelve más de una fila
Update imparte set asignatura=’BDA’,
dni = (select dni, nombre from profesores where categoria =’ASO6’)
where asignatura like ‘%BD%’;
resultado:
ERROR demasiados valores
La segunda opción asigna el resultado de una consulta a una lista de columnas. En este caso,
la sentencia SELECT devolverá una única fila, pero con tantas columnas como elementos haya en
la lista de columnas. Los valores se asignan por orden, de forma que a la primera columna se le
asigna el valor de la primera columna de la SELECT, a la segunda la segunda, y así
sucesivamente. En el ejemplo siguiente se seleccionan dos columnas para dar valor a las
columnas dni y asignatura de la tabla impartir.
Update imparte set (dni,asignatura) =
(select dni, ‘BDA’ from profesores where categoria =’ASO6’)
where asignatura like ‘%BD%’;
resultado:
1 fila actualizada
Update imparte set (dni,asignatura) =
(select dni, ‘BDA’ from profesores)
where asignatura like ‘%BD%’;
resultado:
ERROR la subconsulta devuelve más de una fila
Update imparte set (dni,asignatura) =
(select dni, ‘BDA’, nombre from profesores where categoria =’ASO6’)
where asignatura like ‘%BD%’;
resultado:
ERROR demasiados valores
Update imparte set (dni,asignatura) =
(select dni from profesores where categoria =’ASO6’)
where asignatura like ‘%BD%’;
resultado:
ERROR no hay suficientes valores
Deberá existir una concordancia de tipo de dato y longitud entre los elementos de la lista de
columnas y las columnas seleccionadas.
CLAVES AJENAS: influencia en el UPDATE
En general, las claves ajenas generan las mismas restricciones de integridad referencial que el
DELETE salvo por la naturaleza de la operación: el UPDATE sólo generará problemas de integridad
referencial si el dato a modificar es un valor de clave primaria que está siendo referenciada por
alguna clave ajena. Suponiendo el estado de la base de datos original:
Update asignaturas set codigo = BD1 where codigo = ‘FBD’;
49
resultado:
ERROR:restricción de integridad (BDI.SYS_C005870012) violada registro secundario encontrado
Para poder realizar esta operación, será necesario insertar una nueva fila en asignaturas con el
identificador BD1 y copiando el resto de los valores, después cambiar las referencias a ‘FBD’ por
‘BD1’ y, por último, borrar la fila de ‘FBD’.
Insert into asignaturas (codigo,descripcion,creditos,creditosp)
select ‘BD1’, descripcion,creditos,creditosp
from asignaturas
where codigo = ‘FBD’;
resultado:
1 fila insertada
Update imparte set asignatura = ‘BD1’ where asignatura = ‘FBD’;
Resultado:
1 fila suprimida
Delete from asignaturas where codigo = ‘FBD’;
Resultado:
1 fila suprimida
ÓRDENES MANIPULACIÓN2
Los siguientes ejercicios se ejecutarán sobre la base de datos de Proveedores, ya conocida. Antes
de comenzar, deberás ejecutar las instrucciones contenidas en el fichero BD1CreateBD.sql para
la creación de la BD e inserción de datos iniciales.
1.
Haz que la fecha de recuento del inventario de todas las piezas sea el 1 de enero de
2003.
2.
Modifica la cantidad mínima de todas las piezas inventariadas que cumplan que la
cantidad disponible es menor. Haz que tomen el valor de la cantidad disponible de cada
una de ellas.
3.
Para aquellos vendedores para los que no tengamos teléfono, ponles el valor ‘SIN TLFNO’.
4.
Haz que la calle, la ciudad y la provincia de los vendedores de TOLEDO sea ‘CENTRAL,
5’,‘SALAMANCA’, ‘SALAMANCA’.
5.
Modifica los datos de las piezas que no tengan descripción. Haz que tomen el valor ‘SIN
DESCRIPCION’.
6.
Las piezas suministradas por el vendedor de número 3 van a ser suministradas a partir de
ahora por el de número 500, a un preciounitario de 5 euros.
7.
Pon a 0 el descuento de las piezas cuyos días de suministro sea inferior a 3.
8.
Para pedidos anteriores al año 2000, modifica el número de vendedor por el 3.
9.
Modifica los pedidos realizados por el vendedor de número 200 de forma que los haya
realizado el vendedor de número 1000.
10. El pedido con número 8 va a tener a partir de ahora el número 4, el pedido con número 5
va a tener a partir de ahora el pedido con número 1, el 8 será el 2 a partir de ahora y el 3
el 2.
12
Recuérdese que el identificador de restricción (en este caso, una clave ajena) lo asigna el sistema y
puede cambiar de un usuario a otro.
50
11. Para los pedidos en los que la cantidad recibida variara de la pedida, haz que no sea así.
12. Actualiza la ciudad y la provincia de los vendedores que no sean de ALICANTE. Asígnales
los valores de la ciudad y la provincia del vendedor de número 3.
13. Modifica la descripción de las piezas que estén SIN DESCRIPCIÓN asignándoles la
descripción de la que tenga el precio de venta igual a 7 euros.
14. Actualiza el precio de venta de la pieza de número A-1001-L a 4 euros y el de la pieza de
número C-1002-H a 15.
15. A partir de ahora el vendedor número 5 suministrará la pieza DISKETTE 1.44 PANASONIC
al precio de venta de la misma.
16. Haz lo mismo que en el ejercicio anterior, pero para el vendedor de número 200.
17. Los pedidos del vendedor número 3 han sido realizados a fecha de hoy.
18. Pon el precio de compra igual al precio de venta, la cantidad pedida y recibida a 100 y la
fecha de recepción a la fecha del día, para las líneas de pedido en las que la pieza pedida
sea A-1001-L.
19. Modifica los datos de las piezas recontadas con anterioridad al 1 de enero de 2003 de
forma que el período de recuento sea el mismo que para las piezas recontadas
51
52
manipulación 3
INTEGRIDAD
REFERENCIAL Y
BORRADOS
Objetivos:
• Extender la gestión de las claves ajenas y automatizar el borrado cuando produce
problemas de integridad referencial.
Contenidos
• Cláusula ON DELETE (políticas de mantenimiento de la integridad referencial en las
claves ajenas ante borrados en claves primarias)
ON DELETE
Ya se ha practicado con la integridad referencial en sesiones anteriores y se ha visto que el
intento de borrar ciertas filas es rechazado por el SGBD si éstas están siendo referenciadas por
alguna clave ajena. Recordemos la estructura y el contenido de la base de datos Ejemplo:
PROFESORES ( dni : char(9), nombre : char(25), categoria : char(4), ingreso : date )
Clave primaria: dni
ASIGNATURAS ( codigo : char(5), descripcion : char(40), creditos : decimal(3,1),
creditosp : decimal(3,1) )
Clave primaria: codigo
IMPARTE ( dni : char(9), asignatura : char(5) )
Clave primaria: (dni, asignatura)
Clave ajena: dni → PROFESORES
Clave ajena: asignatura → ASIGNATURAS
Extensiones de Ejemplo:
ASIGNATURAS
codigo descripcion
creditos creditosp
HI
FBD
DGBD
PC
FP
4.5
6.0
6.0
6.0
9.0
HISTORIA DE LA INFORMATICA
FUNDAMENTOS DE LAS BASES DE DATOS
DISEÑO Y GESTION DE BASES DE DATOS
PROGRAMACION CONCURRENTE
FUNDAMENTOS DE LA PROGRAMACION
1.5
3.0
1.5
4.5
53
IMPARTE
PROFESORES
dni
nombre
categoria ingreso
dni
asignatura
21111222
21222333
21333444
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
TEU
TEU
ASO6
21111222
21111222
21333444
FBD
DGBD
PC
01/10/1993
16/06/1989
16/06/1992
No hay ningún problema en borrar cualquier fila de la tabla IMPARTE, no existen claves ajenas
que les hagan referencia, pero tanto PROFESORES como ASIGNATURAS son referenciadas por las
claves ajenas definidas en IMPARTE y según el estado de la BD ciertas filas pueden ser eliminadas
y otras no. Por ejemplo, podemos eliminar “Historia de la Informática” puesto que ningún profesor
la imparte, pero si intentamos eliminar “Fundamentos de las Bases de Datos” el sistema mostrará
un error y no realizará la operación.
Delete from asignaturas where codigo = ‘FBD’;
resultado:
ERROR:restricción de integridad (BDI.SYS_C0058700) violada - registro
secundario encontrado
En ciertos sistemas de información es posible redefinir las restricciones de clave ajena para que
no se den estos mensajes de error. Ello es posible mediante la cláusula ON DELETE al crear una
tabla:
FOREIGN KEY (columna[,columna[, ...]]) REFERENCES tabla ON
DELETE {CASCADE | SET NULL}
La acción a realizar ante el borrado de una fila que está siendo referenciada por alguna clave
ajena puede ser el propagar la operacion (ON DELETE CASCADE) o anular (ON DELETE SET
NULL), dependiendo de la decisión del diseñador de la base de datos.
PROPAGAR EL BORRADO
Supongamos que la tabla IMPARTE de la BD Ejemplo tiene la siguiente definición:
create table IMPARTE ( dni varchar2(10), asignatura char(5),
primary key (dni, asignatura),
foreign key (dni) references PROFESORES (dni),
foreign key (asignatura) references ASIGNATURAS (codigo)
ON DELETE CASCADE);
El resultado del borrado anteriormente intentado sería ahora:
Delete from asignaturas where codigo = ‘FBD’;
resultado:
54
1 fila suprimida
ASIGNATURAS
codigo descripcion
creditos creditosp
HI
DGBD
PC
FP
4.5
6.0
6.0
9.0
HISTORIA DE LA INFORMATICA
DISEÑO Y GESTION DE BASES DE DATOS
PROGRAMACION CONCURRENTE
FUNDAMENTOS DE LA PROGRAMACION
3.0
1.5
4.5
IMPARTE
PROFESORES
dni
nombre
categoria ingreso
dni
asignatura
21111222
21222333
21333444
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
TEU
TEU
ASO6
21111222
21333444
DGBD
PC
01/10/1993
16/06/1989
16/06/1992
Como ya hemos dicho, eliminar la asignatura Historia de la Informática no genera conflictos de
integridad referencial por lo que el sistema puede hacerlo sin problemas:
Delete from asignaturas where codigo = ‘HI’;
resultado:
1 fila suprimida
ASIGNATURAS
codigo descripcion
creditos creditosp
DGBD
PC
FP
6.0
6.0
9.0
DISEÑO Y GESTION DE BASES DE DATOS
PROGRAMACION CONCURRENTE
FUNDAMENTOS DE LA PROGRAMACION
3.0
1.5
4.5
IMPARTE
PROFESORES
dni
nombre
categoria ingreso
dni
asignatura
21111222
21222333
21333444
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
TEU
TEU
ASO6
21111222
21333444
DGBD
PC
01/10/1993
16/06/1989
16/06/1992
Sin embargo, nótese que la clave ajena dni que hace referencia a PROFESORES no tiene
modificado su comportamiento ante borrados:
Delete from profesores where dni = ‘21111222’;
resultado:
ERROR:restricción de integridad (BDI.SYS_xxxxx) violada - registro
secundario encontrado
Delete from profesores where dni = ‘21222333’;
resultado:
1 fila borrada
La fila de Eva GOMEZ no ha podido ser eliminada puesto que imparte DGBD (y no se ha
modificado con ON DELETE) pero sí se ha borrado la de Manuel Palomar, que no imparte
asignatura alguna.
55
ASIGNATURAS
codigo descripcion
creditos creditosp
DGBD
PC
FP
6.0
6.0
9.0
DISEÑO Y GESTION DE BASES DE DATOS
PROGRAMACION CONCURRENTE
FUNDAMENTOS DE LA PROGRAMACION
3.0
1.5
4.5
IMPARTE
PROFESORES
dni
nombre
categoria ingreso
dni
asignatura
21111222
21222333
EVA GOMEZ
MANUEL PALOMAR
TEU
TEU
21111222
21333444
DGBD
PC
01/10/1993
16/06/1989
ANULAR EL VALOR DE CLAVE AJENA
Si la modificación de una clave ajena es ON DELETE SET NULL, la acción que llevará a cabo
automáticamente el SGBD es la de poner NULOS en aquellos casos en que la integridad referencial
se vea comprometida. Esta definición tiene más dificultad de aplicación puesto que prevalecen las
definiciones de clave candidata. Por ejemplo, la siguiente definición es inútil puesto que dni en
IMPARTE forma parte de la clave primaria y no admite nulos en ningún caso:
create table IMPARTE ( dni varchar2(10), asignatura char(5),
primary key (dni, asignatura),
foreign key (dni) references PROFESORES (dni) ON DELETE SET NULL,
foreign key (asignatura) references ASIGNATURAS (codigo) );
Delete from profesores where dni = ‘21111222’;
resultado:
ERROR: no se puede actualizar (“IMPARTE”.”DNI”) a un valor NULL
El sistema ha intentado cambiar el valor ‘21111222’ en la tabla IMPARTE por un nulo pero, al
ser parte de la clave primaria, ha rechazado la operación.
Supongamos que la tabla imparte tiene esta otra definición:
create table IMPARTE ( ficha integer, dni varchar2(10), asignatura char(5),
primary key (ficha),
foreign key (dni) references PROFESORES (dni) ON DELETE SET NULL,
foreign key (asignatura) references ASIGNATURAS (codigo) );
Y el contenido de la BD es ahora:
ASIGNATURAS
codigo descripcion
creditos creditosp
HI
FBD
DGBD
PC
FP
4.5
6.0
6.0
6.0
9.0
56
HISTORIA DE LA INFORMATICA
FUNDAMENTOS DE LAS BASES DE DATOS
DISEÑO Y GESTION DE BASES DE DATOS
PROGRAMACION CONCURRENTE
FUNDAMENTOS DE LA PROGRAMACION
1.5
3.0
1.5
4.5
PROFESORES
dni
nombre
categoria ingreso
21111222
21222333
21333444
EVA GOMEZ
MANUEL PALOMAR
RAFAEL ROMERO
TEU
TEU
ASO6
01/10/1993
16/06/1989
16/06/1992
IMPARTE
ficha
dni
asignatura
1
2
3
21111222
21111222
21333444
FBD
DGBD
PC
Delete from profesores where dni = ‘21111222’;
resultado:
1 fila borrada
El sistema puede borrar la fila de la profesora Eva GOMEZ, poniendo nulos en cualquier
referencia que halle en la clave ajena afectada de IMPARTE.
PROFESORES
dni
nombre
categoria ingreso
21222333
21333444
MANUEL PALOMAR
RAFAEL ROMERO
TEU
ASO6
16/06/1989
16/06/1992
IMPARTE
ficha
1
2
3
dni
asignatura
21333444
FBD
DGBD
PC
ON UPDATE ...
En Oracle9 no existe la posibilidad de establecer políticas para el mantenimiento de la
integridad referencial ante modificaciones (UPDATE) de valores de clave primaria.
57
ÓRDENES MANIPULACIÓN3
Los siguientes ejercicios se ejecutarán sobre la base de datos de Proveedores, ya conocida. Antes de
comenzar, deberás ejecutar las instrucciones contenidas en el fichero BD1CreateBD2.sql para la creación
de la BD e inserción de datos iniciales. Nótese que se han efectuado cambios en la definición de ciertas
claves ajenas para incorporar las políticas de mantenimiento de la integridad referencial ante borrados:
PRECIOSUM
PEDIDO
LINPED
INVENTARIO
Clave
Clave
Clave
Clave
Clave
Clave
Clave
Clave
Clave
Clave
Clave
Primaria: (numpieza, numvend)
Ajena: (numpieza)→ PIEZA RECHAZAR13
Ajena: (numvend)→ VENDEDOR PROPAGAR
Primaria: (numpedido)
Ajena: (numvend)→ VENDEDOR PROPAGAR
Primaria: (numpedido, numlinea)
Ajena: (numpedido)→ PEDIDO PROPAGAR
Ajena: (numpieza)→ PIEZA ANULAR
Primaria: (numbin)
Alternativa: (numpieza)
Ajena: (numpieza)→ PIEZA ANULAR
Para la comprobación de los efectos de las siguientes órdenes es conveniente tener a mano la sesión Select 1
donde se muestra el contenido original de la BD PROVEEDORES.
1.
Borra el vendedor 1.
2.
Comprueba los efectos de la operación anterior consultando todas las tablas.
3.
Borra el vendedor 3.
4.
Comprueba los efectos de la operación anterior consultando todas las tablas.
5.
Borra el vendedor 8001.
6.
Comprueba los efectos de la operación anterior consultando todas las tablas.
7.
Borra el pedido 6
8.
Comprueba los efectos de la operación anterior consultando todas las tablas.
9.
Borra la pieza O-0001-PP.
10. Borra todos los suministros de la pieza O-0001-PP.
11. Borra la pieza O-0001-PP.
12. Comprueba los efectos de la operación anterior consultando todas las tablas.
13. Borra todos los suministros de la pieza DD-0001-210.
14. Borra la pieza DD-0001-210.
15. Modifica BD1CreateBD2.sql (y ejecútalo después de realizada la modificación) cambiando
la política de la clave ajena de INVENTARIO a PROPAGAR, y añádele una nueva tabla con
los siguientes datos: NUEVA(orden entero) CP(orden)
Card(NUEVA, rel1) = (0,1)
Card(PRECIOSUM, rel1) = (0,N)
RECHAZAR
16. Inserta en NUEVA los 3 suministros de la pieza T-0001-IBM.
17. Intenta borrar el vendedor 2 y localiza el error producido.
18. Modifica la política de la clave ajena de NUEVA a ANULAR (y ejecuta), vuelve a insertar
los suministros del ejercicio 16, y vuelve a borrar el vendedor 2, comprobando los efectos
sobre la BD.
13
“Ante borrados en PIEZA, rechazar la operación si existen referencias”, y así con todas las claves
ajenas definidas.
58
conjuntos
OPERACIONES DE
CONJUNTOS
Objetivos:
• Combinar el resultado de varias sentencias select en un único resultado, utilizando los
operadores de conjuntos: unión, intersección y diferencia.
Contenidos
• Union, Union All
• Intersect
• Minus
• Resolución de requerimientos.
OPERADORES SOBRE CONJUNTOS
Un operador sobre conjuntos combina el resultado de dos sentencias SELECT en un único
resultado. Para que se pueda realizar, las sentencias SELECT deben tener ambas como resultado
el mismo número de columnas y los mismos tipos de datos (no es necesario que sean de igual
longitud).
Los operadores de conjuntos son la UNION, UNION ALL, INTERSECT y MINUS. En la versión de
Oracle con la que trabajamos, todos tienen la misma precedencia y se evalúan de izquierda a
derecha. Si queremos alterar este orden debemos utilizar los paréntesis.
UNION, UNION ALL
Al utilizar el operador UNION entre dos sentencias SELECT, el resultado final estará compuesto
por todas aquellas filas que aparecen en el resultado de como mínimo una de las SELECT. El
operador UNION elimina filas duplicadas en el resultado final. El operador UNION ALL opera de
igual modo que el operador UNION, pero no elimina filas duplicadas en el resultado final.
Supongamos que queremos saber el nombre de los profesores que son ASO6 o imparten
asignaturas de 6 créditos.
Se calcula cada SELECT por separado.
select nombre
from profesores
where categoria=’ASO6’
resultado:
nombre
RAFAEL ROMERO
59
select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6
resultado:
nombre
RAFAEL ROMERO
EVA GOMEZ
EVA GOMEZ
En el resultado final aparecerán todas las filas que estén en cualquiera de los dos resultados.
select nombre
from profesores
where categoria=’ASO6’
UNION
select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6
resultado con UNION ALL:
nombre
RAFAEL ROMERO
RAFAEL ROMERO
EVA GOMEZ
EVA GOMEZ
con UNION
nombre
RAFAEL ROMERO
EVA GOMEZ
INTERSECT
Al utilizar el operador INTERSECT entre dos sentencias SELECT, el resultado final estará
compuesto por todas aquellas filas que aparezcan en los resultados de ambas sentencias (no es
suficiente que aparezcan sólo en el resultado de una de ellas)
Supongamos que queremos saber el nombre de los profesores que son ASO6 e imparten
asignaturas de 6 créditos.
select nombre
from profesores
where categoria=’ASO6’
INTERSECT
select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6
resultado:
nombre
RAFAEL ROMERO
Se calcula cada SELECT por separado y aparecen en el resultado final todas las filas que estén
en ambos resultados.
MINUS
Al utilizar el operador MINUS entre dos sentencias SELECT, el resultado final estará compuesto
sólo por aquellas filas que aparecen en el resultado de la primera SELECT y no aparecen en el
resultado de la segunda.
Supongamos que queremos saber el nombre de los profesores que son ASO6 y no imparten
asignaturas de 6 créditos.
60
select nombre
from profesores
where categoria=’ASO6’
MINUS
select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6
resultado:
nombre
Supongamos que las condiciones hubiesen estado al revés. Queremos saber el nombre de los
profesores que imparten asignaturas de 6 créditos y no son ASO6.
select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6
MINUS
select nombre
from profesores
where categoria=’ASO6’
resultado:
nombre
EVA GOMEZ
Algunos de estos requerimientos se pueden resolver con una sola sentencia SELECT donde se
combinen de modo adecuado las condiciones. En otras ocasiones debemos recurrir a operar con
los resultados de varias sentencias. Por ejemplo, en estos dos últimos enunciados, el segundo se
puede solucionar con una SELECT, mientras que en el caso del primero es necesario trabajar con
dos.
CONSULTAS CONJUNTOS
1.
Nombre de las empresas que tienen vendedores con pedidos O que puedan suministrar la
pieza ‘A-1001-L’.
2.
Nombre de las empresas que tienen vendedores con pedidos Y que puedan suministrar la
pieza ‘A-1001-L’.
3.
Nombre de las empresas que tienen vendedores con pedidos PERO NO suministran la
pieza ‘A-1001-L’.
4.
Número de los pedidos en los que se soliciten teclados pero no monitores.
5.
Número y nombre de las piezas que suministra el vendedor número 1,
vendedor número 2.
6.
Número y nombre de las piezas con un precio de venta mayor que 1000, y todas las que
pueden ser suministradas por el vendedor número 1, ordenado por nombre.
7.
Número y nombre de las piezas que han sido pedidas pero no inventariadas
8.
Número y nombre de los vendedores de la empresa MECEMSA que, además, tienen
suministros de precio unitario mayor que 10 o se les ha hecho algún pedido
pero no el
61
62
funciones
ARITMÉTICA Y
FUNCIONES
AGREGADAS
Objetivos:
• Obtención de información calculada.
Contenidos
• operaciones aritméticas: +, -, *, /
• SUM(), AVG(), COUNT(), MAX(), MIN(), ROUND(), ABS().
• etiquetas para columnas
• Resolución de requerimientos.
Introducción de las funciones estadísticas aplicables a columnas enteras y de cuenta de
filas, así como la forma de realizar operaciones como suma, producto, etc., de valores
escalares.
OPERACIONES ARITMÉTICAS
Se pueden utilizar expresiones aritméticas tanto en la cláusula select, para obtener una nueva
columna en la tabla resultado, como en la construcción de condiciones de selección de filas.
Número de horas semanales, en un sólo semestre, que se imparten de cada asignatura:
select descripcion, (creditos/3)*2 from asignaturas
resultado:
descripcion
Historia de la Informática
Fundamentos de las Bases de Datos
Diseño y Gestión de Bases de Datos
Programación Concurrente
Fundamentos de Programación
(creditos/3)*2
3
4
4
4
6
63
Descripción de las asignaturas y número de horas semanales de las asignaturas con menos de
4 horas semanales de clase:
select descripcion, creditos from asignaturas where (creditos/3)*2 < 4
resultado:
descripcion
Historia de la Informática
creditos
4.5
FUNCIONES AGREGADAS
Se dispone de una serie de funciones agregadas que retornan valores calculados sobre una
determinada columna. Estas funciones devuelven un único valor para todas las tuplas
seleccionadas mediante la condición de la cláusula where; si no se especifica ésta, el cálculo se
realiza sobre la totalidad de la columna.
COUNT( *
COUNT( DISTINCT expr
SUM( [DISTINCT] expr
AVG( [DISTINCT] expr
MIN( expr
MAX( expr
ROUND( expr
ABS( expr
)
)
)
)
)
)
)
)
número de filas
número de valores distintos en la columna expr
suma de todos los valores en expr
promedio de todos los valores en expr
el más pequeño de todos los valores en expr
el mayor de todos los valores en expr
redondea expr
valor absoluto de expr
Las funciones de tipo estadístico precisan que la expresión que se evalúe se construya sobre
columnas de tipo de datos numérico.
La expresión expr puede contener el nombre de una columna o un cálculo sobre una o varias
columnas.
Si se especifica la palabra clave distinct la expresión obligatoriamente ha de ser un nombre de
columna, y se asume que la función se calcula únicamente sobre valores distintos de la expresión.
En ningún caso se pueden anidar funciones: avg ( min ( creditos ) ) no está permitido.
¿Cuántos profesores hay en nuestra BD?
select count( * ) from profesores
resultado:
( count( * ) )
3
¿Cuántas asignaturas de más de 5 créditos hay en nuestra BD?
select count( * ) from asignaturas where creditos > 5
resultado:
( count( * ) )
4
¿Cuántas valores de créditos distintos hay en nuestra BD?
select count( distinct creditos ) from asignaturas
resultado:
( count )
3
64
¿Cuál es la media de créditos por asignatura?
select avg( creditos ) from asignaturas
resultado:
( avg )
6.3
¿Cuál es la media de horas por asignatura?
select avg( creditos*2/3 ) from asignaturas
resultado:
( avg )
4.2
Total de créditos ofertados en asignaturas de Bases de Datos:
select sum( creditos ) from asignaturas where codigo like '%BD'
resultado:
sum( creditos )
12
ETIQUETAS PARA COLUMNAS
Dado que las expresiones calculadas no tienen un nombre específico de columna en la salida
por pantalla, es conveniente "renombrarlas" para aclarar su significado.
Se pueden etiquetar las columnas de la tabla resultado añadiendo, antes de la coma si hubiera
más columnas detrás, una cadena de no más de 18 caracteres y sin espacios en blanco, tal como
se hace con los alias temporales de las tablas. Esta cadena de caracteres aparecerá en el
encabezado de la columna.
select count( * ) num_asignaturas, avg(creditos) mediactos
from asignaturas
resultado:
num_asignaturas mediactos
5
6.30
65
CONSULTAS FUNCIONES
1.
Obtener la diferencia entre cantidad pedida y cantidad recibida de las líneas del pedido 1.
2.
Media de días de intervalo entre la fecha de envío del pedido 1 y de entrega de las
distintas piezas solicitadas en ese pedido
3.
Obtener la cantidad de provincias distintas de las que tenemos conocimiento de algún
proveedor.
4.
Mínima diferencia entre precio de compra y precio de suministro del vendedor al que se le
compró.
5.
Media de precios distintos de venta de piezas.
6.
Máximo descuento (en euros) de las piezas suministradas.
7.
Número, nombre y diferencia entre precio de venta y precio de compra de la(s) pieza(s)
que suministran los vendedores de Alicante.
8.
Máximo, mínimo y media de precio de venta de las piezas.
9.
Cantidad total de piezas que sabemos nos pueden suministrar los proveedores.
10. Cantidad de vendedores de nuestra BD.
11. Total de la diferencia en euros entre lo pagado por compra de artículos y sus respectivos
precios de suministro ofrecidos en su día por los proveedores si el segundo precio es
menor que el primero.
66
group by
INFORMACIÓN
AGRUPADA
Objetivos:
• Obtención de información calculada sobre grupos de filas.
Contenidos
• GROUP BY
• Resolución de requerimientos.
Clasificación de información en función de algún criterio especificado mediante la cláusula
GROUP BY.
LA CLÁUSULA GROUP BY
Supongamos que queremos obtener la cantidad de asignaturas que imparte cada profesor:
select p.dni, nombre, count( * )
from profesores p, imparte i
where p.dni = i.dni
group by p.dni, nombre
resultado:
dni
21111222
21333444
nombre
EVA GOMEZ
RAFAEL ROMERO
( count )
2
1
En esta ocasión, y por la utilización de la cláusula group by, la cuenta de valores distintos de la
columna asignatura se calcula en base a cada profesor de nuestra BD que imparte alguna asignatura.
El criterio de agrupación se forma con al menos todas las columnas no calculadas de la lista de la
cláusula select.
• No se pueden poner columnas no calculadas en la select que no aparezcan en la group by.
select p.dni, nombre, count( * )
from profesores p, imparte i
where p.dni = i.dni
group by p.dni
resultado:
ERROR
67
• Si se pueden poner más columnas en la lista del group by que en la de la select.
select nombre, count( * )
from profesores p, imparte i
where p.dni = imparte.dni
group by p.dni, nombre
resultado:
nombre
( count(*) )
EVA GOMEZ
RAFAEL ROMERO
2
1
where y group by
Cuando se utiliza la cláusula where, aparte de enlazar tablas por columnas comunes, como
PROFESORES e IMPARTE por profesores.dni e imparte.dni respectivamente, se puede utilizar para
eliminar ciertas filas del cálculo.
Así, si queremos calcular cuantas asignaturas imparte cada profesor sin contar Fundamentos de
las Bases de Datos, escribiremos la siguiente sentencia.
select nombre, count( * )
from profesores p, imparte i
where p.dni = i.dni
and asignatura <> 'FBD'
group by p.dni, nombre
resultado:
nombre
EVA GOMEZ
RAFAEL ROMERO
( count(*) )
1
1
ATRIBUTOS NO CLAVE EN EL GROUP BY
Los únicos atributos que aseguran la identificación de una tupla respecto de las demás son los que
forman la clave primaria (en general, la clave candidata).
Así, si la clave primaria de una tabla de personas (profesores o alumnos, por ejemplo) es el D.N.I.,
podemos decir sin equivocarnos que no habrá duplicados en este atributo. No obstante, el nombre no
será clave y, por lo tanto, admite duplicados. Es decir, es perfectamente posible encontrar a dos
personas distintas (con números de D.N.I. diferentes, obviamente) que se llamen igual (nombres y
apellidos).
Si, por ejemplo, agrupamos datos por el nombre y no por el D.N.I. podemos obtener información
en una única fila de dos personas diferentes que se llaman igual. Sea una ocurrencia tal como ésta:
DNI
21
22
68
CLIENTE
NOMBRE
JUAN
JUAN
OPERACIÓN
1
2
3
INGRESO
CLIENTE
21
22
22
INGRESO
1000
2000
3000
select nombre, avg( ingreso ) media
from cliente, ingreso
where dni = cliente
group by nombre
resultado:
nombre
JUAN
media
2000
Puesto que el nombre es el mismo para los dos clientes, la agrupación contabiliza todas las
ocurrencias de ingreso como de uno sólo. Sin embargo, si introducimos en la lista de columnas del
GROUP BY aquellas que son su clave primaria:
select nombre, avg( ingreso ) media
from cliente, ingreso
where dni = cliente
group by dni, nombre
resultado:
nombre
JUAN
JUAN
media
1000
2500
Es evidente que, si queremos saber exactamente de a qué cliente nos referimos en cada tupla del
resultado, debemos incluir la clave primaria como atributo de la relación derivada de la ejecución de
la select.
En general, y aunque no afecte al resultado, evitaremos la no inclusión de atributos clave en la
cláusula group by.
ORDENACIÓN DE LA SALIDA
En la cláusula order by podemos especificar la expresión tal cual aparece en la select.
select dni, count( * ) asignaturas from profesores group by p.dni, nombre order by count( * )
resultado:
dni
21333444
21111222
asignaturas
1
2
O bien podemos utilizar una alias para la columna (asignaturas en este ejemplo) o el orden de la
columna empezando por la izquierda (la función está en la tercera columna en este ejemplo):
select dni, count( * ) asignaturas
from profesores
group by p.dni, nombre
order by asignaturas
select dni, count( * ) asignaturas
from profesores
group by p.dni, nombre
order by 2
resultado:
dni
21333444
21111222
asignaturas
1
2
69
CONSULTAS GROUP BY
NOTA:
es muy recomendable, aunque no se especifique explícitamente en el
requerimiento, que la salida se ordene ascendentemente (por defecto)
por las columnas no calculadas de la lista de la cláusula select.
NOTA:
así mismo, se deben etiquetar las columnas calculadas.
1.
Obtener para cada pieza, nombre de la pieza, precio de venta, y la media de la diferencia
entre el precio de venta y el de suministro.
2.
Obtener para cada número de pedido, el precio pagado en total por ese pedido, la cantidad
pedida total así como la diferencia entre cantidad pedida total y cantidad recibida total.
3.
Obtener la cantidad de vendedores de cada empresa, indicando cantidad y nombre de la
misma, ordenado descendentemente por cantidad de empleados.
4.
Obtener, por pieza solicitada, la máxima diferencia entre cantidad pedida y cantidad recibida
de entre todas las veces en que fue servida.
5.
Obtener para cada pieza, el número de la pieza y el número total de vendedores que nos
pueden suministrar esa pieza.
6.
Obtener número de pieza y número total de vendedores que la pueden suministrar para
piezas de más de 250 de precio de venta.
7.
De cada pieza obtener el precio unitario medio de suministro.
8.
De cada pieza de precio de venta mayor que 250 obtener el precio medio de suministro.
9.
Obtener la media de las ventas (en euros) realizadas por cada vendedor de cada pieza.
10. Obtener la cantidad de pedidos efectuados por fecha y el total pagado por las mercancías.
11. Calcular las ganancias (precio de compra menos precio de suministro por la cantidad
recibida) de cada vendedor que ha efectuado alguna venta.
12. Calcular por número de pedido, la media de la diferencia entre el precio de compra y el de
suministro (que nos ofertaba el vendedor al que se le solicitó el pedido) de las líneas de cada
pedido.
13. Calcular para cada pieza, el tanto por ciento de beneficios del precio de venta al público
respecto al precio medio de compra de todas las compras que se han realizado de la pieza
14. Obtener, por cada pieza solicitada, cuántos vendedores la podrían suministrar, ordenado
alfabéticamente por la descripción de la pieza y eliminando aquellas compradas a
proveedores de Alicante.
70
group by - having
SELECCIÓN DE
INFORMACIÓN
AGRUPADA
Objetivos:
• Establecer selecciones sobre información agrupada.
Contenidos
• HAVING.
• Resolución de requerimientos.
LA CLÁUSULA HAVING
Al igual que la cláusula where selecciona filas, la cláusula having selecciona grupos; si en la
where la condición que se especifica afecta a las tuplas de toda la tabla, el group by efectúa los
cálculos en función de esa selección previa y da como resultado una tabla con la información
calculada para cada grupo. Sobre esta última el having eliminaría aquellas tuplas que no cumplen
la condición.
Normalmente, where selecciona sobre los datos almacenados en la tabla y having sobre la
información calculada.
Supongamos que queremos saber cuantas asignaturas imparte cada profesor pero únicamente
en el caso de que imparta 2 ó más asignaturas:
select p.dni, nombre, count( * ) asignaturas
from profesores p, imparte i
where p.dni = i.dni
group by p.dni, nombre
having count(*) >= 2
order by nombre
resultado:
dni
21111222
nombre
EVA GOMEZ
asignaturas
2
71
select p.dni, nombre, count( * ) asignaturas
from profesores p, imparte i
where p.dni = i.dni and asignatura <> 'FBD'
group by p.dni, nombre
having count(*) >= 2
order by nombre
resultado:
dni
nombre
asignaturas
En la expresión del having no se pueden utilizar los alias de las columnas (asignaturas) en este
caso.
Veamos, cláusula a cláusula, los efectos de esta última orden:
1. la cláusula where ha eliminado las tuplas de imparte de código de asignatura FBD.
2. la cláusula group by calcula, para cada profesor, el número de asignaturas que imparte.
Puesto que no contamos FBD, Eva GOMEZ sólo imparte, igual que Rafael Romero, una
única asignatura.
3. la cláusula having elimina del resultado del paso anterior todas aquellas tuplas con un valor
en la cuenta de filas menor que 2. El resultado es vacío puesto que ninguno de los grupos
supera la condición.
CONSULTAS GROUP BY - HAVING
1.
Nombre de las empresas que tienen más de dos vendedores.
2.
Números de pedido que tengan más de tres líneas de pedido.
3.
Números de pedido donde el total de piezas pedidas es mayor que 40.
4.
Obtener los números de pedido donde el precio total sea superior a 1000.
5.
Para las piezas que se hayan ofertadoa un precio unitario medio mayor que 260 obtener
el número de pieza, el máximo precio unitario, y la cantidad de suministradores.
6.
Para las piezas que se ofrecen a un precio unitario medio mayor que 260 (sin tener en
cuenta los suministros menores de 250) obtener el número de pieza, el máximo precio
unitario, y la cantidad de suministradores.
7.
Obtener aquellos números de pedido y fecha en que se confeccionaron cuya cantidad de
artículos pedidos sea superior a 30 y la recibida inferior a 10.
8.
Obtener el número de pieza y el precio unitario medio de aquellas piezas que tarden de
media 14 días como máximo en ser suministradas (diassum=tiempo de suministro).
9.
Obtener los números de pedido, precio de compra y cantidad pedida de los números de
línea 1 y recibidas en fecha 10-05-92.
10. Obtener el número, el nombre y el precio máximo unitario de las piezas cuyo precio de
venta sea mayor que 250 o menor que 170, su descuento medio oscile entre 10 y 17 y
que tengan un precio unitario medio total superior a 150, ordenado por precio máximo.
11. Determinar el número total de proveedores que pueden suministrar la pieza 'P-0001-33’.
12. Para cada pieza, de la que se tiene información sobre sus posibles vendedores, obtener el
número de pieza, y sus precios unitarios máximo y mínimo, exceptuando la información
referida al vendedor número 1.
72
13. Dar una relación del nombre de las piezas que nos pueden suministrar más de dos
proveedores.
14. Obtener el número y el nombre del vendedor así como el número y nombre de las piezas
de precio unitario mayor que 200 que nos puedan suministrar. El resultado se dará
ordenado por número y nombre de vendedor y por nombre de la pieza.
73
74
subselect
CONSULTAS ANIDADAS
Objetivos:
•
Utilizar el resultado de una sentencia select para establecer las condiciones de otra
sentencia select.
Contenidos
•
Subqueries.
•
operadores de comparación escalar.
•
IN, ALL, ANY, [NOT].
•
Resolución de requerimientos.
CONSULTAS ANIDADAS (SUBQUERIES)
En la condición de búsqueda de la orden select (en la cláusula where o en la having) también
podemos:
• comparar una expresión con el resultado de otra orden select
• determinar si el valor de una expresión está incluido en los resultados de otra orden select
• preguntar si una orden select ha seleccionado filas.
Cuando una orden select se encuentra dentro de la cláusula where de otra select recibe el
nombre de subconsulta (subquery). Por ejemplo :
select descripcion, creditos
from asignaturas
where creditos = ( select min(creditos) from asignaturas )
resultado:
descripcion
Historia de la Informática
creditos
4.5
En primer lugar se calcula la select anidada (entre paréntesis) y se obtiene el valor mínimo
para la columna créditos de la tabla asignaturas. Con ese valor se compara tupla a tupla y se
obtiene la asignatura (o asignaturas) cuya cantidad de créditos es igual al mínimo.
sintaxis general de la subconsulta
expresión op_comparación { ALL | [ ANY | SOME ] } ( orden select )
expresión [ NOT ] IN ( orden select )
[ NOT ] EXISTS ( orden select )
Los valores posibles a devolver por una orden select anidada son :
•
nada
•
un valor único (una fila y una columna),
•
un conjunto de valores (varias filas y una columna).
75
Siempre que la subselect devuelva algo, únicamente será en una y nada más que
una columna (salvo el operador EXISTS).
DEVOLUCIÓN DE UN ÚNICO VALOR
expresión op_comparación ( orden select )
Podemos utilizar los operadores de comparación para preguntar si el valor de una determinada
expresión es mayor, menor, igual, etc. que el resultado de la subselect, siempre y cuando ésta
devuelva una única fila y una única columna, es decir, un valor simple.
En general serán órdenes select que calculan una función agregada (sum, min, max, avg,
count).
select descripcion
from asignaturas
where creditos = ( select min(creditos) from asignaturas )
No sería correcto, porque la subselect devuelve más de una fila, la siguiente orden :
select descripcion
from asignaturas
where creditos = ( select creditos from asignaturas where creditos < 9 )
DEVOLUCIÓN DE UNA LISTA DE VALORES
expresión op_comparación ALL | [ ANY | SOME ] ( orden select )
Cuando la tabla resultado contiene más de una fila (pero una única columna, insistimos) hay
que utilizar un modificador para el operador de comparación.
Nombre de la asignatura que tiene el mínimo número de créditos (es equivalente al primer
ejemplo) :
select descripcion
from asignaturas
where creditos <= ALL ( select creditos from asignaturas )
resultado:
descripcion
Historia de la Informática
creditos
4.5
En este caso, el número en créditos de la asignatura tiene que ser menor o igual que todos
(all) los valores obtenidos en la subconsulta (que es la relación de créditos de todas las
asignaturas).
76
Nombre de las asignaturas que no tienen el mínimo número de créditos :
select descripcion
from asignaturas
where creditos > ANY ( select creditos from asignaturas )
resultado:
creditos
6
6
6
9
descripcion
Fundamentos de las Bases de Datos
Diseño y Gestión de Bases de Datos
Programación Concurrente
Fundamentos de la Programación
Serían todas aquellas asignaturas cuyos créditos superasen al menos a uno (any) de los
valores devueltos por la subconsulta. El modificador some es equivalente a any.
Otra forma de expresar el mismo requerimiento :
select descripcion
from asignaturas
where creditos != ( select min(creditos) from asignaturas )
Supongamos que deseamos obtener el nombre de los profesores que imparten una asignatura
que no sea la máxima en número de créditos :
select nombre
from profesores p, asignaturas a, imparte i
where p.dni = i.dni and i.asignatura = a.codigo
and creditos < ANY ( select creditos from asignaturas )
resultado:
nombre
Eva GOMEZ
Rafael Romero
expresión [ NOT ] IN ( orden select )
También podemos consultar la pertenencia de un valor a la lista de valores devuelta por la
subconsulta.
Obtener todos los datos de los profesores que imparte alguna asignatura :
select * from profesores
where dni IN ( select dni from imparte )
O dicho de otra manera : datos de los profesores cuyo dni aparece en la tabla imparte.
En este caso daría lo mismo procesar la orden :
select p.* from profesores p, imparte i
where p.dni = i.dni
Se verá más clara la utilidad de este operador si preguntamos justo lo contrario.
77
Obtener todos los datos de los profesores que no imparten asignaturas :
select * from profesores
where dni NOT IN ( select dni from imparte )
Por último, veamos que algunos de estos operadores son equivalentes :
expresión IN (orden select)
expresión NOT IN (orden select)
≡
≡
expresión =ANY (orden select)
expresión !=ALL (orden select)
CONSULTAS SUBSELECT
1.
Obtener todos los datos de los vendedores a los que se les han solicitado más pedidos
que a todos los demás.
2.
Número y nombre de los vendedores que no ofertan ninguna pieza.
3.
Número y nombre de los vendedores a los que se les ha solicitado algún pedido.
4.
Número y nombre de los vendedores a los que no se les ha solicitado pedidos.
5.
Nombre de la empresa que ofrece la pieza más barata de precio de suministro.
6.
Número y descripción de la pieza más cara (precio de venta).
7.
Para cada pieza que se ofrece en la lista de suministros, obtener el número de pieza, y
sus precios unitarios máximo y mínimo, exceptuando aquellos suministrados por el
vendedor número 1.
8.
Número de pedido y precio total pagado del pedido más caro.
9.
Número y nombre del vendedor al que se le ha solicitado el pedido más caro.
10. Número, descripción y precio de venta de los monitores que no han sido nunca
solicitados.
11. Calcular, por cada número de vendedor, la cantidad de piezas distintas que ha vendido,
para aquellos vendedores pertenecientes a la empresa con más proveedores.
12. Nombre de los suministradores que pueden suministrar al menos alguna de las piezas que
puede suministrar el vendedor número 5.
13. Listar los vendedores que sean de la misma provincia que el vendedor número 100.
14. Obtener los nombres de los vendedores de la misma empresa que Luis García.
15. Número y descripción de las piezas cuyo precio medio de suministro esté por encima del
mayor precio de compra pagado por ella.
16. Número, nombre, empresa en la que trabaja y número de piezas que puede suministrar el
vendedor que tiene la media más alta de piezas servidas.
17. Nombre de la empresa con mayor importe de ventas.
18. Número y descripción de la pieza que ha sido pedida más veces.
19. Número y descripción de las piezas que pueden ser suministradas por proveedores de la
Comunidad Valenciana o que pueden ser suministradas por el vendedor que ha realizado
la menor venta (pedido de importe más bajo)
78
20. Número de vendedor, número de pieza y descuento para aquellas piezas cuyo precio de
venta supere en más del 15% la media del precio de compra de los pedidos en los que
aparece.
21. Cantidad de piezas a la venta de las que no tenemos información sobre sus posibles
suministradores.
79
80
subselect - exists
CONSULTAS ANIDADAS II
Contenidos
•
El operador EXISTS.
•
Resolución de requerimientos.
EL OPERADOR EXISTS
[ NOT ] EXISTS ( orden select )
El operador exists nos informa si una subconsulta ha devuelto algún resultado, o lo que es lo
mismo, si la tabla resultado tiene alguna fila.
Exists devuelve verdadero si hay al menos una tupla en la relación derivada y falso si la
relación derivada es vacía.
Supongamos que queremos conocer si algún profesor imparte todas las asignaturas :
select nombre from profesores p
where not exists ( select codigo from asignaturas a
where not exists ( select asignatura from imparte i
where i.asignatura=a.codigo and p.dni=i.dni ) )
Vamos a leer el requerimiento siguiendo las apariciones del operador exists dentro de las
sucesivas órdenes select : Nombre de los profesores tales que no hay ninguna asignatura que no
imparta él.
Supongamos que la forma que tiene el SGBD de resolver esta sentencia es la siguiente :
•
En la primera select recorremos la tabla de profesores.
•
Para cada profesor, la segunda select recorre la tabla de asignaturas.
•
Para cada profesor y asignatura comprueba que el primero imparte la segunda.
Una vez que ha fijado el profesor y la asignatura, la última subconsulta dará como resultado
verdadero si la imparte y falso en caso contrario (devolverá una tupla o no devolverá nada).
Supongamos un profesor que no imparte al menos una de las asignaturas de nuestra base de
datos. Cuando el SGBD esté resolviendo la última subselect para ese profesor y esa asignatura,
como no están relacionados, no devolverá ninguna tupla : el resultado del segundo exists es falso,
y, como está negado, finalmente verdadero (ese profesor no imparte esa asignatura).
Por lo tanto, para la primera subselect, ya existe una asignatura que obtiene en la cláusula
where un valor verdadero : esa asignatura saldrá en la tabla resultado. Como ésta última tiene al
menos una fila, el primer exists será verdadero, y, como está negado, finalmente falso. El profesor
no imparte todas las asignaturas de nuestra base de datos.
Un profesor que imparta todas las asignaturas obtendrá siempre una fila en la última subselect
y, por lo tanto, ninguna asignatura aparecerá como resultado de la primera subselect, el
correspondiente exists será falso, y por efecto del operador de negación la condición será cierta :
ese profesor aparecerá en la solución.
En nuestra base de datos Ejemplo no hay ningún profesor que imparta todas las asignaturas.
81
Aunque puede inducir a error, por su traducción intuitiva del inglés al español, no
se deben confundir nunca los operadores IN y EXISTS : el primero devuelve una lista de
valores, mientras que el segundo devuelve un valor de verdad; la sintaxis también es muy
diferente.
CONSULTAS SUBSELECT - EXISTS
1.
Nombre de los vendedores que pueden suministrar todas las piezas.
2.
Nombre de los vendedores que no pueden suministrar ninguna pieza, ordenados
alfabéticamente.
3.
Numero y descripción de las piezas que se han solicitado en todos los pedidos del
vendedor 1.
4.
Nombre de las empresas que cumplen que todos sus vendedores son de la Comunidad
Valenciana, ordenadas alfabéticamente.
5.
Número y nombre de todos los vendedores de la ciudad de Alicante.
6.
Empresas que no han servido ninguna pieza.
7.
Empresas que han servido la(s) pieza(s) de mayor precio de venta.
8.
Numero de los pedidos cuyas piezas tienen todas un precio de venta mayor que la mitad
del precio máximo de venta.
9.
Obtener todos los datos de los vendedores que sirvieron los pedidos del requerimiento
anterior.
10. Número y nombre de los vendedores que han servido algún pedido (utilizando
obligatoriamente EXISTS).
11. Número y nombre de la pieza de menor precio de suministro (utilizando EXISTS).
12. Nombre de los vendedores a los que se les haya solicitado más de dos pedidos (utilizando
subconsultas).
13. Número de pedido, fecha y número de vendedor del pedido más caro (utilizando
subconsultas).
82
adicionales 1
EJERCICIOS
ADICIONALES
CONSULTAS
1.
Toda la información de las piezas que puedan ser suministradas por vendedores de
empresas cuyo nombre empieza por 'H'.
2.
Piezas que el vendedor numero 1 ofrece en la lista de suministros y que han sido servidas
en algún pedido
3.
Vendedores que pueden suministrarnos piezas que se venden al público con un precio de
venta entre 50 y 100 y que esa pieza ha sido solicitada en algún momento (no
necesariamente a ellos)
4.
Nombre de las empresas de Alicante a las que se ha comprado algún monitor
5.
Nombre y numero de las piezas que se han solicitado en algún pedido ordenadas por el
nombre
6.
Para cada pieza comprada, número de pieza y diferencia en euros entre el precio de
compra y el de suministro del vendedor al que se le compró, ordenado descendentemente
por dicha cantidad.
7.
Numero de vendedor y empresa para la que trabaja de aquellos que han vendido alguna
pieza por un precio mayor que el estipulado por ellos en la lista de suministros
83
84
adicionales 2
EJERCICIOS
ADICIONALES
CONSULTAS
1.
Obtener el nombre de los vendedores y la cantidad de piezas que pueden suministrar,
ordenado alfabéticamente por vendedor.
2.
Obtener el número y el nombre de los vendedores y la cantidad de piezas que pueden
suministrar ordenado alfabéticamente por vendedor.
3.
Obtener el nombre de las piezas, la media del precio unitario de cada pieza y el precio de
venta de todas las piezas de las que conocemos posibles suministradores.
4.
Para cada pedido obtener el número de líneas que tiene, el número y nombre del
vendedor y la fecha del pedido.
5.
Obtener el nombre de las piezas, la media del precio unitario de cada pieza y el precio de
venta de todas las piezas que puedan sernos suministradas por más de tres proveedores.
6.
Obtener los números y nombres de los vendedores que han servido algún pedido con más
de tres artículos diferentes.
7.
Obtener número y nombre de vendedores a los que les hayamos solicitado algún pedido.
8.
Obtener el nombre de las piezas, la media del precio unitario de cada pieza y el precio de
venta de todas las piezas de precio unitario medio mayor que 100 y que puedan ser
suministradas por más de dos proveedores.
9.
Obtener para cada pieza, el nombre de las pieza, la media del precio unitario de
suministro y el precio de venta, para las piezas de precio de venta mayor que 300,
teniendo en cuenta que la media de los precios unitarios debe estar entre 100 y 280.
Ordenar el resultado por el nombre de la pieza.
10. Obtener número y nombre de las piezas que tengan una diferencia entre precio de venta
y media de precio de suministro (preciounit) menor del 20% del precio de venta.
85
86
adicionales 3
EJERCICIOS
ADICIONALES
CONSULTAS
1.
Obtener para los vendedores de la provincia de Alicante, el número de vendedor, su
nombre y la cantidad total de pedidos que se les ha solicitado.
2.
Obtener la cantidad total de piezas que se solicitaron en el año 1992.
3.
Obtener el número de pedido, el importe total, y el numero y nombre del vendedor al que
se les solicitó, para los pedidos de importe total superior a 10000 euros. Ordena el
resultado por el importe total.
4.
Para cada pieza que pueda ser suministrada a un precio medio unitario inferior a 10
euros, obtener el número de la pieza, su nombre, el precio máximo al que nos la han
ofrecido, el precio mínimo y la cantidad de vendedores que nos la pueden suministrar.
5.
Para los pedidos que nos han sido servidos en más de un día, obtener el número de
pedido, el número del vendedor al que se le solicitó, su nombre, y la cantidad de días
distintos en los que nos han servido las piezas solicitadas.
6.
Para las empresas que tengan un único vendedor, obtener el nombre de la empresa y la
cantidad total de pedidos que se le han solicitado, y el importe total entre todos los
pedidos.
7.
Para las piezas recibidas en domingo, obtener el número de la pieza, su nombre y el
número y nombre del vendedor al que se le solicitaron. Ordena el resultado por el nombre
de la pieza.
87
88
adicionales 4
EJERCICIOS
ADICIONALES
CONSULTAS
1.
Número y nombre de los vendedores a los que les hemos solicitado algún pedido en el
año 1995 pero no les hemos solicitado ninguno en el año 1992.
2.
Obtener el número y el nombre las piezas que puedan sernos suministradas por más de
dos vendedores de la provincia de Alicante, y que en total (entre todos los pedidos
solicitados a todos los vendedores) hayamos pedido más de 500 unidades.
3.
Obtener el nombre de las empresas de las que tengamos más de 1 de un vendedor de
Alicante y no se les haya hecho ningún pedido (a ninguno de sus vendedores) antes del
año 1995.
4.
Obtener el número y nombre de las piezas que nunca hemos solicitado.
5.
Obtener el número de los vendedores (numvend) que nos hubiesen podido servir todo lo
que se solicita en las líneas 1, 2 y 3 del pedido número 1.
6.
Obtener para los vendedores de Alicante o Madrid, el número y nombre de vendedor
junto con el importe total que les hemos pagado a través de todos los pedidos que se les
ha solicitado.
89
90
adicionales 5
EJERCICIOS
ADICIONALES
CONSULTAS
1.
Obtener para los pedidos con un importe total entre 400 y 600 euros, el número de
pedido, el número y nombre del vendedor al que se le solicitó, y la fecha del pedido.
2.
Obtener para las piezas cuyo precio de suministro oscila entre 10 y 15, el número de la
pieza, su nombre, y la cantidad de vendedores que nos la pueden suministrar a ese
precio.
3.
Obtener para los vendedores a los que les hayamos pagado en total (entre todos sus
pedidos) más de 3000 euros, el número y nombre de vendedor junto con el importe total
que les hemos pagado, y el total de pedidos que les hemos hecho.
4.
Obtener para el número y nombre de los vendedores de Alicante a los que se les haya
solicitado alguna pieza, de la que nos habían indicado que su plazo de suministro sería
superior a una semana, junto con el número y nombre de la pieza, y la cantidad de
pedidos distintos en los que se les ha solicitado. Ordena el resultado por la última
columna.
5.
Obtener el nombre de la empresa que tiene más de tres vendedores, y al menos dos de
ellos son de la provincia de Alicante.
6.
Obtener los nombre y empresas de los vendedores que no son de la Comunidad
Valenciana, de los que se desconoce el teléfono.
91
92
adicionales 6
EJERCICIOS
CONSULTAS
1.
Obtener el nombre de la pieza (o piezas) y su precio unitario máximo de la pieza de
precio unitario medio más bajo.
2.
Nombre del vendedor y media de todos sus precios de suministro para los vendedores
que viven en la misma ciudad que algún vendedor de apellido García.
3.
Para la pieza (o piezas) de precio de venta mayor, obtener el nombre de la pieza y
número total de vendedores que la pueden suministrar.
4.
Obtener el nombre de vendedor para los vendedores cuya media de precio unitario de
suministro sea máxima.
5.
Obtener el nombre de la pieza y su precio unitario medio de la pieza más barata de precio
de venta.
6.
Nombre y empresa de los vendedores de la ciudad a la que se le ha solicitado más piezas.
7.
Número de pedido, y número y nombre de vendedor del pedido que no es el de menor
importe de venta (preciocompra*cantrecibida) siendo el año del pedido posterior al 1992
(>1992).
8.
Nombre de los vendedores a los que se les haya solicitado más de dos pedidos en los que
se sirvan discos duros.
9.
Número de pieza, descripción y precio de venta de la pieza que más veces se ha pedido.
10. Número de pieza, descripción, precio medio de suministro y descuento máximo de las
piezas que proceden de la misma ciudad que la empresa Mecemsa y que se han solicitado
2 veces o más.
93
94
adicionales 7
EJERCICIOS
CONSULTAS
1.
Número y nombre de los vendedores que oferten alguna de las piezas que pueden ser
suministradas por el vendedor número 1, pero que no oferten ninguna de las que puedan
ser suministradas por el vendedor número 2.
2.
Obtener el número y el nombre de los vendedores y la cantidad de piezas que pueden
suministrar a un precio entre 15 y 20 euros, ordenado por el nombre de vendedor.
3.
Obtener, para el vendedor que cumple que la diferencia de precio al que le compramos
una pieza y el precio que nos había ofrecido por ella sea máxima, el número de vendedor,
su nombre y la diferencia media entre el precio al que nos vende las piezas y el que nos
había ofrecido por las mismas.
4.
Obtener el número de pieza de los teclados que nos han sido servidos en el mayo de
cualquier año.
5.
Obtener un listado en el que figure el número y nombre de la pieza , junto con el número
y nombre de vendedor que nos ha ofertado la pieza, pero al que nunca se la hemos
solicitado.
6.
Obtener los números y nombres de los vendedores que nos han servido más de tres
artículos diferentes.
95
96
SOLUCIONES SELECT1
Muchas de las soluciones también se muestran en álgebra relacional (AR) y cálculo
relacional de tuplas (CRT), que son temas que se tratarán más adelante en las clases de
teoría. En AR y CRT los resultados son relaciones, por lo tanto todas las soluciones que
se muestran aquí corresponden al enunciado al que se esté dando respuesta, pero eliminando
duplicados. En CRT se consideran declaradas correctamente todas las variables utilizadas.
--1
select numpieza
from pieza
En AR PIEZA[numpieza]
En CRT {P.numpieza/PIEZA(P)}
--2
select nompieza
from pieza
where preciovent < 1000
En AR PIEZA donde preciovent<1000[nompieza]
En CRT {P.nompieza / PIEZA(P) ∧ P.preciovent<1000}
--3
select numpieza, nompieza, preciovent
from pieza
where preciovent > 10 or preciovent < 1
order by preciovent
(la ordenación no se puede expresar ni En CRT ni En AR)
En AR PIEZA donde preciovent>10 o preciovent<1 [numpieza,nompieza,preciovent]
En CRT { P.nompieza, P.nompieza, P.preciovent /
PIEZA(P) ∧ P.preciovent>1000 ∧ P.preciovent<10000}
--4
select numpieza, descuento
from preciosum
order by descuento desc
En AR PRECIOSUM [numpieza, descuento]
En CRT {P.numpieza, P.descuento / PRECIOSUM(P)}
--5
select nomvend
from vendedor
where numvend < 6
--6
select distinct nomvend
from vendedor
where numvend < 6
En AR VENDEDOR donde numvend<6 [nomvend]
En CRT {V.nomvend / VENDEDOR(V) ∧ V.numvend<6}
--7
select numvend, nomvend
from vendedor
where numvend < 6
En AR VENDEDOR donde numvend<6 [numvend, nomvend]
En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ V.numvend<6}
--8
select distinct numvend
from preciosum
--9
select numvend, nomvend
from vendedor
where provincia = 'ALICANTE'
--10
select nomvend, nombrecomer
from vendedor
where provincia = 'ALICANTE'
or provincia = 'CASTELLON'
or provincia = 'VALENCIA'
97
--11
select numvend, diassum
from preciosum
where numpieza = 'P-0001-33'
SOLUCIONES SELECT2
--2
select distinct numpieza, provincia
from preciosum ps, vendedor v
where ps.numvend = v.numvend
order by numpieza desc
(En AR y C.R.T. no se puede hacer order by)
En AR Vendedor ∞ Preciosum [numpieza, provincia]
En CRT {PS.numpieza, V.provincia/ Preciosum(PS) ∧ ∃
V(Vendedor(V) ∧ PS.numvend=V.numvend) }
--9
select preciounit
from preciosum
where numvend = 100 and numpieza='A-1001-L'
En AR Preciosum donde numvend=100 y numpieza=A-1001-L
[precionuit]
En CRT {PS.preciounit / Preciosum(PS) ∧ numvend=100 ∧
numpieza=A-1001-L }
--17
select p.numpieza, nompieza
from preciosum ps, pieza p
where ps.numpieza=p.numpieza
and (numvend = 2
or numvend = 4)
En AR Pieza ∞ Preciosum donde numvend=2 o numvend=4
[numpieza, nompieza]
En CRT {P.numpieza, P.nompieza/ Pieza(P) ∧ ∃ PR
(Preciosum(PR) ∧ P.numpieza=PR.numpieza ∧ (numvend=2 ∨
numvend=4)) }
--19
select nompieza, l.numpieza, preciovent
from pieza pz, pedido p,linped l
where numvend = 1
and p.numpedido=l.numpedido
and l.numpieza=pz.numpieza
En AR Pieza ∞ Linped ∞ Pedido donde numvend=1 [numpieza,
nompieza, preciovent]
En CRT {P.numpieza, P.nompieza P.preciovent/ Pieza(P) ∧ ∃ LP
(Linped(LP) ∧ P.numpieza=LP.numpieza ∧ ∃ P (Pedido(P) ∧
LP.numpedido=P.numpedido ∧ numvend=1)) }
SOLUCIONES SELECT3
En AR y CRT no existe el operador LIKE, ni el operador IS
NULL, así como tampoco se puede establecer un criterio para
ordenar el resultado.
--1
select nompieza
from pieza p, preciosum ps, vendedor v
where p.numpieza = ps.numpieza
and ps.numvend = v.numvend
and nomvend like 'S%'
98
--2
select nompieza
from pieza p, preciosum ps, vendedor v
where p.numpieza = ps.numpieza
and ps.numvend = v.numvend
and (nomvend like 'S% MARTIN %'
or nomvend like 'S% MARTINEZ %')
--3
select nomvend
from vendedor
where provincia in ('ALICANTE', 'VALENCIA', 'CASTELLON')
order by nomvend
En AR Vendedor donde provincia=Alicante o
provincia=Castellón o provincia=Valencia [nomvend]
En CRT {V.nomvend / Vendedor(V) ∧ (provincia=Alicante ∨
provincia=Castellon ∨ provincia=Valencia)}
--7
select nomvend
from vendedor
where nomvend like 'M_R%'
order by nomvend
--12
select *
from vendedor
where telefono is not null
order by nomvend
SOLUCIONES SELECT FECHA
--1
select numpieza
from inventario
where fecharecuento=’15/10/1992’
--2
select numpieza
from inventario
where fecharecuento >= '1/10/1992' and fecharecuento <='31/10/1992'
--3
select numpedido, fecha
from pedido
where fecha >= '1/7/1992' and fecha <= '31/12/1992';
select numpedido, fecha
from pedido
where to_char(fecha,'YY') = '92' and to_char(fecha,'MM') >= 6;
--4
select distinct nomvend
from vendedor v, pedido pd, linped l
where v.numvend = pd.numvend
and pd.numpedido = l.numpedido
and to_char(fecharecep,'YYYY') = 1992
and to_char(fecharecep,'MM') = 5
and to_char(fecharecep,'DD') <= 15
order by nomvend
--7
select distinct pz.numpieza, nompieza
from linped l, pieza pz
where l.numpieza = pz.numpieza
and to_char(fecharecep,'DD') = 10
99
SOLUCIONES CREATE
Algunas de las órdenes provocan errores, se debe identificar el origen del mismo.
--1 tabla creada
--2 ninguna fila seleccionada
--3 1 fila creada
--4 ERROR
--5 1 fila creada
--6
col1 col2
---- ---1
AA
2
BB
--9 tabla borrada
--10 ERROR
--11 tabla creada
--12 1 fila
1 fila
1 fila
1 fila
ERROR
ERROR
ERROR
1 fila
1 fila
creada
creada
creada
creada
creada
creada
--13 create table listin
(apodo varchar2(10),
nombre varchar2(25),
telefono varchar2(9),
primary key (apodo)
);
--14 drop table listin;
create table listin
(apodo varchar2(10),
nombre varchar2(25),
telefono varchar2(9),
grado integer,
primary key (apodo)
);
--15 create table compra
(orden integer,
articulo varchar2(40),
cantidad integer,
formato varchar2(10),
precioEstimado number(5,2),
primary key (orden)
);
SOLUCIONES MANIPULACIÓN1
--1
create table listin
(apodo varchar2(10),
nombre varchar2(25),
telefono varchar2(9),
grado integer,
primary key (apodo)
);
insert into listin (apodo,nombre,grado) values ('semao','Paco Musoso',2);
insert into listin (apodo,nombre,grado,telefono)
values ('aguila','Luis Ligero',1,'555111222');
100
insert into listin (apodo,nombre,grado,telefono)
values ('largo','Juan Pitillo',1,'555111333');
insert into listin (apodo,nombre,grado)values ('sobrao','Cristobal Garcilaso',5);
--2
create table amistad
(grado integer,
descripcion varchar2(20),
primary key (grado)
);
--3
drop table listin;
create table listin
(apodo varchar2(10),
nombre varchar2(25),
telefono varchar2(9),
grado integer,
primary key (apodo),
foreign key (grado) references amistad(grado)
);
--4
ERROR: No se puede insertar ninguna fila
restricción de integridad (BD1.SYS_C004090) violada - clave
principal no encontrada
SOLUCIONES MANIPULACIÓN2
-- 1
update inventario set fecharecuento=’01/01/2003’;
-- 2
update inventario set cantminima=cantdisponible where cantdisponible<cantminima;
-- 3
update vendedor set telefono='SIN TLFNO' where telefono is null;
-- 4
update vendedor set calle='CENTRAL, 5', provincia='SALAMANCA', ciudad='SALAMANCA'
where provincia='TOLEDO';
-- 5
update pieza set nompieza='SIN DESCRIPCION' where nompieza is null;
-- 9
update pedido set numvend=1000 where numvend=200;
--restricción de integridad violada
-- 10
update pedido set numpedido=4 where numpedido=8;
update pedido set numpedido=1 where numpedido=5;
--restricción única violada
update pedido set numpedido=8 where numpedido=2;
--restricción de integridad violada, encontrado registro secundario
update pedido set numpedido=3 where numpedido=2;
--restricción única violada
-- 13
update pieza set nompieza=(select nompieza from pieza where preciovent=7)
where nompieza=’SIN DESCRIPCION’;
--La subconsulta devuelve más de una fila
101
-- 16
update preciosum set (numpieza, preciounit) =
(select numpieza, preciovent from pieza
where nompieza = ‘DISKETTE 1.44 PANASONIC’)
where numvend=200;
--se viola la clave primaria de preciosum, ya que hay varias filas para
--ese número de vendedor
-- 17
update pedido set fecha=to_date(sysdate,’DDMMYYYY’) where numvend=3;
-- 19
update inventario set periodorecuen = (select periodorecuen from inventario
where fecharecuento > ‘1/01/2003’)
where fecharecuento < ‘01/01/2003’;
--la subconsulta puede devolver más de una fila
SOLUCIONES MANIPULACIÓN3
-- 1
delete from vendedor where numvend = 1;
-- 2
El vendedor 1 tiene suministros (PRECIOSUM) y pedidos (PEDIDO). Dada la definición
de claves ajenas en PRECIOSUM, el borrar la fila de este vendedor provoca el borrado
automático de todas sus filas en PRECIOSUM.
También ocurre lo mismo en PEDIDOS, pero esta tabla está, a su vez, referenciada en
LINPED con una clave ajena que también tiene establecida la PROPAGACIÓN como mecanismo
para mantener la integridad referencial ante borrados en PEDIDO: todas las filas de los
pedidos del vendedor 1 (los pedidos 1, 2, y 5) son eliminadas también.
Resumiendo, por la definición de claves ajenas en la BD, el borrado del vendedor 1
afecta a las tablas PRECIOSUM, PEDIDO y LINPED, quedando PIEZA e INVENTARIO como estaban
ya que en ellas no se generan problemas de integridad referencial.
-- 3
delete from vendedor where numvend = 3;
-- 4
El vendedor 3 tiene suministros (PRECIOSUM) y pero no pedidos. Borrar la fila de
este vendedor provoca el borrado automático de todas sus filas en PRECIOSUM, pero no se
producen más operaciones en ninguna otra tabla.
-- 5
delete from vendedor where numvend = 8001;
-- 6
El vendedor 8001 no tiene suministros (PRECIOSUM) ni pedidos. Por tanto, la única
fila eliminada es la propia del vendedor en la tabla VENDEDOR.
-- 7
delete from pedido where numpedido = 3;
-- 8
El borrado del pedido 3 provoca la eliminación automática de todas sus líneas
pedido pero nótese que el vendedor 2 (al que pertenecía este pedido) sigue estando en
tabla VENDEDOR (como ocurría en las operaciones anteriores, por cierto, con las líneas
pedido borradas automáticamente pero no sus piezas en PIEZA). Los únicos problemas
integridad referencial, en este caso, se producen en LINPED.
de
la
de
de
-- 9
delete from pieza where numpieza = ‘O-0001-PP’;
La pieza ‘O-0001-PP’ tiene referencias en la tabla PRECIOSUM (también en LINPED), y
como no se ha modificado la clave ajena en esta tabla, el sistema tiene como política
asignada por defecto RECHAZAR: la operación ha generado un error.
-- 10
delete from preciosum where numpieza = ‘O-0001-PP’;
102
-- 12
delete from pieza where numpieza = ‘O-0001-PP’;
La pieza ‘O-0001-PP’ ya no tiene referencias en la tabla PRECIOSUM, pero sigue
manteniendo las de LINPED. En esta tabla se ha definido la ANULACIÓN como política ante
borrados en PIEZA: todas las referencias a esta pieza se han sustituido por NULOS.
-- 14
delete from pieza where numpieza = ‘DD-0001-210’;
La pieza ‘DD-0001-210’ no tiene referencias en la tabla PRECIOSUM puesto que las
hemos eliminado en la orden 13, pero sí las tiene en LINPED e INVENTARIO. En ambas tablas
se ha elegido la ANULACIÓN para las clavea ajenas a PIEZA, pero mientras es posible
aplicarla en LINPED, en INVENTARIO es imposible ya que la clave ajena no admite nulos (es
clave alternativa al definirla como UNIQUE y NOT NULL simultáneamente). La operación no
puede realizarse.
SOLUCIONES CONJUNTOS
--1
select nombrecomer from vendedor v,pedido p where v.numvend=p.numvend
UNION
select nombrecomer from vendedor v, preciosum ps
where v.numvend=ps.numvend and numpieza='A-1001-L'
En AR Vendedor ∞ Pedido [nombrecomer] ∪ (Vendedor ∞ Preciosum donde
numpieza = ‘A-1001-L’ [nombrecomer])
--2
select nombrecomer from vendedor v,pedido p where v.numvend=p.numvend
INTERSECT
select nombrecomer from vendedor v, preciosum ps
where v.numvend=ps.numvend and numpieza='A-1001-L'
--o también:
select nombrecomer
from vendedor v,pedido p, preciosum ps
where v.numvend=p.numvend
and v.numvend=ps.numvend and numpieza='A-1001-L'
En AR Vendedor ∞ Pedido [nombrecomer] ∩ (Vendedor ∞ Preciosum donde
numpieza = ‘A-1001-L’ [nombrecomer])
--3
En AR Vendedor ∞ Pedido [nombrecomer] - (Vendedor ∞ Preciosum donde
numpieza = ‘A-1001-L’ [nombrecomer])
SOLUCIONES FUNCIONES
--1
select numlinea, cantrecibida-cantpedida diferencia
from linped
where numpedido = 1
--2
select avg(abs(fecha-fecharecep)) mediarecep
from linped l, pedido pd
where pd.numpedido = 1
and l.numpedido = pd.numpedido
--3
select count(distinct provincia) provincias
from vendedor
103
--4
select min(preciocompra-preciounit) minimo
from preciosum ps, pedido pd, linped l
where ps.numvend = pd.numvend
and pd.numpedido = l.numpedido
and l.numpieza = ps.numpieza
--5
select avg(distinct preciovent) mediaventa
from pieza
SOLUCIONES GROUP BY
En AR y C.R.T. no hay definidas funciones agregadas por lo
que muchos de los requerimientos nos los podríamos abordar,
sobre todo si estas funciones agregadas aparecen en la
cláusula SELECT.
--1
select nompieza, preciovent, avg(preciovent-preciounit) media
from pieza p, preciosum ps
where p.numpieza=ps.numpieza
group by p.numpieza,nompieza,preciovent
order by nompieza
--2
select numpedido, sum(preciocompra*cantrecibida) precioPagado,
sum(cantpedida) cantidadPedida,
sum(cantpedida-cantrecibida) no_recibido
from linped
group by numpedido
order by numpedido
--3
select count(*) vendedores, nombrecomer
from vendedor
group by nombrecomer
order by vendedores desc, nombrecomer
--4
select numpieza, max(cantpedida-cantrecibida) maximo
from linped
group by numpieza
order by numpieza
--5
select numpieza, count(*) vendedores
from preciosum
group by numpieza
order by numpieza
--6
select ps.numpieza, count(*) vendedores
from preciosum ps, pieza p
where ps.numpieza = p.numpieza
and preciovent >= 250
group by ps.numpieza
order by 2
--7
select numpieza,avg(preciounit) precio_Sum_Medio
from preciosum
group by numpieza
order by numpieza
--13
select p.numpieza, max(preciovent)/avg(preciocompra)*100
from linped l, pieza p
where l.numpieza=p.numpieza
group by p.numpieza
order by p.numpieza
104
SOLUCIONES GROUP BY - HAVING
En AR y CRT no hay definidas funciones de agregados por lo
que muchos de los requerimientos nos los podríamos abordar,
sobre todo si estas funciones agregadas aparecen en la
cláusula SELECT.
--1
select nombrecomer
from vendedor
group by nombrecomer
having count(*)>2
En AR Define alias V1, V2 para VENDEDOR
V1 × V2 × VENDEDOR donde V1.nombrecomer=V2.nombrecomer and
V2.nombrecomer=Vendedor.nombrecomer and
V1.numvend<>V2.numvend and V1.numvend<> VENDEDOR.numvend and
V2.numvend<>Vendedor.numvend [V1.nombrecomer]
En CRT {V1.nombrecomer | VENDEDOR(V1) ∧ ∃ V2(VENDEDOR(V2) ∧
V1.nombrecomer=V2.nombrecomer ∧ V1.numvend<>V2.numvend ∧ ∃
V3(VENDEDOR(V3) ∧ V2.nombrecomer=V3.nombrecomer ∧
V1.numvend<>V3.numvend ∧ V2.numvend<>V3.numvend))}
--2
select numpedido
from linped
group by numpedido
having count(*)>3
En AR Define alias LP1, LP2, LP3 para LINPED
LP1 × LP2 × LP3 × LINPED donde LP1.numpedido=LP2.numpedido
and LP2.numpedido=LP3.numpedido and
LP3.numpedido=LINPED.numpedido and LP1.numlinea<>LP2.numlinea
and LP1.numlinea<> LP3.numlinea and LP1.numlinea<>
LINPED.numlinea and LP2.numlinea<> LP3.numlinea and
LP2.numlinea<>LINPED.numlinea and LP3.numlinea<>
LINPED.numlinea [LP1.numpedido]
En CRT {LP1.numpedido | LINPED(LP1) ∧ ∃ LP2 ∃ LP3 ∃ LP4
(LINPED(LP2) ∧ LINPED(LP3) ∧ LINPED(LP4) ∧
LP1.numpedido=LP2.numpedido ∧ LP1.numlinea<>LP2.numlinea ∧
LP1.numlinea<>LP3.numlinea ∧ LP1.numlinea<>LP4.numlinea ∧
LP2.numpedido=LP3.numpedido ∧ LP3.numpedido=LP4.numpedido ∧
LP2.numlinea<>LP4.numlinea ∧ LP3.numlinea<>LP4.numlinea) }
--3
select numpedido
from linped
group by numpedido
having sum(cantpedida)>40
--4
select numpedido
from linped l
group by numpedido
having sum(cantrecibida*preciocompra)>1000
--5
select numpieza, max(preciounit), count(*)
from preciosum
group by numpieza
having avg(preciounit)>260
--6
select numpieza, max(preciounit) maximo, count(*) cuantos
from preciosum
where preciounit >= 250
group by numpieza
having avg(preciounit)>260
--7
select p.numpedido, fecha
from pedido p, linped l
where p.numpedido=l.numpedido
group by p.numpedido,fecha
having sum(cantpedida)>30 and sum(cantrecibida)<10
105
--10
select p.numpieza,nompieza,max(preciounit) maximo
from pieza p,preciosum ps
where ps.numpieza=p.numpieza
and preciovent > 250 or preciovent < 170
group by p.numpieza,nompieza
having avg(descuento) between 10 and 17
and avg(preciounit) > 150
order by maximo
SOLUCIONES SUBSELECT
--1
select *
from vendedor
where numvend in (select numvend
from pedido
group by numvend
having count(*) >= all(select count(*)
from pedido
group by numvend))
--2
select numvend, nomvend
from vendedor
where numvend not in (select numvend
from preciosum)
order by nomvend
En AR (VENDEDOR[numvend] ∼ PRECIOSUM[numvend]) ∞
VENDEDOR[numvend, nomvend]
En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ⎤ ∃
PR(PRECIOSUM(PR) ∧ PR.numvend=V.numvend)}
--3a
select v.numvend, nomvend
from vendedor v, pedido p
where v.numvend = p.numvend
order by nomvend
En AR VENDEDOR ∞ PEDIDO [numvend, nomvend]
En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃ P(PEDIDO(P) ∧
P.numvend=V.numvend)}
--3b
select numvend, nomvend
from vendedor
where numvend in (select numvend
from pedido)
order by nomvend
--11
select v.numvend,count(distinct numpieza) npiezas
from vendedor v, pedido p, linped l
where v.numvend=p.numvend
and p.numpedido=l.numpedido
and nombrecomer in
(select nombrecomer
from vendedor
group by nombrecomer
having count(*) >= all
(select count(*)
from vendedor
group by nombrecomer))
group by v.numvend
order by v.numvend
--15
select p.numpieza, nompieza,avg(preciounit),max(preciocompra)
from pieza p, preciosum ps, linped l
where p.numpieza=ps.numpieza and ps.numpieza=l.numpieza
group by p.numpieza, nompieza
having avg(preciounit)>=
(select max(preciocompra)
from linped
where linped.numpieza=p.numpieza)
106
SOLUCIONES SUBSELECT - EXISTS
--1
select nomvend
from vendedor v
where not exists
(select *
from pieza pz
where not exists
(select *
from preciosum
where numvend = v.numvend and numpieza = pz.numpieza))
En AR ((PRECIOSUM [numvend, numpieza] ÷ PIEZA[numpieza]) ∞
VENDEDOR) [nomvend]
En CRT { V.nomvend / VENDEDOR(V) ∧ ∀P (PIEZA(P) ⇒ ∃ PR
(PRECIOSUM(PR) ∧ PR.numvend=V.numvend ∧
PR.numpieza=P.numpieza ))}
--2
select nomvend
from vendedor
where numvend not in (select numvend
from preciosum)
order by nomvend
--2
select nomvend
from vendedor v
where not exists (select *
from preciosum
where numvend = v.numvend)
order by nomvend
En AR ((VENDEDOR[numvend] ∼ PRECIOSUM[numvend]) ∞
VENDEDOR)[nomvend]
En CRT {V.nomvend / VENDEDOR(V) ∧ ⎤ ∃ PR(PRECIOSUM(PR) ∧
PR.numvend=V.numvend)}
--3
select numpieza, nompieza
from pieza pz
where not exists
(select *
from pedido pd
where numvend=1
and not exists (select *
from linped l
where pd.numpedido=l.numpedido
and pz.numpieza=l.numpieza))
En AR ((LINPED [numpieza, numpedido] ÷ (PEDIDO donde
numvend=1)[numpedido]) ∞ PIEZA) [numpieza, nompieza]
En CRT { P.numpieza, P.nompieza / PIEZA(P) ∧ ∀PD (PEDIDO(PD)
∧ PD.numvend=1 ⇒ ∃ LP (LINPED(LP) ∧
LP.numpedido=PD.numpedido ∧ LP.numpieza=P.numpieza ))}
--4
select distinct nombrecomer
from vendedor v
where not exists
(select *
from vendedor
where nombrecomer = v.nombrecomer
and provincia not in ('ALICANTE','CASTELLON','VALENCIA'))
order by nombrecomer
En AR VENDEDOR[nombrecomer] ∼ (VENDEDOR donde
provincia<>ALICANTE or provincia<>CASTELLON or
provincia<>VALENCIA)[nombrecomer]
En CRT { V.nombrecomer / VENDEDOR(V) ∧ ∀ V2 (VENDEDOR(V2) ∧
V2.nombrecomer=V.nombrecomer ⇒ (V2.provincia=ALICANTE ∨
V2.provincia=CASTELLON ∨ V2.provincia=VALENCIA))}
O bien
{ V.nombrecomer / VENDEDOR(V) ∧ ⎤ ∃ V2 (VENDEDOR(V2) ∧
V2.nombrecomer=V.nombrecomer ∧ V2.provincia<>ALICANTE ∧
V2.provincia<>CASTELLON ∧ V2.provincia<>VALENCIA))}
107
SOLUCIONES ADICIONALES 1
--3
select distinct numvend
from preciosum ps, pieza p, linped l
where ps.numpieza = p.numpieza
and p.numpieza = l.numpieza
and preciovent between 50 and 100
order by numvend
En AR PIEZA ∞ PRECIOSUM ∞ LINPED donde preciovent≥50 and
preciovent≤100 [numvend]
En CRT {PR.numvend / PRECIOSUM(PR) ∧ ∃ P (PIEZA(P) ∧
P.numpieza=PR.numpieza ∧ preciovent≥5000 ∧ preciovent≤10000 ∧
∃ LP (LINPED(LP) ∧ PR.numpieza=LP.numpieza)) }
--4
select nombrecomer
from vendedor v, pedido pd, linped l, pieza p
where v.numvend = pd.numvend
and pd.numpedido = l.numpedido
and l.numpieza = p.numpieza
and nompieza like '%MONITOR%'
and provincia = 'ALICANTE'
--5
select nompieza, p.numpieza
from pieza p, linped l
where p.numpieza = l.numpieza
order by nompieza
En AR PIEZA ∞ LINPED [numpieza, nompieza]
En CRT {P.numpieza, P.nompieza / PIEZA(P) ∧ ∃ LP (LINPED(LP)
∧ P.numpieza=LP.numpieza) }
--6
select ps.numpieza, preciounit - preciocompra
from linped l, pedido pd, preciosum ps
where l.numpedido = pd.numpedido
and pd.numvend = ps.numvend
and ps.numpieza = l.numpieza
order by diferencia
En AR PRECIOSUM ∞ PEDIDO ∞ LINPED [numpieza, preciounit,
preciocompra]
En CRT {PR.numpieza, PR.preciounit, LP.preciocompra /
PRECIOSUM(PR) ∧ LINPED(LP) ∧ ∃ P (PEDIDO(P) ∧
PR.numvend=P.numvend ∧ P.numpedido=LP.numpedido ∧
PR.numpieza=LP.numpieza) }
En AR y C.R.T.: no está considerada, en la formalización de
estos lenguajes, la resta como resultado.
--7
select distinct v.numvend, nombrecomer
from vendedor v, pedido pd, linped l, preciosum ps
where ps.numvend = v.numvend
and v.numvend = pd.numvend
and pd.numpedido = l.numpedido
and l.numpieza = ps.numpieza
and preciocompra > preciounit
En AR VENDEDOR ∞ PRECIOSUM ∞ PEDIDO ∞ LINPED donde
preciocompra > preciounit [numvend, nomvend]
En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃
PR(PRECIOSUM(PR) ∧ V.numvend=PR.numvend ∧ ∃ P (PEDIDO(P) ∧
PR.numvend=P.numvend ∧ ∃ LP(LINPED(LP) ∧
P.numpedido=LP.numpedido ∧ PR.numpieza=LP.numpieza ∧
preciocompra > p
109
SOLUCIONES ADICIONALES 2
--1
select nomvend,count(*) cantidad
from preciosum ps, vendedor v
where ps.numvend=v.numvend
group by v.numvend,nomvend
order by nomvend
--2
select v.numvend,nomvend,count(*) cantidad
from preciosum ps, vendedor v
where ps.numvend=v.numvend
group by v.numvend,nomvend
order by nomvend
--6
select numvend, nomvend
from vendedor v, pedido p, linped lp
where v.numvend = p.numvend
and p.numpedido = lp.numpedido
group by p.numpedido,v.numvend, nomvend
having count(distinct numpieza)> 3
En AR Define alias LP1, LP2, LP3 para LINPED
LP1 × LP2 × LP3 × LINPED donde LP1.numpedido=LP2.numpedido
and LP2.numpedido=LP3.numpedido and
LP3.numpedido=LINPED.numpedido and LP1.numpieza<>LP2.numpieza
and LP1.numpieza<> LP3.numpieza and LP1.numpieza<>
LINPED.numpieza and LP2.numpieza<> LP3.numpieza and
LP2.numpieza<>LINPED.numpieza and LP3.numpieza<>
LINPED.numpieza [LP1.numpedido] ∞ PEDIDO ∞ VENDEDOR [numvend,
nomvend]
En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃ P (PEDIDO(P) ∧
P.numvend=V.numvend) ∧ ∃ LP1 ( LINPED(LP1) ∧
LP1.numpedido=P.numpedido ∧ ∃ LP2 (LINPED(LP2) ∧
LP1.numpedido=LP2.numpedido ∧ ∧ LP1.numpieza<>LP2.numpieza ∧
∃ LP3 (LINPED(LP3) ∧ LP2.numpedido=LP3.numpedido ∧
LP1.numpieza<>LP3.numpieza ∧ LP2.numpieza<>LP3.numpieza ∧ ∃
LP4 (LINPED(LP4) ∧ LP3.numpedido=LP4.numpedido ∧
LP1.numpieza<>LP4.numpieza ∧ LP2.numpieza<>LP4.numpieza ∧
LP3.numpieza<>LP4.numpieza))))) }
--4
select p.numpedido, count(*), p.numvend, nomvend, fecha from pedido p, linped l,
vendedor v where p.numvend = v.numvend and p.numpedido = l.numpedido group by
p.numpedido, p.numvend, nomvend, fecha
(en este caso coincide count(*) y count(distinct numlinea)
--7
select v.numvend, nomvend from vendedor v, pedido p where v.numvend = p.numvend
--8
select nompieza, avg(preciosum), preciovent from preciosum ps, pieza p where
p.numpieza = ps.numpieza group by nompieza, preciovent having avg(preciosum) > 100
and count(*) > 2
(aquí también coincide count(*) y count(distinct numvend)
--9
select nompieza, avg(preciounit) media, preciovent
from preciosum ps, pieza p
where ps.numpieza=p.numpieza
and preciovent > 30000
group by p.numpieza,nompieza,preciovent
having count(*)>2
and avg(preciounit) between 100 and 280
order by p.nompieza
--10
select p.numpieza, nompieza from pieza p, preciosum ps where p.numpieza =
ps.numpieza group by p.numpieza, nompieza, preciovent having preciovent*20/100 >
avg(preciounit)
(necesito poner el preciovent en el group by porque es no calculado)
110
SOLUCIONES ADICIONALES 3
--1
select v.numvend, nomvend, count(*) cantidadPED
from vendedor v, pedido p
where v.numvend=p.numvend and provincia=’ALICANTE’
group by v.numvend, nomvend
--4
select p.numpieza, nompieza, max(preciounit) maxPrecio,
min(preciounit) minPrecio, count(*) totalVend
from preciosum ps, pieza p
where ps.numpieza=p.numpieza
group by p.numpieza, nompieza
having avg(preciounit)<10
--5
select p.numpedido, v.numvend, nomvend, count(distinct fecharecep)
from vendedor v, pedido p, linped lp
where v.numvend = p.numvend
and p.numpedido = lp.numpedido
group by p.numpedido, v.numvend, nomvend
having count(distinct fecharecep)> 1
--7
select p.numpieza, nompieza, v.numvend, nomvend
from pieza p, linped lp , pedido ped, vendedor v
where lp.numpieza=p.numpieza and lp.numpedido=ped.numpedido
and ped.numvend=v.numvend and to_char(fecharecep, ‘d’)=7
order by 2
SOLUCIONES ADICIONALES 4
--1
select v.numvend, nomvend
from pedido p, vendedor v
where p.numvend=v.numvend and to_char(fecha,‘yyyy’)=1995
minus
select v.numvend, nomvend
from pedido p, vendedor v
where p.numvend=v.numvend and to_char(fecha,‘yyyy’)=1992
--4
select numpieza, nompieza
from pieza
minus
select p.numpieza, nompieza
from linped lp, pieza p
where lp.numpieza=p.numpieza
En AR
PIEZA[numpieza, nompieza]
∼ (PIEZA ∞ LINPED)[numpieza, nompieza]
En CRT {P.numpieza, P.nompieza / PIEZA(P) ∧ ⎤ ∃ LP(LINPED(LP)
∧ LP.numpieza=P.numpieza}
111
--5
select numvend
from preciosum ps, linped lp
where ps.numpieza=lp.numpieza and numpedido=1 and numlinea=1
intersect
select numvend
from preciosum ps, linped lp
where ps.numpieza=lp.numpieza and numpedido=1 and numlinea=2
intersect
select numvend
from preciosum ps, linped lp
where ps.numpieza=lp.numpieza and numpedido=1 and numlinea=3
En AR Define alias V1, V2 para VENDEDOR
PRECIOSUM [numvend, numpieza] ÷
LINPED DONDE (numpedido=1 and (numlinea=1 or numlinea=2 or
numlinea=3)) [numpieza]
En CRT
{V.numvend / VENDEDOR(V) ∧
∀ LP (LINPED(LP) ∧ LP.numpedido=1 ∧ (LP.numlinea=1 ∨
LP.numlinea=2 ∨ LP.numlinea=3) ⇒
∃ PS(PRECIOSUM(PS) ∧ PS.numpieza=LP.numpieza ∧
PS.numvend=V.numvend) ) }
--6
select v.numvend, nomvend, sum(cantrecibida*preciocompra) Total
from vendedor v, pedido p, linped lp
where v.numvend=p.numvend and p.numpedido=lp.numpedido
and provincia I (‘ALICANTE’, ‘MADRID’)
group by v.numvend, nomvend
SOLUCIONES ADICIONALES 5
--1
select p.numpedido, v.numvend, nomvend, fecha
from pedido p, linped lp, vendedor v
where p.numvend=v.numvend and p.numpedido=lp.numpedido
group by p.numpedido, fecha, v.numvend, nomvend
having sum(ctdpedida*preciocompra) between 400 and 600
--4
select v.numvend, nomvend, p.numpieza, nompieza, count(distinct numpedido)
from vendedor v, preciosum ps, pedido pd, linped lp, pieza p
where v.numvend = pd.numvend and v.numvend=ps.numvend
and pd.numpedido = lp.numpedido and p.numpieza=lp.numpieza and
p.numpieza=ps.numpieza and diassum>7
group by v.numvend, nomvend, p.numpieza, nompieza
order by 5
--5
select nombrecomer
from vendedor
group by nombrecomer
having count(*)>3
intersect
select nombrecomer
from vendedor
where provincia=’AICANTE’
group by nombrecomer
having count(*)>1
--6
select nomvend, nombrecomer
from vendedor
where provincia not in (‘ALICANTE’,’CASTELLON’,’VALENCIA’) and telefono is null
112
SOLUCIONES ADICIONALES 6
--2
select nomvend, avg(preciounit) mediasumin
from vendedor v, preciosum ps
where v.numvend=ps.numvend
and ciudad IN (select ciudad
from vendedor
where nomvend like '%GARCIA%')
group by v.numvend, nomvend,ciudad
order by mediasumin
--7
select numpedido, v.numvend, nomvend, fecha
from pedido p, vendedor v
where p.numvend=v.numvend
and to_char(fecha,'YYYY')>1992
and numpedido in (select numpedido
from linped
group by numpedido
having sum(preciocompra*cantrecibida) > any
(select sum(preciocompra*cantrecibida)
from linped
group by numpedido))
--10
select ps.numpieza, nompieza, avg(preciounit) media,
max(descuento) descuento
from preciosum ps, pieza pz, vendedor v
where ps.numpieza=pz.numpieza and v.numvend=ps.numvend
and v.ciudad in (select ciudad
from vendedor
where nombrecomer='MECEMSA')
and ps.numpieza in (select numpieza
from linped
group by numpieza
having count(*)>1)
group by ps.numpieza,nompieza
order by ps.numpieza
SOLUCIONES ADICIONALES 7
--1
select v.numvend, nomvend
from vendedor v, preciosum ps
where v.numvend=ps.numvend and
numpieza IN (select numpieza from preciosum where numvend=1)
and numvend NOT IN (
select v.numvend, nomvend
from vendedor v, preciosum ps
where v.numvend=ps.numvend and
numpieza IN (select numpieza from preciosum where numvend=2))
113
--1
select numvend, nomvend
from vendedor
where numvend IN (
select numvend from preciosum
where numpieza IN (select numpieza from preciosum where numvend=1)
MINUS
select numvend from preciosum
where numpieza IN (select numpieza from preciosum where numvend=2))
En AR
(PRECIOSUM donde numvend=1 [numpieza] ∞ PRECIOSUM ∞
VENDEDOR)[numvend, nomvend]
∼ (PRECIOSUM donde numvend=2 [numpieza] ∞ PRECIOSUM ∞
VENDEDOR)[numvend, nomvend]
En CRT {V1.numvend, V1.nomvend / VENDEDOR(V1) ∧ ∃
PS1(PRECIOSUM(PS1) ∧ PS1.numvend=V1.numvend ∧ ∃
PS2(PRECIOSUM(PS2) ∧ PS2.numvend=1 ∧
PS1.numpieza=PS2.numpieza ∧
⎤ ∃ PS3(PRECIOSUM(PS3) ∧ PS3.numvend=V1.numvend ∧ ∃
PS4(PRECIOSUM(PS4) ∧ PS4.numvend=2 ∧
PS3.numpieza=PS4.numpieza)) ) ) }
--3
select v.numvend, nomvend, avg(preciocompra-preciounit) DifMedia
from preciosum ps, pedido p, linped lp, vendedor v
where p.numpedido=lp.numpedido and ps.numvend=p.numvend
and lp.numpieza=ps.numpieza and p.numvend=v.numvend
group by v.numvend, nomvend
having max(precicompra-preciounit) =
(Select max(preciocompra–preciounit)
from preciosum ps, pedido p, linped lp
where p.numpedido=lp.numpedido and ps.numvend=p.numvend
and lp.numpieza=ps.numpieza)
--4
select numpieza
from pieza p, linped lp
where p.numpieza=lp.numpieza and nompieza like ‘%TECLADO%’
and to_char(fecharecep, ‘mm’)=5
--6
select v.numvend, nomvend
from vendedor v, pedido p, linped lp
where v.numvend=p.numvend and p.numpedido=lp.numpedido
group by v.numvend, nomvend
having count(distinct numpieza)>3
114
Descargar