Pregunta 1¿Cuál de estas es obligatoria cuando escribes una subconsulta (tabla derivada) en la cláusula FROM?
Subconsultas ② — Tablas derivadas, subconsultas en SELECT, CREATE / INSERT SELECT
Aprende las tablas derivadas SQL, las subconsultas en la cláusula SELECT, su combinación con CASE y CREATE / INSERT SELECT — práctica con datos de empleados y ventas en tu navegador.
Datos usados en este artículo — employee / department / sales
La última vez usaste una subconsulta en WHERE.
En este artículo recorrerás cuatro aplicaciones en orden: poner una subconsulta en la cláusula `FROM` (una tabla derivada), escribir una en una columna de `SELECT`, combinarla con `CASE` y construir una tabla nueva a partir del resultado de una subconsulta.
El material son tres tablas de datos de empleados.
Usando employee (30 empleados), department (6 departamentos) y sales (50 líneas de venta), construirás una tabla de agregados por departamento y alinearás las ventas totales de cada empleado como una columna.
Tablas derivadas en FROM — tratar el resultado de una subconsulta como una sola tabla
Una tabla derivada es una forma de escribir una subconsulta en la cláusula FROM de modo que su resultado se trate como una sola tabla virtual.
Puedes construir primero "el salario promedio por departamento" como una tabla de agregados, y luego aplicar más JOIN o WHERE a esa tabla.
Es útil cuando quieres reducir un resultado agregado un paso más.
La regla clave de las tablas derivadas es que debes darle un alias.
Escribe AS alias como FROM (SELECT ...) AS ds (SQLite también te deja omitir AS) — sin él obtienes un error.
A través de ese alias referencias las columnas de la tabla derivada, como ds.avg_salary.
-- Tabla derivada en FROM: agregar plantilla y salario promedio por departamento, luego unir con department
SELECT d.dept_name, ds.headcount, ds.avg_salary
FROM (
SELECT dept_id, COUNT(*) AS headcount, AVG(salary) AS avg_salary
FROM employee
WHERE dept_id IS NOT NULL
GROUP BY dept_id
) AS ds
JOIN department d ON d.dept_id = ds.dept_id
ORDER BY ds.avg_salary DESC;
Subconsultas en la cláusula SELECT — incrustar un único valor como columna
Cuando escribes una subconsulta escalar en la lista de columnas de SELECT, puedes añadir una columna cuyo valor se calcula uno por fila.
Pon (SELECT SUM(sale.amount) FROM sales sale WHERE sale.emp_id = emp.emp_id) en una columna, y podrás alinear "las ventas totales de ese empleado" como una columna por empleado.
Esta es una subconsulta correlacionada que referencia el emp.emp_id exterior.
-- Subconsulta en la cláusula SELECT: añadir las ventas totales de cada empleado como una columna
SELECT emp.name,
COALESCE(
(SELECT SUM(sale.amount) FROM sales sale WHERE sale.emp_id = emp.emp_id),
0
) AS total_amount
FROM employee emp
ORDER BY emp.emp_id
LIMIT 6;
Un empleado sin ventas hace que la subconsulta devuelva NULL, así que reemplazarlo por 0 con COALESCE(..., 0) hace que la tabla sea más fácil de leer.
Una subconsulta en la cláusula SELECT también tiene que caber en una fila y una columna.
Combinar con CASE — adjuntar una etiqueta de ramificación según el valor de una subconsulta
Una subconsulta en la cláusula SELECT funciona igual de bien como condición en CASE.
Puedes construir una columna de rango como "si las ventas totales son 1,500,000 o más entonces High, si son mayores que 0 entonces Mid, si no None" juzgando el valor de la subconsulta con CASE WHEN.
Ten en cuenta que tienes que repetir la misma subconsulta en cada WHEN del CASE (si lo primero es la legibilidad, también hay una forma de escribirla solo una vez con WITH (expresiones de tabla común), que aprenderás en un capítulo posterior).
En este artículo cubrirás la forma básica de combinar una subconsulta y CASE directamente.
-- Clasificar empleados por su número de ventas
SELECT emp.name,
(SELECT COUNT(*) FROM sales sale WHERE sale.emp_id = emp.emp_id) AS sale_count,
CASE
WHEN (SELECT COUNT(*) FROM sales sale WHERE sale.emp_id = emp.emp_id) >= 4 THEN 'Frequent'
WHEN (SELECT COUNT(*) FROM sales sale WHERE sale.emp_id = emp.emp_id) >= 1 THEN 'Occasional'
ELSE 'None'
END AS activity
FROM employee emp
ORDER BY sale_count DESC, emp.emp_id
LIMIT 8;
CREATE / INSERT SELECT — convertir el resultado de una subconsulta en una tabla
Escribir CREATE TABLE new_table AS SELECT ... te permite guardar el resultado del SELECT directamente como una tabla nueva (CTAS: Create Table As Select).
Se usa a menudo cuando quieres conservar un resultado agregado como una instantánea.
Cuando quieres añadir filas a una tabla que ya existe, usa INSERT INTO existing_table SELECT ... para añadir en bloque el resultado del SELECT.
Estas son operaciones de escritura que crean una tabla o añaden filas.
En este artículo usarás una tabla de trabajo desechable top_seller para la agregación.
Para que obtengas el mismo resultado sin importar cuántas veces lo ejecutes, limpiarás la tabla de trabajo con DROP TABLE IF EXISTS antes de recrearla.
El INSERT en bloque es más rápido
INSERT INTO table SELECT ... inserta las filas objetivo todas a la vez en una sola sentencia.
Comparado con repetir INSERT INTO table VALUES (...) para cada fila, el análisis del SQL, las actualizaciones de índices y el manejo de la transacción ocurren una sola vez, así que cuantas más filas insertes, más rápido se vuelve.
Al copiar o mover otra tabla o un resultado agregado, prefiere el INSERT ... SELECT en bloque antes que repetir el INSERT fila a fila.
-- Guardar un agregado por departamento en una tabla de instantánea
DROP TABLE IF EXISTS dept_summary;
CREATE TABLE dept_summary AS
SELECT dept_id, COUNT(*) AS headcount, AVG(salary) AS avg_salary
FROM employee
WHERE dept_id IS NOT NULL
GROUP BY dept_id;
SELECT * FROM dept_summary ORDER BY avg_salary DESC;
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2En SELECT emp.name, (SELECT SUM(sale.amount) FROM sales sale WHERE sale.emp_id = emp.emp_id) AS total FROM employee emp, ¿qué le pasa a la columna total para un empleado sin ninguna venta?
Pregunta 3¿Cuál es una descripción correcta de CREATE TABLE top_seller AS SELECT ...?