Restricciones de SQL

A veces queremos asegurarnos que los datos mantienen coherencia. ¿Cómo lo hacemos?

Restricciones de SQL
Photo by Jose Fontano / Unsplash

A la hora de trabajar con nuestros datos hay veces que queremos mantener unas limitaciones a la hora de incorporarlos. Podemos hacerlo de distintas formas, seguramente la que se te habrá ocurrido es la de incorporar validaciones en tus modelos de datos. Si bien es una buena manera de mantener los errores en la capa de la aplicación, también es muy recomendable incorporar restricciones en la base de datos.

Estas restricciones, en caso de intentar romperlas, nos devolverá un error de SQL. Esto significa que, ya sea al intentar hacerlo desde nuestra aplicación o nosotros directamente desde la consola, no podemos tener datos inválidos almacenados.

ℹ️
Para simplificar el concepto y los ejemplos, siempre tomaré de referencia a MariaDB. Generalmente el concepto es el mismo independientemente del sistema de BBDD que utilices, pero puede tener peculiaridades únicas.

Para que se utilizan las restricciones

Una cosa que a todo desarrollador debe quedar clara es que en cualquier momento vas a romper las cosas. Si bien los usuarios son los más propensos a romper nuestra aplicación de mil maneras inimaginables (o incluso alcanzando lo que llamamos casos extremos), nosotros también podemos romper la aplicación introduciendo algún bug crítico. Es por esto por lo que debemos poner también ciertas comprobaciones para nosotros, para cuando desarrollemos no hagamos algo fatal.

Al forzar la integridad de los datos desde nuestro sistema de base de datos, evitamos que al realizar las validaciones correspondientes en la lógica de la aplicación nos dejemos algo importante por el camino y guardemos datos inválidos.

En el post de las relaciones de bases de datos, comenté que los ORMs ayudan a realizar las relaciones. Pero ayudan con todo tipo de operaciones con la base de datos. Otra de las operaciones que nos permiten es justamente implementar constraints, o restricciones.

Entendiendo las relaciones de Bases de Datos
Nadie dijo que relacionar dos tablas de tu base de datos fuera sencillo…
💡
Las restricciones se aplican en la estructura de tabla, así que hay que declararlas o bien al crearla o al alterarla.

Asumamos que tenemos el siguiente caso, queremos forzar que tenemos un programa interno de gestión de descuentos y queremos forzar que no podamos aplicar el mismo descuento dos veces para el mismo producto.

CREATE TABLE descuentos
(
    id         bigint auto_increment
        primary key,
    product_id int null,
    descuento  int null,
    constraint constraint_descuentos
        unique (product_id, descuento)
);

Comando para crear la tabla de nuestro ejemplo.

ℹ️
Para simplificar el ejemplo, simularemos que product_id es una clave foránea que vincula a una tabla de productos.

Hemos agregado la instrucción CONSTRAINT, lo que crea una clave única que restringe que la combinación de product_id y descuento sea única. Podemos probar esto intentando ejecutar el siguiente comando dos veces seguidas.

INSERT INTO descuentos (product_id, descuento) VALUES (1, 50)

La primera vez el comando funcionará, la segunda devolverá el siguiente error:

[23000][1062] Duplicate entry '1-50' for key 'descuentos.constraint_descuentos'

Esto nos indica que tenemos una entrada duplicada cuando tenemos una restricción única para esa combinación, por lo que no nos dejará crearla con esta combinación de valores. No obstante, si lo intentamos con otros valores sí nos dejará.

INSERT INTO descuentos (product_id, descuento) VALUES (1, 30)

Si volvemos a intentar lo mismo de ejecutar 2 veces esta instrucción no nos dejará con el mismo error. De esta manera hemos asegurado a nivel de base de datos que no tengamos descuentos del mismo valor duplicados.


Todo esto no quita que se deba realizar las validaciones a nivel de aplicación mediante validadores, ya que siempre es mejor manejar los errores a nivel de aplicación, pero esto nos permite que valores inválidos alcancen nuestra BBDD.