Aprende Bases de datos y SQL desde cero
1Qué es una base de datos relacional
Una base de datos relacional guarda los datos en tablas. Una tabla parece una hoja de cálculo: cada fila es un registro, cada columna es una propiedad.
Una tienda podría tener una tabla customers con las columnas id, name y city, y una tabla orders con las columnas id, customer_id y total.
Una clave primaria es una columna, o un conjunto de columnas, que identifica cada fila de forma única. Nunca puede repetirse ni estar vacía. Aquí es el id de cada tabla.
Una clave foránea es una columna que hace referencia a la clave primaria de otra tabla. En orders, customer_id indica qué cliente hizo el pedido.
Así se enlazan las tablas: un cliente puede tener muchos pedidos, pero cada pedido pertenece a un solo cliente. Es una relación uno a muchos.
SQL (Structured Query Language) es el lenguaje que se usa para crear tablas, modificar datos y hacer consultas sobre ellos.
Autoevaluación ¿Qué es una clave primaria?
- La primera columna de cada tabla
- Un índice que acelera las búsquedas
- Una columna o un conjunto de columnas que identifica cada fila de forma única
- Una columna que hace referencia a una fila de otra tabla
Respuesta: Una columna o un conjunto de columnas que identifica cada fila de forma única. Una clave primaria es única y nunca es NULL, así que señala exactamente una fila. Una columna que hace referencia a otra tabla es una clave foránea.
2Leer datos con SELECT
La mayoría de las preguntas tratan de la sentencia SELECT. Se construye con cláusulas, que siempre se escriben en este orden:
SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY …
- SELECT enumera las columnas que quieres. DISTINCT elimina las filas duplicadas.
- FROM nombra la tabla, o las tablas combinadas.
- WHERE conserva solo las filas que cumplen una condición, por ejemplo WHERE total > 20.
- GROUP BY junta en un grupo las filas con el mismo valor, para que puedas contar o sumar por grupo.
- HAVING conserva solo los grupos que cumplen una condición. Puede usar agregados, cosa que WHERE no puede.
- ORDER BY ordena el resultado, de forma ascendente por defecto; añade DESC para el mayor primero.
Las funciones de agregación resumen muchas filas en un valor: COUNT, SUM, AVG, MIN y MAX.
La base de datos no ejecuta las cláusulas en el orden en que las escribes. Ejecuta primero FROM, luego WHERE, GROUP BY, HAVING, SELECT y por último ORDER BY.
Otras sentencias modifican datos: INSERT añade filas, UPDATE cambia filas y DELETE elimina filas. CREATE, ALTER y DROP cambian las propias tablas.
Autoevaluación Quieres solo los clientes con más de 5 pedidos. ¿Qué cláusula filtra por COUNT(*) > 5?
- DISTINCT
- HAVING
- ORDER BY
- WHERE
Respuesta: HAVING. El recuento solo existe después de agrupar las filas, y HAVING filtra grupos. WHERE se ejecuta antes de agrupar, así que no puede usar un agregado como COUNT.
3Joins, normalización y transacciones
Un join combina filas de dos tablas mediante una condición, normalmente clave foránea = clave primaria:
FROM customers c JOIN orders o ON o.customer_id = c.id
- INNER JOIN (o JOIN) conserva solo las filas que tienen correspondencia en ambas tablas.
- LEFT JOIN conserva todas las filas de la tabla izquierda. Donde no hay correspondencia, las columnas de la tabla derecha son NULL.
- NULL significa que falta un valor o que es desconocido. Se comprueba con IS NULL, nunca con = NULL.
La normalización divide las tablas para que cada dato se guarde una sola vez. Así se evita actualizar el mismo dato en varios sitios.
- 1FN: cada celda contiene un único valor atómico, sin grupos repetidos.
- 2FN: 1FN, y cada columna que no es clave depende de toda la clave, no de una parte de una clave compuesta.
- 3FN: 2FN, y ninguna columna que no es clave depende de otra columna que no es clave.
Una transacción agrupa sentencias en una unidad. COMMIT la hace permanente y ROLLBACK la deshace. Las transacciones cumplen ACID: atomicidad (todo o nada), consistencia, aislamiento y durabilidad.
Autoevaluación Un cliente no ha hecho ningún pedido. ¿Qué le ocurre a ese cliente en customers LEFT JOIN orders?
- Aparece una vez por cada pedido de la tabla
- Aparece una vez, con NULL en las columnas del pedido
- La consulta falla con un error
- Queda fuera del resultado
Respuesta: Aparece una vez, con NULL en las columnas del pedido. Un LEFT JOIN conserva todas las filas de la tabla izquierda y rellena con NULL el lado derecho que falta. Dejar fuera al cliente es lo que hace un INNER JOIN.
4El método paso a paso
Para escribir una consulta, o para averiguar qué devuelve una consulta dada:
- Encuentra las tablas que contienen los datos y cómo se enlazan mediante claves.
- Escribe FROM con los joins. Elige LEFT JOIN cuando las filas sin correspondencia deban permanecer.
- Añade WHERE para las condiciones sobre filas individuales.
- Si la pregunta dice “por” o “para cada”, añade GROUP BY y el agregado.
- Añade HAVING para las condiciones sobre el agregado, y luego ORDER BY si importa el orden.
- Comprueba el resultado con un ejemplo pequeño: enumera las filas tras cada cláusula, en el orden en que las ejecuta la base de datos.
En una pregunta de teoría, nombra primero el concepto (una clave, un tipo de join, una forma normal, una propiedad ACID) y luego elige la opción que coincida con su definición.
5Un ejemplo resuelto
Sigue cada paso. Intenta adivinar el siguiente antes de abrirlo.
Ejemplo resueltoLa tabla customers tiene las filas (1, Ana), (2, Ben) y (3, Cas). La tabla orders tiene las filas (id, customer_id) = (10, 1), (11, 1), (12, 2) y (13, 1). ¿Qué devuelve esta consulta? SELECT c.name, COUNT(o.id) FROM customers c LEFT JOIN orders o ON o.customer_id = c.id GROUP BY c.name
1Cada cliente se empareja con los pedidos que llevan su id. Ana coincide con los pedidos 10, 11 y 13. Ben coincide con el pedido 12.
Cas no tiene pedidos. Como es un LEFT JOIN, Cas permanece en el resultado, con NULL en o.id.
2- Ana, 10
- Ana, 11
- Ana, 13
- Ben, 12
- Cas, NULL
Son 5 filas.
3GROUP BY c.name forma tres grupos: Ana con 3 filas, Ben con 1 fila y Cas con 1 fila.
4COUNT(o.id) cuenta solo los valores que no son NULL. Ana obtiene 3 y Ben obtiene 1.
Cas tiene una fila, pero su o.id es NULL, así que Cas obtiene 0.
5Ana, Ben y Cas juntos tienen 3 + 1 + 0 = 4 pedidos, igual que el número de filas de orders. Con COUNT(*) en su lugar, Cas obtendría 1 por error, porque COUNT(*) cuenta la propia fila.
Respuesta Ana 3, Ben 1, Cas 0.
6Errores frecuentes
- Usar un agregado en WHERE. Las condiciones sobre COUNT, SUM o AVG van en HAVING.
- Escribir = NULL. Cualquier comparación con NULL es desconocida; usa IS NULL o IS NOT NULL.
- Usar un INNER JOIN cuando las filas sin correspondencia deben permanecer. Usa un LEFT JOIN.
- Olvidar la condición del join. Sin ON, cada fila se empareja con todas las filas (un producto cartesiano).
- Seleccionar una columna que no está en GROUP BY ni dentro de un agregado.
- Confundir DELETE (elimina filas) con DROP TABLE (elimina la tabla entera).
- Ejecutar UPDATE o DELETE sin WHERE. Cambia todas las filas de la tabla.
Autoevaluación Una tabla tiene 10 filas, y la columna col es NULL en todas. ¿Qué devuelve SELECT COUNT(col)?
- 0
- 10
- 1
- NULL
Respuesta: 0. COUNT(col) cuenta solo los valores que no son NULL, así que devuelve 0. COUNT(*) cuenta filas y devolvería 10.
7Cómo son las preguntas de examen
- Fácil: términos y datos clave. Qué hacen SELECT, WHERE, ORDER BY o DELETE, claves primarias y foráneas, qué significa NULL.
- Medio: aplicar los conceptos. La consulta adecuada para una tarea, WHERE frente a HAVING, joins internos frente a externos, las formas normales, ACID.
- Difícil: casos y análisis. Subconsultas, niveles de aislamiento y sus anomalías, BCNF, funciones de ventana, índices y rendimiento de consultas, inyección SQL.
Cuando se da una consulta, síguela con unas pocas filas en el orden FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY. La mayoría de las trampas aparecen en tres filas.
Apréndelo paso a paso en la appApréndelo paso a paso en la app