Ir al contenido
wannacode

Claves foráneas: vínculos entre tablas

En resumen: REFERENCES convierte una columna en clave foránea, y ON DELETE (CASCADE, SET NULL, RESTRICT) dice qué pasa con las filas que apuntan a una fila borrada.

Problema

Borra mi cuenta

Maria Ivanova escribe: «Por favor, borra mi cuenta.» Lo intentas:

SQLbase de datos: tienda

La base de datos se niega. Maria tiene 12 pedidos, y cada uno apunta a ella. Si la clienta desaparece, los pedidos apuntarán a nadie.

¿Qué debe pasar con sus pedidos? ¿Y con sus reseñas? ¿Y con su lista de productos favoritos? La respuesta es distinta para cada tabla. Y está escrita en el esquema.

La idea

REFERENCES

Ya conoces la clave foránea: una columna que apunta a una fila de otra tabla. En CREATE TABLE se escribe con REFERENCES tabla(columna). Así están hechos los pedidos de la tienda:

orders

  • PKidinteger
  • FKcustomer_idinteger *→ customers
  • ordered_attext *
  • statustext *

Aquí hay una tabla nueva: los productos favoritos de cada cliente. La primera fila entra, la segunda apunta al cliente 99, que no existe:

SQLbase de datos: tienda

Ahora la base de datos vigila los vínculos ella misma. Una fila que apunta a un cliente o a un producto que no existe no entra.

Pruébalo

Los productos favoritos

La tabla wishlist ya tiene sus columnas. Haz que customer_id apunte a customers y product_id a products.

SQLbase de datos: tienda

La idea

ON DELETE CASCADE

Después de REFERENCES puedes decir qué debe pasar cuando se borra la fila a la que apuntas. Eso es ON DELETE.

CASCADE significa «bórrame a mí también». Yavor Penev (cliente 20) tiene dos productos favoritos. Teodora Genova (cliente 19) tiene uno. Yavor borra su cuenta:

SQLbase de datos: tienda

Los favoritos de Yavor se fueron con él. Los de Teodora siguen ahí. Una lista de favoritos no tiene sentido sin el cliente, así que CASCADE es lo correcto aquí.

La idea

SET NULL y RESTRICT

SET NULL significa «consérvame, pero sin el vínculo». Las preguntas sobre productos también son útiles para otros compradores, aunque el autor se haya ido:

SQLbase de datos: tienda

La pregunta se quedó, y customer_id pasó a NULL: una pregunta de un cliente que ya no está.

RESTRICT significa «no permitas el borrado». Las facturas hay que conservarlas durante años por ley:

SQLbase de datos: tienda

Sin ON DELETE el comportamiento es casi el mismo: el borrado se detiene. Por eso Maria no pudo borrar su cuenta. Los pedidos son la historia de la tienda y no deben desaparecer.

Más precisamente, para curiosos

Sin ON DELETE la regla es NO ACTION. La única diferencia con RESTRICT es cuándo se comprueba: RESTRICT se detiene al instante, mientras que NO ACTION comprueba al final de la sentencia (o de la transacción, si la comprobación está aplazada). También existe ON UPDATE para cambiar la clave, pero se usa poco, porque una clave primaria casi nunca cambia. ON DELETE SET DEFAULT también es raro.

Míralo

SET NULL contra NOT NULL

Alguien escribió la tabla de preguntas así:

customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE SET NULL

Yavor borra su cuenta otra vez:

SQLbase de datos: tienda

SET NULL quiere guardar NULL, y NOT NULL no lo permite. El borrado se detiene. SQLite no te avisa de esto en CREATE TABLE, solo cuando alguien intenta borrar. Una columna con SET NULL debe poder quedar vacía.

Pruébalo

Las direcciones de entrega

La tabla addresses guarda las direcciones de los clientes. Cuando un cliente borra su cuenta, sus direcciones deben desaparecer con él. Corrige customer_id.

SQLbase de datos: tienda

La idea

La comprobación tiene que estar activada

En el curso la base de datos comprueba las claves foráneas. Se lo preguntas con PRAGMA, el comando de SQLite para sus ajustes:

SQLbase de datos: tienda

1 significa «activada». Si la desactivas, REFERENCES ya no vigila nada:

SQLbase de datos: tienda

Un pedido del cliente 99, que no existe, entró sin ningún error.

Más precisamente, para curiosos

En SQLite real la comprobación está desactivada por defecto. Abre sqlite3 en tu computadora y escribe PRAGMA foreign_keys;: la respuesta es 0. La razón son los programas antiguos escritos antes de que SQLite comprobara las claves foráneas. El ajuste vale solo para una conexión a la base de datos. Por eso un programa ejecuta PRAGMA foreign_keys = ON; cada vez que abre la base. Esta página lo hace por ti. PostgreSQL, MySQL (con InnoDB) y SQL Server comprueban las claves foráneas por defecto.

Ejercicio

Preguntas sobre productos

La tabla questions tiene id, product_id, customer_id y body. Cuando un producto se retira de la tienda, las preguntas sobre él desaparecen. Cuando un cliente borra su cuenta, sus preguntas se quedan, pero sin autor. Añade los vínculos.

SQLbase de datos: tienda

Test

Ponte a prueba

1. La tabla orders tiene customer_id REFERENCES customers(id) sin ON DELETE. ¿Qué pasa con un DELETE de un cliente que tiene pedidos?
2. Un cliente borra su cuenta. ¿Qué le va a su lista de productos favoritos?
3. La columna es customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE SET NULL. ¿Qué pasa cuando se borra al cliente?
4. Ejecutas un script en SQLite de verdad, y un INSERT que apunta a un cliente que no existe pasa. ¿Por qué?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·