Como ya sabemos, las restricciones permiten especificar condiciones que deberán cumplir tablas o columnas para mantener la integridad de sus datos. Algunas de las restricciones vendrán impuestas por el modelo concreto que se esté implementando, mientras que otras tendrán su origen en las reglas de negocio del cliente, los valores que pueden tomar algunos campos, etc.
Ejemplo |
Una columna definida como integer no puede contener cadenas de caracteres. |
Los valores que puede contener una columna están restringidos en primer lugar por el tipo de datos. Ésta no es la única restricción que se puede definir para los valores en una columna, PostgreSQL ofrece las restricciones siguientes:
• null y not null. En múltiples ocasiones el valor de una columna es desconocido, no es aplicable o no existe. En estos casos, los valores cero, cadena vacía o falso son inadecuados, por lo que utilizamos null para especificar la ausencia de valor. Al definir una tabla podemos indicar qué columnas podrán contener valores nulos y cuáles no.
create table Persona (
nombre varchar(40) not null,
trabajo varchar(40) null,
correo varchar(20),
);
El nombre de una persona no puede ser nulo, y es posible que la persona no tenga trabajo. También es posible que no tenga correo, al no especificar una restricción not null, se asume que la columna puede contener valores nulos.
• unique. Esta restricción se utiliza cuando no queremos que los valores contenidos en una columna puedan duplicarse.
create table Persona (
nombre varchar(40) not null,
conyuge varchar(40) unique,
);
cónyuge no puede contener valores duplicados, no permitiremos que dos personas tengan simultáneamente el mismo cónyuge.
• primary key. Esta restricción especifica la columna o columnas que elegimos como clave primaria. Puede haber múltiples columnas unique, pero sólo debe haber una clave primaria. Los valores que son únicos pueden servir para identificar una fila de la tabla de forma unívoca, por lo que se les denomina claves candidatas.
create table Persona (
nss varchar(10) primary key, conyuge varchar(40) unique,
);
Al definir una columna como primary key, se define implícitamente con unique. El nss (número de la seguridad social) no sólo es único, sino que lo utilizamos para identificar a las personas.
• references y foreign key. En el modelo relacional, establecemos las relaciones entre entidades mediante la inclusión de claves foráneas en otras relaciones. PostgreSQL y SQL ofrecen mecanismos para expresar y mantener esta integridad referencial. En el siguiente ejemplo, las Mascotas tienen como dueño a una Persona:
create table Mascota(
nombre varchar(20),
dueño varchar(10) references Persona,
);
Una referencia por defecto es a una clave primaria, por lo que dueño se refiere implícitamente al nss de Persona. Cuando se capturen los datos de una nueva mascota, PostgreSQL verificará que el valor de dueño haga referencia a un nss que exista en Persona, en caso contrario emitirá un mensaje de error. En otras palabras, no se permite asignar a una mascota un dueño que no exista.
También es posible especificar a qué columna de la tabla hace referencia:
create table Mascota(
nombre varchar(20),
dueño varchar(10) references Persona(nss),
);
o su equivalente:
create table Mascota(
nombre varchar(20),
dueño varchar(10),
FOREIGN KEY dueño references Persona(nss),
);
Podría darse el caso de que la clave primaria de la tabla referenciada tuviera más de una columna, en ese caso, la clave foránea también tendría que estar formada por el mismo número de columnas:
create table t1 (
a integer PRIMARY KEY,
b integer,
c integer,
FOREIGN KEY (b, c) REFERENCES other_table (c1, c2)
);
Si no se especifica otra acción, por omisión la persona que tenga una mascota no puede ser eliminada, porque la mascota se quedaría sin dueño. Para poder eliminar una persona, antes se deben eliminar las mascotas que tenga. Este comportamiento no parece ser el más adecuado para el caso.
Para modificar este comportamiento disponemos de las reglas de integridad referencial del lenguaje SQL, que PostgreSQL también soporta. En el siguiente ejemplo se permite que al eliminar una persona, las mascotas simplemente se queden sin dueño.
create table Mascota (
dueño varchar(10) references Persona on delete set null,
);
En cláusula on delete se pueden especificar las siguientes acciones:
– set null. La referencia toma el valor NULL: si se elimina Persona su Mascota se quedará sin dueño.
– set default. La referencia toma el valor por omisión.
– cascade. La acción se efectúa en cascada: si se elimina Persona automáticamente se elimina su Mascota.
– restrict. No permite el borrado del registro: no se puede eliminar una Persona que tenga Mascota. Ésta es la acción que se toma por omisión.
Si se modifica la clave primaria de la tabla referenciada, se dispone de las mismas acciones que en el caso anterior, que especificaremos con la cláusula ON UPDATE.
• check. Esta restricción realiza la evaluación previa de una expresión lógica cuando se intenta realizar una asignación. Si el resultado es verdadero, acepta el valor para la columna, en caso contrario, emitirá un mensaje de error y rechazará el valor.
create table Persona (
edad int check( edad > 10 and edad < 80 ),
correo varchar(20) check( correo ~ `.+@.+\..+´ ),
ciudad varchar(30) check( ciudad <>" )
);
Comparación de expresiones regulares |
El operador ~ realiza compara- ciones de cadenas con expre- siones regulares. Las expresiones regulares son patrones de búsqueda muy flexibles desarrollados en el mundo Unix. |
Se han restringido los valores que se aceptarán en la columna de la manera siguiente.
• Edad debe estar entre 11 y 79 años.
• Ciudad no debe una cadena vacía.
• Correo debe tener una arroba.
Cualquiera de esas restricciones puede tener nombre, de manera que se facilita la referencia a las restricciones específicas para borrarlas, modificarlas, etc. pues puede hacerse por nombres. Para dar nombre a una restricción, utilizamos la sintaxis siguiente:
constraint nombre_de_restricción