La integridad referencial declarativa y las relaciones entre tablas
Introducción
La integridad referencial declarativa (DRI) y las relaciones entre tablas vienen a garantizar algo importantísimo en los sistemas relacionales, en este caso la consistencia de los datos. No es de recibo que exista en una base de datos un albarán al cliente 50, y que el cliente 50 no exista!!, y eso es lo que nos garantiza la DRI, que esas cosas no sucedan. Ahora bien, lo que la integridad referencial no garantiza es que existan registros relacionados,
/* Siempre nos basamos en una bd que exista en el sistema y que se llame pruebas */
use pruebas go create table cabecera( id int identity (1,1) primary key not null,
fecha datetime default getdate())
go create table lineas (id int not null, orden int not null,
Descripcion varchar(100) not null,
constraint pk_lineas primary key (id,orden),
constraint fk_lineas foreign key (id) references cabecera)
go
/* además metemos 100 cabeceras */
declare @i int
set @i=0
while @i<100
begin
insert into cabecera default values
select @i=@i+1
end
go
/* y dos lineas *//
insert into lineas values (1,1,’Esto es una prueba’)
insert into lineas values (1,2,’Esto es una prueba linea 2′)
go
select * from cabecera
— 100 filas
Esto es normal, el sistema nos devuelve las 100 filas de la cabecera,
go
select * from cabecera inner join lineas on cabecera.id=lineas.id
— 2 filas !!!!
Sin embargo ahora devuelve solo dos, por que una sola cabecera tiene líneas y tiene dos líneas, por tanto devuelve aquellas que están en las dos tablas, coincidiendo su id, esto da como resultado, dos líneas solamente.
Pero podemos hacer que devuelva todas las cabeceras, y aquellas que no tengan líneas, pues que nos devuelva valores null, esto son los llamados ‘joins externos’ y sirven para resolver la problemática precisamente de cabeceras no relacionadas con líneas.
go
select * from cabecera left join lineas on cabecera.id=lineas.id
— 101 filas
El resultado serán las 101 filas, siendo todos los valores de la tabla líneas null, en aquellas que no tienen registros relacionados. Aparece una fila más que cabeceras por que una cabecera tiene dos líneas, por tanto esa cabecera aparecerá dos veces.
go
select * from cabecera left join lineas on cabecera.id=lineas.id where lineas.id is null
— 99 filas = 101 −2 filas.
También podemos mediante sentencias como la que tenéis arriba encontrar todas las cabeceras que no tiene líneas, sabemos que si no hay líneas, el campo que relaciona líneas con cabecera será null, no existirá, así que obligamos a que esto sea así con el predicado ‘Where lineas.id is null’
Otras cuestiones, también puede ser que las relaciones externas sean opcionales, en nuestro ejemplo, vamos a añadir una zona, que resultará opcional, se podrá indicar para esta cabecera o no. Si no se indica será un valor null en la tabla de cabecera, pero si se indica, tiene que existir, a continuación el script para crear esta relación.
alter table cabecera add idZona int
go
create table Zonas (idzona int identity(1,1) not null primary key,
nombre varchar(100) not null )
go
alter table cabecera add constraint fk_CabZonas foreign key (idZona) references zonas(idzona)
go
Insertamos un registro en zonas
insert into zonas values (‘Sur Este?’)
select @@identity
Insertada la zona 1
Sin embargo existen ya 100 cabeceras con zona =null y eso no supone ningún problema, vamos excepto que queramos sacar el nombre de la cabecera.
select * from cabecera c inner join zonas on c.idzona=zonas.idzona
También devolverá cero registros, por lo que tendremos que usar de nuevo left join.
Como comentarios añadir que sql-server también admite una notación distinta de inner join, left join y right join, a base de poner el la condición where el símbolo * al lado del igual de una de las condiciones, pero que además de ser menos clara en mi opinión, no es nomenclatura ANSI, por lo que Sql-server podría no soportarla en futuras versiones.