Professional Documents
Culture Documents
Es posible que varios atributos tengan el mismo dominio, como ocurre con nombre_cliente y
nombre_empleado, que tienen como dominio el conjunto de todos los nombres de personas. Sin embargo los
dominios de saldo y nombre_sucursal deben ser distintos.
El principio que hay detrás de los dominios de atributo es similar al que hay detrás de la asignación de tipos a
variables en los lenguajes de programación.
Vimos que la inserción de tuplas incompletas pueden introducir valores vacíos en la BD. Para determinados
atributos, los valores nulos pueden ser inapropiados.
Considérese una tupla en la relación cliente en la que nombre_cliente es un valor vacío. En casos como éste,
deseamos prohibir los valores nulos, restringiendo el dominio de nombre_cliente para que excluya los valores nulos.
El SQL estándar permite que la declaración del dominio de un atributo incluya la especificación not null. Esto
prohibe la inserción de un valor nulo para este atributo. Cualquier modificación de la BD que causara que se insertase un
valor nulo en un dominio not null genera un diagnóstico de error.
Hay muchas situaciones en las que la prohibición de valores nulos es deseable. Un caso particular en el que es
esencial prohibir los valores nulos es en la clave primaria de un esquema de relación.
43
Bases de Datos
Considérese un par de relaciones r(R ) y s(S) y el producto natural r|x|s. Puede darse el caso de que haya una
tupla t en r que no se corresponda con ninguna tupla en s. Es decir, no hay ninguna t en s tal que tr[R∩S]=ts[R∩S].
Dichas tupla se llaman tuplas colgadas.
Supóngase que hay una tupla t en depósito con t1[nombre_sucursal = “Lunartown”], pero no hay no hay
ninguna tupla en la relación sucursal para Lunartown. Esta sería una situación no deseable. Esperamos que la relación
sucursal liste todas las sucursales, por tanto, t haría referencia a una cuenta de una sucursal que no existe. Esta claro que
queremos tener una restricción de integridad que prohiba tuplas colgadas de este tipo.
Sin embargo, no todas las instancias de tuplas colgadas son no deseables. Supóngase que hay una tupla t en la
relación sucursal con t2[nombre_sucursal = “Mokan”], pero no hay ninguna tupla en depósito para Mokan. En este
caso existe una sucursal que no tiene cuentas, y aunque no es deseable es posible esta situación.
Para ver la diferencia entre estos dos ejemplos, recordamos que nombre_sucursal es la clave primaria de
esquema_sucursal. Puesto que nombre_sucursal aparece en esquema_depósito, las tuplas depósito hacen referencia a la
clave primaria de sucursal. decimos que el atributo nombre_sucursal en esquema_depósito es una clave exterior, ya que
nombre_sucursal es la clave primaria de una planificación de relaciones distinta de esquema_depósito. Sin embargo, el
atributo nombre_sucursal en esquema_sucursal no es una clave exterior ya que nombre_sucursal no es la clave de
ningún otro esquema de relaciones.
Así, la distinción entre estos dos ejemplos de tuplas colgadas es la presencia de una clave exterior.
Sean r1(R1) y r2(R2) relaciones con claves primarias K 1 y K 2 respectivamente. Decimos que un subconjunto α de
R2 es una clave exterior con referencia K 1 en la relación r1 si es necesario que para cada t2 en r2 haya una tupla t1 en r1 tal
que t1[K 1] = t2[α].El último término surge del hecho de que la restricción de integridad anterior puede escribirse como
∏α(r2)⊆∏k1(r1). Nótese que para que una restricción de integridad referencial tenga sentido, o bien α = K1, o α y K1
deben ser conjuntos de atributos compatibles.
Otra fuente de restricciones de integridad referencial son los conjuntos de entidades débiles. Recuerdese que el
esquema de relaciones para un conjunto de entidades débil debe incluir la clave primaria del conjunto de entidades del
cual depende. Así pues, el esquema de relaciones para cada conjunto de entidades débil uncluye una clave exterior que
conduce a una restricción de integridad referencial.
n Insertar. Si una tupla t2 se inserta en r2, el sistema debe asegurar que existe una tupla t1 en r1, tal que t1[K] =
t2[α]. Es decir:
t2[α]∈∏k(r1)
n Eliminar. Si una tupla t1 se elimina en r1, el sistema debe calcular el conjunto de tuplas en r2 que hacen
referencia a t1:
σα=t1[K](r2)
Si este conjunto no está vacío, o la orden de eliminar se rechaza como un error, se deben eliminar las tuplas
que hacen referencia a t1. La última solución puede llevar a eliminaciones en forma de cascada, ya que las
tuplas pueden hacer referencia a t1, y así respectivamente.
n Actualizar. Debemos considerar dos casos para actualizar: actualizaciones a la relación que hace referencia (r2)
y actualizaciones a la relación referenciada (r1).
44
Tema 5. Restricciones de integridad.
Si se actualiza una tupla t2 en la relación r2 y la actualización modifica valores para la clave exterior α,
entonces se hace una prueba similar a la del caso de insertar.t’2 representa el nuevo valor de la tupla t2. El
sistema debe asegurar que:
t’2[α]∈∏k(r1)
Si se actualiza una tupla t1 en r1 y la actualización modifica valores para la clave primaria (K), entonces se
hace una prueba similar a la del caso de eliminar. El sistema debe calcular:
σα=t1[K](r2)
usando el valor antiguo de t1 (se aplica el valor de antes de la actualización). Si el conjunto no está vacío, la
actualización se rechaza como un error.
El SQL estándar original no incluía sentencias para especificar claves exteriores. Una característica de
intensificación de la integridad ha sido aprobada como un añadido al estándar. Esta característica permite la especificación
de claves primarias y candidatas y de claves exteriores como parte de la sentencia create table:
n La cláusula primary key de la sentencia create table incluye una lista de los atributos que comprenden la
clave primaria.
n La cláusula unique key incluye una lista de los atributos que comprenden una clave candidata.
n La cláusula foreign key incluye una lista de los atributos que comprenden la clave exterior y el nombre de la
relación a la que hace referencia la clave exterior.
create table depósito
(nombre_sucursal char (15) not null,
número_cuenta char (10)
nombre_cliente char (20) not null
saldo integer,
primary key (número_cuenta, nombre_cliente),
foreign key (nombre_sucursal) references sucursal
foreign key (nombre_cliente) references cliente) )
Cualquier atributo que sea miembro de una clave candidata debe ser not null. Así pues, en la definición de
depósito necesitamos especificar número_cuenta y nombre_cliente como not null. Esta permitido tener valores vacíos
en una clave exterior a menos que dicha clave exterior sea miembro de una clave candidata.
Las dependencias funcionales son una restricción al conjunto de relaciones legales. Nos permiten expresar
hechos acerca de la empresa que estamos modelando con la BD.
Anteriormente definimos la noción de superclave como sigue: sea R un esquema de relaciones, un
subconjunto K de R es una superclave de R si, en cualquier relación legal r(R ), para todos los pares t1 y t2 de tuplas en r
tales que t1 ≠ t2, t1[K] ≠ t2[K]. Es decir, dos tuplas en cualquier relación legal r(R ) no pueden tener el mismo valor en el
conjunto de atributos K.
La noción de dependencia funcional generaliza la noción de superclave. Sea α⊆R y β⊆R. La dependencia
funcional α→β
se cumple en R si en cualquier relación legal r(R ), para todos los pares de tuplas t1 y t2 en r tales que t1[α] = t2[α],
también se cumple que t1[β] = t2[β]
Utilizando la notación de la dependencia funcional, decimos que K es una superclave de R si Kà R. Es decir,
K es una superclave si siempre que t1[K] = t2[K], también se cumple que t1[R] = t2[R], es decir, t1 = t2.
Las dependencias funcionales nos permiten expresar restricciones que no pueden expresarse por medio de
superclaves. Considérese el esquema:
Esquema_préstamo = ( nombre_sucursal, número_préstamo, nombre_cliente, cantidad)
Si un préstamo dado puede hacerse a más de un cliente, entonces no esperaríamos que el atributo
número_prestamo fuenra una superclave. Sin embargo, esperamos que la dependencia funcional
número_prestamo à cantidad
se cumpla, puesto que sabemos que cada número de préstamo está asociado precisamente a una cantidad.
Usaremos las dependencias funcionales de dos formas:
n Para especificar restricciones en el conjunto de relaciones legales. Así pues, nos interesaremos sólo por las
relaciones que satisfagan un conjunto dado de dependencias funcionales. Si queremos limitarnos a las
relaciones de esquema R que satisfacen F, decimos que F se cumple e R.
n Para probar si una relación es legal bajo un conjunto dado de dependencias funcionales. Si una relación r es
legal bajo un conjunto F de dependencias funcionales, decimos que r satisface a F.
45
Bases de Datos
46
Tema 5. Restricciones de integridad.
Para comprobar que un conjunto α es una superclave debemos idear un algoritmo para calcular el conjunto de
atributos determinados funcionalmente por α. Veremos que un algoritmo de este tipo, también es útil como parte del
cálculo del cierre de un conjunto F de dependencias funcionales.
Sea α un conjunto de atributos. Al conjunto de todos los atributos determinados funcionalmente por α bajo
un conjunto F de dependencias funcionales se le llama cierre de α bajo F y re representa por α+.
Ahora mostramos un algoritmo para calcular α+. La entrada es un conjunto F de dependencias funcionales y el
conjunto α de atributos. La salida se almacena en la variable resultado.
resultado:= α;
while (cambios en resultado) do
for each dependencia funcional β → γ in F do
begin
if β ⊆ resultado then resultado:= resultado ∪ γ;
end
Usemos el algoritmo para calcular (AG)+ con las dependencias funcionales definidas anteriormente.
Empezamos con resultado = AG. La primera vez que ejecutamos el bucle while para probar cada dependencia funcional
encontramos que:
AàB nos hace incluier B en el resultado, ya que AàB esta en F, A⊆resultado (que es aG), por tanto
resultado:=resultado∪B.
AàC hace que el resultado se convierta en ABCG.
CGàH hace que el resultado sea ABCGH.
CGàI hace que el resultado se convierta en ABCGHI.
La segunda vez que ejecutamos el bucle while, no se añaden atributos a resultado y el algoritmo termina.
La regla de unión implica que α à resultado ∪ γ, así α determina funcionalmente cualquier resultado nuevo
generado por el bucle while. Por tanto, cualquier atributo devuelto por el algoritmo está en α+.
Es fácil ver que el algoritmo encunetra α+ completo. Si hay algún atributo en α+ que no esté todavía en
resultado, entonces debe haber una dependencia funcional β → γ para la cual β ⊆ resultado y al menos un atributo de F
no está en resultado.
Resulta ser que en el peor de los casos este algoritmo puede tardar un tiempo que es una función cuadrática del
tamaño de F, así que existen algoritmos más rápidos.
Para minimizar el número de dependencias funcionales que necesitan ser probadas en caso de actualización,
restringimos un conjunto dado F de dependencias funcionales a un recubrimiento canónico de F. Un recubrimiento
canónico de F es un conjunto de dependencias tal que F implica lógicamente a todas las dependencias en Fc y Fc implica
lógicamente a todas las dependencias de F. Además Fc debe tener las siguientes propiedades:
n Cada una de las dependencias funcionales α→β en Fc no contiene atributos extraños a α. Los atributos
extraños son atributos que pueden eliminarse de α sin cambiar F+c. Así A es extraño a α si A∈α y Fc
implica lógicamente a (Fc-{α→β})∪{α-A→β}.
n Cada una de las dependencias funcionales α→β en Fc no contiene atributos extraños a β. Los atributos
extraños son atributos que pueden eliminarse de β sin cambiar F+c. Así A es extraño a β si A∈β y (Fc-
{α→β})∪{α→β-A}. implica lógicamente a Fc.
n Cada lado izquierdo de una dependencia funcional en Fc es único. Es decir, no existe dos dependencias
α1→β1 y α2→β2 en Fc tales que α1=α2.
47
Bases de Datos
Para calcular un recubrimiento canónico para F, utilícese la regla de unión para sustituir cualquier dependencia en
F de la forma α1→β1 y α1→β2 con α1→β1β2 . Pruébese cada dependencia funcional α→β para ver si hay un atributo
extraño a α. Para cada dependencia α→β compruébese si hay un atributo extraño a β. Este proceso se debe repetir
hasta que no ocurra ningún cambio en el bucle.
Considérese el siguiente conjunto de dependencias funcionales F={AàBC, BàC, AàB, ABàC} en el
esquema (A, B, C). Calculemos el recubrimiento canónico de F.
Hay dos dependencias con el mismo atributo en el lado izquierdo de la flecha AàBC y AàB, por lo que las
combinamos en AàBC.
A es extraño a ABàC porque BàC implica lógicamente a ABàC, y así ((F-{ABàC})∪{BàC} implica
lógicamente a Fc. Como resultado de suprimir A de ABàC, obtenemos que BàC, la cual ya está en el conjunto de
dependencias funcionales.
En este momento, el conjunto de dependencias funcionales es F={AàBC, BàC}.
Obsérvese que ahora se cumplen las propiedades de un recubrimiento canónico.
5.4. Afirmaciones.
Una afirmación es un predicado que expresa una condición que se desea que siempre satisfaga la BD. Las
restricciones de dominio, las dependencias funcionales y las restricciones de integridad referencial son formas especiales
de afirmación, sin embargo, existen muchas restricciones que no pueden expresarse usando solamente estas tres formas
especiales. Entre los ejemplos de dichos límites están: que cada cliente de préstamos debe tener una cuenta con un saldo
mínimo de 1000$, y que cada sucursal no puede prestar más dinero que su activo.
Cuando se hace una afirmación, el sistema prueba su validez. Si la afirmación es válida, entonces cualquier
futura modificación de la BD está permitida sólo si no se provoca que se viole la afirmación.
El elevado tiempo de prueba y mantenimiento de las afirmaciones ha llevado a la mayoría de los que
desarrollan los sistemas a omitir el soporte para afirmaciones generales. La propuesta original para el lenguaje SQL
incluía una construcción de propósito general assert, para la expresión de restricciones de integridad.
Una afirmación perteneciente a una única relación toma la forma:
assert <nom_afirmación> on nom_relación> : <predicado>
Por ejemplo, si queremos definir una restricción de integridad que ningún saldo de cuenta sea negativo:
assert limite_saldo on depósito : salo ≥ 0
Podíamos haber escrito la afirmación anterior como una restricción de dominio. Sin embargo, la sentencia
assert nos permite especificar restricciones en una relación que no pueden expresarse como un límite del dominio:
assert limite_banquero on persona: nombre_cliente ≠ nombre_empleado
Las afirmaciones pueden restringirse para aplicarse sólo a modificaciones de la BD como en el caso de que
queremos prevenir la adición de una cuenta a menos que el nombre del cliente aparezca en la relación cliente. Escribimos
la afirmación siguiente:
assert limite_dirección on insertion to depósito
exists (select * from cliente
where cliente.nombre_cliente = depósito.nombre_cliente)
De hecho, la afirmación anterior es una restricción de integridad referencial.
La forma más general de afirmación es:
assert <nom_afirmación> : <predicado>
donde >predicado> es cualquier cláusula where válida en SQL
Debido al elevado tiempo que lleva la prueba de afirmaciones arbitrarias, la sentencia assert ha desaparecido de
las versiones más recientes de SQL, incluyendo la estándar. En lugar de las afirmaciones están las restricciones más fáciles
de probar, como las de dominio, las de clave y las de integridad referencial. Sin embargo, existe una propuesta para
incluir afirmaciones generales en una futura revisión del SQL estándar.
5.5. Disparadores.
Un disparador es una sentencia que el sistema ejecuta automáticamente como un efecto secundario de una
modificación de la BD.
Para diseñar un mecanismo de parador debemos:
n Especificar las condiciones bajo las cuales se va a ejecutar el disparador.
n Especificar las acciones que se van a tomar cuando se ejecute el disparador.
Supóngase que en lugar de permitir saldos negativos, el banco trata los saldos deudores poniendo el saldo de
cuenta a cero y creando un préstamo en la cantidad del saldo deudor. A éste préstamo se le da un número igual al
número de cuenta de la cuenta deudora.. Sea t la tupla con un saldo negativo, las acciones que se deben realizar son las
siguientes:
Insertar una nueva tupla s en la relación préstamo con:
s[nombre_sucursal] = t[nombre_sucursal] s[número_préstamo] = t [número_préstamo]
s[cantidad] = ¬t[saldo] s[nombre_cliente] = t [nombre_cliente]
Poner t[saldo] a cero.
El disparador de éste ejemplo sería:
48
Tema 5. Restricciones de integridad.
49