Dos teléfonos para un mismo cliente
Un taller de bicicletas de Bilbao guarda todas sus reparaciones en una sola tabla. Cada fila repite el nombre y el teléfono del cliente.
Un día, Iñaki cambia de número. Alguien lo actualiza en una fila, pero no en las otras.
Ahora el taller tiene dos teléfonos para Iñaki y no sabe a cuál llamar.
Al final de esta lección
Nota
Puedo separar los datos en tablas para que cada dato se guarde una sola vez.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Redundancia | el mismo dato guardado en varios sitios |
| Inconsistencia | dos copias de un dato que no coinciden |
| Normalizar | separar los datos en tablas para no repetirlos |
| Desnormalizar | repetir un dato a propósito para leer más rápido |
| NoSQL | bases de datos que no guardan tablas, sino documentos u otras formas |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Repetir un dato acaba en contradicción
Si un dato está escrito en tres filas, hay que cambiarlo en las tres. Basta con olvidar una para que la tabla diga dos cosas distintas.
Ese problema se llama inconsistencia. Pasa con teléfonos, direcciones y precios, y siempre sale caro: una llamada al número equivocado, un paquete perdido.
Prueba: encuentra la contradicción
-- ¿Cuántos teléfonos distintos tiene Iñaki?
SELECT customer, phone, COUNT(*) AS num_rows
FROM repairs
GROUP BY customer, phone;
-- Un mismo cliente con dos teléfonos: ¿cuál es el bueno?
Cada cosa en su propia tabla
La solución es separar. Los clientes van en una tabla customers, con su teléfono una sola vez.
Las reparaciones van en otra tabla y solo guardan customer_id, una clave foránea.
Para saber de quién es una reparación, unes las dos tablas con JOIN. Si Iñaki cambia de número, cambias una sola fila.
Prueba: un cambio en un solo sitio
-- Iñaki cambia de teléfono: se cambia en un solo sitio.
UPDATE customers SET phone = '622999888' WHERE id = 1;
-- Todas sus reparaciones muestran ya el número nuevo.
SELECT repairs.id, customers.name, customers.phone, repairs.price
FROM repairs
JOIN customers ON repairs.customer_id = customers.id;
Ejemplo: antes y después de separar
| Una tabla | Dos tablas | |
|---|---|---|
| Teléfono de Iñaki | Escrito 3 veces | Escrito 1 vez |
| Cambiar su número | 3 filas | 1 fila |
| Ver una reparación con su cliente | Una consulta simple | Una consulta con JOIN |
| Riesgo de contradicción | Alto | Casi nulo |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un error frecuente
Advertencia
Mucha gente cree que hay que separar siempre al máximo. No siempre compensa. Un informe que se lee miles de veces al día puede guardar un total ya calculado. Es desnormalizar a propósito: se gana velocidad y se acepta cuidar esa copia.
Cuándo encaja una base NoSQL
Algunos datos no caben bien en columnas fijas. En una tienda, un casco tiene tallas y una luz tiene horas de batería.
Una base de documentos, como MongoDB, guarda cada ficha entera, con sus propios datos. Encaja cuando la ficha se lee de una vez y cambia de forma de un producto a otro. Para pedidos, pagos y clientes, las tablas siguen siendo la opción habitual.
Prueba: una ficha como documento
# Una ficha de producto como documento, al estilo de una base NoSQL.
# Cada producto lleva los datos que necesita, sin columnas vacías.
helmet = {
"name": "Casco urbano",
"price": 49,
"sizes": ["S", "M", "L"],
}
light = {
"name": "Luz delantera",
"price": 22,
"battery_hours": 12,
}
for product in [helmet, light]:
print(product["name"], "tiene", len(product), "datos")
# Añade a light el dato "color": "negro" y vuelve a ejecutar.