SELECT nombre, altura FROM Puerto WHERE categoria = 1

Anuncio
1.
Práctica 3:
Lenguaje de Manipulación del SQL
Se presentan las instrucciones que se pueden ejecutar desde un intérprete
de SQL, lo que se denomina SQL interactivo.
Lenguaje SQL
1ª Parte: Manipulación de Bases de Datos
SQL es un lenguaje muy expresivo y, en general, permite muchas formas
de expresar las misma órdenes.
Objetivos:
Las cuatro instrucciones que componen el lenguaje de manipulación de
datos son las siguientes:
•Presentar la sintaxis del lenguaje SQL (sólo del Lenguaje de
Manipulación).
•Ver algunos ejemplos sencillos para clarificar la semántica del SQL.
•select: permite la declaración de consultas para la recuperación de
información de una o más tablas de una base de datos.
•Presentar las bases de datos CICLISMO, MÚSICA y BIBLIOTECA.
•insert: realiza la inserción de una o varias filas sobre una tabla.
•Realizar de menor a mayor complejidad consultas SQL sobre dichas
bases de datos.
•delete: permite efectuar el borrado de una o varias filas de una
tabla.
•Realizar todo lo anterior usando la herramienta ISQL del sistema de
gestión de bases de datos ORACLE.
•update: realiza una modificación de los valores de una o más
columnas de una o varias filas de una tabla.
2
1
1.1.1.
1.1. Consultas: instrucción select
select [all | distinct] comalista_item_seleccionado | *
from comalista_referencia_tabla
[where expresión_condicional]
[group by comalista_referencia_col]
[having expresión_condicional]
3
1
from tabla
2
[where expresión_condicional]
4
[order by comalista_referencia_col]
•comalista_item_seleccionado: información a obtener de la base de datos.
•from comalista_referencia_tabla: especifica de qué tablas se obtiene la
información buscada.
•where expresión_condicional: expresa una condición que deben cumplir
las filas de la consulta resultante.
•group by comalista_referencia_col: permite formar consultas agrupadas
para extraer información global sobre los grupos formados.
•having expresión_condicional: condición sobre los grupos formados.
•order by comalista_referencia_col: ordena por una o varias columnas.
Condiciones en consultas simples
select [all | distinct] comalista_ítem_seleccionado | *
[order by comalista_referencia_col]
•all : Permite la aparición de filas idénticas (valor por defecto).
•distinct: No permite la aparición de filas idénticas.
•La expresión_condicional está formada por un conjunto de predicados
combinados con las conectivas lógicas and, or y not. Los predicados
utilizados permiten comparar columnas:
•predicados de comparación: =, <>, >, <, >=, <=.
•predicado like: permite comparar una tira de caracteres con un patrón.
•predicado between: permite comprobar si un escalar está en un rango.
•predicado in: permite comprobar si el valor está dentro de un conjunto.
•predicado is null: permite comprobar si el valor es nulo.
3
EQUIPO(nom_eq: d_eq, director: d_dir)
Ciclismo
Clave Primaria: {nom_eq}
CICLISTA(dorsal: d_dor, nombre: d_nom, edad: d_edad, nom_eq: d_eq))
Clave Primaria: {dorsal}
CAj: {nom_eq} hace referencia a EQUIPO
VNN: {nom_eq}
4
EJEMPLO: Obtener el nombre y la altura de todos los puertos de 1ª categoría.
⇑
⇑
ETAPA(nºetapa: d_nº, km: d_km, salida: d_sal, llegada: d_lleg, dorsal: d_dor)
Clave Primaria: {nºetapa}
CAj: {dorsal} hace referencia a CICLISTA
PUERTO(nompuerto:d_nom,altura:d_alt,categoría:d_cat, nºetapa:d_nº,dorsal: d_dor)
Clave Primaria: {nompuerto}
CAj: {nºetapa} hace referencia a ETAPA
CAj: {dorsal} hace referencia a CICLISTA
VNN: {nºetapa}
MAILLOT(código: d_código, tipo: d_tipo, premio: d_pre, color: d_col)
Clave Primaria: {código}
1. ¿En qué tablas se encuentra la información?
LLEVAR(dorsal: entero, nºetapa: d_nº, código: d_código)
Clave Primaria: {nºetapa, tipo}
CAj: {nºetapa} hace referencia a ETAPA
CAj: {dorsal} hace referencia a CICLISTA
CAj: {código} hace referencia a MAILLOT
VNN: {dorsal}
SELECT nombre, altura FROM Puerto
⇑
2. ¿Qué condición deben cumplir las filas resultantes?
3. ¿Que información queremos visualizar?
4. ¿Queremos ordenar el resultado por alguna columna?
WHERE categoria = 1;
5
6
1
EJEMPLO: Obtener el número de las etapas donde el nombre de la ciudad de
llegada tenga por segunda letra una “O” o donde el nombre de la ciudad de
salida lleve dos o más ‘A’s.
EJEMPLO: Obtener el nombre y la edad de todos los ciclistas.
SELECT nombre, edad FROM Ciclista;
SELECT netapa FROM Etapa
WHERE llegada LIKE ‘_O%’ OR salida LIKE ‘%A%A%’;
EJEMPLO: Obtener el nombre de los ciclistas cuya edad está entre 20 y
30 años.
EJEMPLO: Obtener el nombre de los puertos de 1ª, 2ª o 3ª categoría.
SELECT nompuerto FROM Puerto
WHERE categoría IN ( 1, 2, 3 ) ;
SELECT nombre FROM Ciclista
(*) También el predicado in es derivado y la expresión equivalente es:
WHERE edad BETWEEN 20 AND 30;
(*) El predicado between es equivalente a una condición
con comparaciones de la siguiente forma:
exp in (exp1, exp2, …, expn) ≡ (exp=exp1) or (exp=exp2) or…or
(exp=expn)
EJEMPLO: Obtener todos los datos de aquellos ciclistas de los que se
desconocía su edad.
exp between exp1 and exp2 ≡ (exp >= exp1) and (exp <= exp2)
SELECT * FROM Ciclista
7
COMPARACIÓN DE VALORES NULOS
WHERE edad IS NULL;
8
Ejemplo de consulta incorrecta (error de sintaxis)
Las comparaciones entre cualquier valor y NULL resultan en indefinido.
Ejemplo:
select *
select nomeq
from Equipo
where director = null
from T
where atrib1 > atrib2
Si en una fila se diera el caso que atrib1 = 50 y atrib2 fuera nulo, el
resultado de la comparación sería indefinido y por tanto dicha fila no se
incluiría en la selección.
La consulta correcta sería
select nomeq
from Equipo
where director IS NULL
9
MÁS EJEMPLOS DE COMPARACIONES
10
CONSULTAS DE VALORES AGREGADOS
Uso de operadores aritméticos: + (suma), − (diferencia), * (producto), /
(división), etc.
EJEMPLO: Obtener de los maillots el tipo y el premio en dólares (supongamos
que está en pesetas) ($1 = 150 ptas.) de aquellos maillots cuyo premio supere los
100 dólares.
SELECT tipo, premio / 150 FROM Maillot
La sintaxis de una referencia a una función agregada es la siguiente:
{ avg | max | min | sum | count } ( [all | distinct] expresión_escalar ) | count(*)
•Las funciones agregadas no se pueden anidar.
•Para las funciones sum y avg los argumentos deben ser numéricos.
•distinct indica que los valores redundantes sean eliminados antes de que se
realice el cálculo correspondiente.
WHERE premio / 150 > 100;
•La función especial count(*), en la que no está permitido incluir distinct ni
all, da como resultado el cardinal del conjunto de filas de la selección.
Uso de LIKE
•Los cálculos se realizan después de la selección y aplicar las condiciones.
EJEMPLO: Obtener el nombre y la edad de los ciclistas que pertenezcan a
equipos cuyo nombre contenga la cadena “100%”.
•Los valores nulos son eliminados antes de realizar los cálculos (incl. count).
SELECT nombre, edad FROM Ciclista
•Si el número de filas de la selección es 0, la función count devuelve el valor
0 y las otras funciones el valor nulo.
WHERE nomeq LIKE ‘%100\%%’ ESCAPE ‘\’
Se ha utilizado ‘\’ para indicar que el carácter comodín tiene su valor ‘%’
11
12
2
FUNCIONES AGREGADAS EN CONSULTAS NO AGRUPADAS
CONSULTAS SIMPLES SOBRE VARIAS TABLAS
EJEMPLO:
Cuando la información que se desea obtener de la base de datos se encuentra
almacenada en más de una tabla se hace indispensable el declarar una consulta que
manipule estas tablas.
SELECT ‘Núm. de ciclistas =’, COUNT(*), ‘Media Edad =’, AVG(edad)
FROM Ciclista
WHERE nomeq = ‘Banesto’;
En consultas no agrupadas, la selección sólo podrá incluir referencias a
funciones agregadas o literales ya que las funciones van a devolver un único
valor.
EJEMPLO INCORRECTO:
SELECT nombre, AVG(edad)
FROM Ciclista
WHERE nomeq = ‘ONCE’;
13
EJEMPLO: Obtener el dorsal y nombre de los ciclistas que han ganado una etapa.
1. ¿En qué tablas se encuentra la información?
14
Ejemplo: SELECT * FROM T1, T2 WHERE T1.n = T2.n
T1
FROM Ciclista, Etapa
T2
n
2. ¿Qué condición deben cumplir las filas resultantes?
a1
a2
a3
WHERE Ciclista.dorsal = Etapa.dorsal;
3. ¿Qué información queremos visualizar?
SELECT Ciclista.dorsal, nombre
c1
c2
d1
b2
T1 x T2
En está expresión es obligatorio que la referencia a la columna dorsal de Etapa y
Ciclista sea calificada con el nombre de la tabla, si no es ambigua. ==>
SELECT Ciclista.dorsal, nombre
FROM Ciclista, Etapa
WHERE Ciclista.dorsal = Etapa.dorsal;
¿Salen tuplas repetidas? ¿Por qué? ¿Cómo evitarlo?
n
b1
b2
b3
15
Cont. Consulta en varias tablas
• Cuando se va a trabajar con una tabla para hacer consulta entre diferentes
tuplas de ella, entonces se utilizan las variables de recorrido
n
X
X
X
√
X
X
a1
a1
a2
a2
a3
a3
b1
b1
b2
b2
b3
b3
n
c1
c2
c1
c2
c1
c2
d1
b2
d1
b2
d1
b2
16
EJEMPLO: Obtener el nombre de los ciclistas compañeros de equipo de ‘Miguel
Induráin’ que sean más jóvenes que él.
1. ¿En qué tablas se encuentra la información?
[tabla | variable_recorrido].columna
FROM Ciclista
Es una instancia de la tabla. Es virtual
Pero, como se requiere comparar con tuplas de la misma tabla,
entonces se necesita tener varias imágenes de ella
FROM Ciclista C1, Ciclista C2
• Por tanto, permiten dar un nombre alternativo a la misma tabla dentro de una
consulta. La manera de declarar una variable de recorrido es:
2. ¿Qué condición deben cumplir las filas resultantes?
WHERE C2.nombre=‘Miguel Induráin’ AND C1.nomeq = C2.nomeq AND
C1.edad < C2.edad;
from tabla [as] variable_recorrido
3. ¿Qué información queremos visualizar?
SELECT DISTINCT C1.nombre
SELECT DISTINCT C1.nombre FROM Ciclista C1, Ciclista C2
==> WHERE C2.nombre=‘Miguel Induráin’ AND C1.nomeq = C2.nomeq
17
AND C1.edad < C2.edad;
18
3
CANCION(cod: d_can, título: d_tit, duración: d_dur)
Clave Primaria: {cod} VNN: {título}
USO DE CLAVES AJENAS EN
Música
COMPAÑIA(cod: d_comp, nombre: d_nom, dir: d_dir, fax: d_tel, tfno: d_tel)
Clave Primaria: {cod} VNN: {nombre}
CONSULTAS DE VARIAS TABLAS
Si existen claves ajenas, lo más normal es que se dé una igualdad entre la clave
ajena y los atributos correspondientes de la tabla a la que se hace referencia.
DISCO(cod: d_dis, nombre: d_nom, fecha: d_fecha, cod_comp: d_comp, cod_gru: d_gru)
Clave Primaria: {cod}
Clave Ajena: {cod_comp}→ COMPAÑÍA VNN: {cod_comp, cod_gru }
Clave Ajena: {cod_gru}→ GRUPO
EJEMPLO: Obtener los nombres de los ciclistas pertenecientes al equipo dirigido
por ‘Álvaro Pino’.
ESTA(can: d_can, cod: d_dis)
Clave Primaria: {can, cod}
Clave Ajena: {can}→ CANCIÓN
Clave Ajena: {cod}→ DISCO
SELECT C.nombre FROM Ciclista C, Equipo E
WHERE C.nomeq = E.nomeq AND E.director = ‘Álvaro Pino’;
GRUPO(cod: d_gru, nombre: d_nom, fecha: d_fecha, pais: d_pais)
Clave Primaria: {cod} VNN: {nombre}
EJEMPLO: Obtener pares nombre de ciclista, número de etapa, de tal forma que
dicho ciclista haya ganado dicha etapa. Además la etapa debe superar los 150 km.
de recorrido.
SELECT C.nombre, E.netapa FROM Ciclista C, Etapa E
WHERE C.dorsal = E.dorsal AND E.km > 150;
19
ARTISTA(dni: d_dni, nombre: d_nom)
Clave Primaria: {dni} VNN: {nombre}
CLUB(cod: d_club, nombre: d_nom, sede: d_dir, num: d_num, cod_gru: d_gru)
Clave Primaria: {cod}
Clave Ajena: {cod_gru}→ GRUPO VNN: {cod_gru} VNN: {nombre}
PERTENECE(dni: d_dni, cod: d_gru, funcion: f_fun)
Clave Primaria: {dni, cod}
Clave Ajena: {dni}→ ARTISTA
Clave Ajena: {cod}→ GRUPO
20
CONSULTAS COMPLEJAS: SUBCONSULTAS
Si la información que se está buscando está incluida en una tabla y la condición de
búsqueda de esta información requiere acceder a otras tablas, entonces también se
pueden utilizar las subconsultas para expresar este tipo de condiciones.
EJEMPLO: Obtener el nombre de los ciclistas compañeros de equipo de ‘Miguel
Induráin’ que sean más jóvenes que él. (Es el mismo enunciado de antes)
Consultas sobre una o varias
tablas (Ciclismo y Música)
SELECT C1.nombre FROM Ciclista C1
Tablas que se requieren para el Select precedente
WHERE C1.nomeq IN (SELECT C2.nomeq FROM Ciclista C2
WHERE C2.nombre=‘Miguel Induráin’)
Se verá más adelante
AND C1.edad < (SELECT C2.edad FROM Ciclista C2
WHERE C2.nombre=‘Miguel Induráin’);
21
Obtener los nombres de los ciclistas pertenecientes al equipo dirigido por ‘Álvaro
Pino’.
22
PREDICADOS QUE ACEPTAN SUBCONSULTAS
Las subconsultas pueden aparecer en las condiciones de búsqueda, como
argumentos de algunos predicados, tanto de la cláusula WHERE como de la
HAVING.
Antes, se habían usado igualdades:
SELECT C.nombre FROM Ciclista C, Equipo E
WHERE C.nomeq = E.nomeq AND E.director = ‘Álvaro Pino’;
Los predicados que pueden llevar como argumentos subconsultas son los
siguientes:
Usando subconsultas, sería:
• predicados de comparación (=, <>, >, <, >=, <=).
SELECT C.nombre FROM Ciclista C
WHERE C.nomeq = (SELECT E.nomeq FROM Equipo E
WHERE E.director = ‘Álvaro Pino’);
• in: comprueba que un valor pertenece a una colección dada mediante una
subconsulta.
Esto es posible porque la información que se requiere, nombre del ciclista, no está
en la tabla de la subconsulta (Equipo) y porque la subconsulta retorna un
• match: comprueba si un valor es idéntico a algún valor de una colección.
• predicados de comparación cuantificados (any y all): permitir comparar un
valor con un conjunto de valores.
único valor.
• exists: equivalente al cuantificador existencial, comprueba si una subconsulta
devuelve alguna fila.
• unique: comprueba si una subconsulta no devuelve filas repetidas.
23
24
4
PREDICADOS DE COMPARACIÓN
(=, <>, >, <, >=, <=)
EJEMPLO: Obtener los nombres de los puertos cuya altura es mayor que la media
de altura de los puertos de 2ª categoría.
Cada uno de los dos lados de un predicado de comparación debe ser una única tupla
formada por el mismo número de columnas. Es decir:
(A1, A2, …, An) predicado_comparación (B1, B2, …, Bn)
1. ¿En qué tablas se encuentra la información?
Puerto
Las subconsultas pueden ser argumentos, siempre y cuando devuelvan una única
fila y el número de columnas coincida en número y tipo con el otro
lado del predicado de comparación.
Llamaremos constructor_fila a una lista de atributos entre paréntesis o una subconsulta.
constructor_fila predicado_comparación constructor_fila
•En el caso que la subconsulta esté vacía, se convierte a una fila con valores nulos
en todas las columnas.
==> FROM Puerto
2. ¿Qué condición deben cumplir las filas resultantes?
altura > avg(altura) de los Puertos de segunda categoría
Es un valor - una fila
==> WHERE altura > (SELECT AVG(altura) FROM Puerto
WHERE categoria = ‘2’ );
==
> Compara cada valor de altura con el valor obtenido
en avg(altura)
• Para poder comparar dos constructor_fila de más de una columna, existe una
forma definida de realizar esta comparación para cada uno de los predicados de
comparación (=, <>, >, <, <=, >=). Pero, en general se verán subconsultas de una
única columna, como el ejemplo anterior.
25
EJEMPLO: Obtener los nombres de los puertos cuya altura es mayor que la media
de altura de los puertos de 2ª categoría.
1. ¿En qué tablas se encuentra la información?
Puerto
EJEMPLO: Obtener los nombres de los puertos cuya altura es mayor que la media
de altura de los puertos de 2ª categoría.
1. ¿En qué tablas se encuentra la información?
==> FROM Puerto
Puerto
2. ¿Qué condición deben cumplir las filas resultantes?
==> FROM Puerto
2. ¿Qué condición deben cumplir las filas resultantes?
altura > avg(altura) de los Puertos de segunda categoría
altura > avg(altura) de los Puertos de segunda categoría
==> WHERE altura > (SELECT AVG(altura) FROM Puerto
WHERE categoria = ‘2’ );
==> WHERE altura > (SELECT AVG(altura) FROM Puerto
WHERE categoria = ‘2’ );
3. ¿Qué información queremos visualizar?
nompuerto
26
3. ¿Qué información queremos visualizar?
==> SELECT nompuerto ==> 1 columna con
n filas
27
nompuerto
==> SELECT nompuerto
==> SELECT nompuerto FROM Puerto
WHERE altura > (SELECT AVG(altura) FROM Puerto
WHERE categoria = ‘2’ );
28
Predicado IN
¿Qué hace el siguiente ejemplo?
Comprueba que un valor pertenece a una colección dada
¿Es correcto?
mediante una subconsulta.
SELECT nompuerto FROM Puerto
1 columna con n filas
WHERE altura > (SELECT altura FROM Puerto
constructor_fila [not] IN(expresión_tabla)
A la derecha de IN puede aparecer más de una fila y por eso se
denomina expresión_tabla.
WHERE categoria = ‘2’ );
Es un valor a la vez
EJEMPLO: Obtener el nº de las etapas ganadas por ciclistas con edad
superior a los 30 años.
==> No puede hacer la comparación
INCORRECTO: (error de ejecución).
SELECT netapa FROM Etapa
WHERE dorsal IN (SELECT dorsal FROM Ciclista
29
WHERE edad > 30);
30
5
También, con IN se pueden hacer Subconsultas Encadenadas:
Predicados de comparación cuantificados (ALL, ANY)
Permiten comparar un valor con un conjunto de valores.
EJEMPLO: Obtener el número de las etapas ganadas por ciclistas
que pertenezcan a equipos cuyo director tenga un nombre que
empiece por ‘A’.
constructor_fila predicado_comparación {all | any | some}
(expresión_tabla)
• El predicado de comparación cuantificado con ALL se evalúa a
cierto si lo es para todas las filas de la expresión de tabla (si la
tabla está vacía también se evalúa a cierto).
SELECT netapa FROM Etapa
WHERE dorsal IN (SELECT dorsal FROM Ciclista
WHERE nomeq IN (SELECT nomeq FROM Equipo
WHERE director LIKE ‘A%’));
• El predicado de comparación cuantificado con ANY o SOME se
evalúa a cierto si lo es para alguna fila de la expresión de tabla (si
la tabla está vacía se evalúa a falso).
(*) el predicado IN es idéntico al predicado de comparación
cuantificado =any.
31
EJEMPLO: Obtener el nombre de los puertos y de los ciclistas que los hayan
ganado que tengan la mayor pendiente.
32
Predicado exists
exists (expresión_tabla)
SELECT P.nompuerto, C.nombre FROM Puerto P, Ciclista C
WHERE P.dorsal = C.dorsal AND
P.pendiente >= ALL (SELECT P1.pendiente FROM Puerto P1 )
EJEMPLO: Obtener el nombre de los puertos y de los ciclistas que los hayan
ganado, cumpliendo que el puerto no sea el que tenga la menor pendiente.
SELECT P.nompuerto, C.nombre FROM Puerto P, Ciclista C
WHERE P.dorsal = C.dorsal AND
P.pendiente > ANY (SELECT P1.pendiente FROM Puerto P1 )
•El predicado exists se evalúa a cierto si la expresión select devuelve
al menos una fila.
•En general, IN y EXISTS son intercambiables y se pueden eliminar
haciendo consultas a múltiples tablas e igualando por claves ajenas.
(*) Cualquier ANY se puede convertir en un ALL cambiando la condición
a su condición negada y añadiendo un NOT.
NOT ( P.pendiente < ALL (SELECT P1.pendiente FROM Puerto P1 ) )
33
34
EJEMPLO: Obtener el nombre de los ciclistas que no han ganado etapas.
EJEMPLO: Obtener el nombre de aquellos ciclistas que han llevado un maillot de
un premio menor de 50000 ptas. .
SELECT C.nombre FROM Ciclista C, Llevar L
SELECT nombre FROM Ciclistas
WHERE NOT EXISTS (SELECT * FROM Etapa
WHERE Etapa.dorsal = Ciclista.dorsal);
WHERE C.dorsal = L.dorsal AND
EXISTS (SELECT *
WHERE EXISTS (SELECT * FROM …)
FROM Maillot M
equivale a: WHERE 0 < (SELECT COUNT(*) FROM …)
WHERE M.premio < 50000 AND M.codigo = L.codigo)
O bien:
SELECT C.nombre FROM Ciclista C, Llevar L
WHERE NOT EXISTS (SELECT * FROM …)
WHERE C.dorsal = L.dorsal AND
equivale a: WHERE 0 = (SELECT COUNT(*) FROM …)
L.codigo IN (SELECT M.codigo
FROM Maillot M
WHERE M.premio < 50000 )
35
36
6
Uso de EXISTS para cuantificación universal (NO
HAY EN SQL)
∀ X F(X) ≡  ∃ X  F(X)
Obtener el nombre del ciclista que ha ganado todas las etapas de más de
200 km.
C.nombre| Ciclista(C)∧∀ X (Etapa(X)∧X.Km>200→C.dorsal=X.dorsal)
Para poder expresar esta consulta en SQL se convertirá en: “Obtener
el nombre del ciclista tal que no existe una etapa de más de 200 km.
que él no haya ganado”
SELECT nombre FROM Ciclista C
WHERE NOT EXISTS (SELECT * FROM Etapa E
WHERE km > 200 AND
C.dorsal <> E.dorsal );
es equivalente a:
C.nombre| Ciclista(C)∧ ∃X(Etapa(X)∧X.Km>200∧C.dorsal<>X.dorsal)
37
AUTOR(autor_id: tira(4), nombre: tira(35), nacionalidad: tira(20))
38
Biblioteca
Clave Primaria: {autor_id}
LIBRO(id_lib: tira(10), titulo: tira(80), año: entero, num_obras: entero)
Clave Primaria: {id_lib} VNN: {titulo}
TEMA(tematica: tira(20), descripcion: tira(50))
Clave Primaria: {tematica}
OBRA(cod_ob: entero, titulo: tira(80), año: d_cat, tematica: tira(20))
Clave Primaria: {cod_ob}
Clave Ajena: {tematica}→ TEMA
VNN: {titulo}
AMIGO(num: entero, nombre: tira(60),
telefono: tira(10))
Clave Primaria: {num}
VNN: {nombre}
PRESTAMO(num: entero, id_lib:tira(10))
Clave Primaria: {num,id_lib}
Clave Ajena: {num} → AMIGO
Clave Ajena: {id_lib} → LIBRO
ESTA_EN(cod_ob: entero, id_lib:tira(10))
Clave Primaria: {cod_ob,id_lib}
Clave Ajena: {cod_ob} → OBRA
Clave Ajena: {id_lib} → LIBRO
ESCRIBIR(cod_ob: entero, autor_id:tira(4))
Clave Primaria: {cod_ob,autor_id}
Clave Ajena: {cod_ob}→ OBRA
Clave Ajena: {autor_id}→ AUTOR
39
7
Descargar