Cómo escribir consultas SQL que combinan múltiples subconsultas

Las subconsultas SQL son una técnica poderosa para ejecutar una consulta dentro de otra consulta. Especialmente, combinando múltiples subconsultas de manera efectiva, es posible realizar extracciones y análisis de datos complejos. En este artículo, comenzaremos con lo básico de las subconsultas, exploraremos subconsultas correlacionadas y combinaciones de múltiples subconsultas, y finalmente, proporcionaremos ejemplos prácticos para explicar cómo escribir consultas SQL utilizando subconsultas. También se ofrecen consejos para optimizar el rendimiento. Si deseas mejorar tus habilidades en SQL, te invitamos a leer este artículo.

Índice

Conceptos básicos de las subconsultas

Una subconsulta es una consulta SQL que se incluye dentro de otra consulta SQL. Las subconsultas se utilizan para proporcionar datos a la consulta principal, y los resultados se utilizan dentro de la consulta principal. A continuación, se muestra un ejemplo básico de subconsulta.

Estructura básica

Una subconsulta básica se utiliza dentro de una sentencia SELECT y está delimitada por paréntesis. Por ejemplo, una subconsulta para encontrar al empleado con el salario más alto sería así:

SELECT employee_name
FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);

Tipos de subconsultas

Existen varios tipos de subconsultas:

  • Subconsulta de una sola fila: una subconsulta que devuelve un solo resultado.
  • Subconsulta de múltiples filas: una subconsulta que devuelve múltiples resultados.
  • Subconsulta correlacionada: una subconsulta que depende de cada fila de la consulta principal.

Entender lo básico de las subconsultas es el primer paso para crear consultas más complejas. A continuación, explicaremos en detalle las subconsultas correlacionadas.

Subconsultas correlacionadas

Las subconsultas correlacionadas son subconsultas que se ejecutan para cada fila de la consulta principal y hacen referencia a columnas de la consulta principal. Esto permite una extracción de datos más dinámica y flexible.

Concepto de subconsultas correlacionadas

Las subconsultas correlacionadas dependen de cada fila de la consulta principal, y la consulta principal y la subconsulta están interrelacionadas. Esto permite realizar comparaciones y agregaciones de datos más complejas.

Estructura básica de las subconsultas correlacionadas

La estructura básica de una subconsulta correlacionada es la siguiente. En el ejemplo siguiente, se extraen los empleados cuyo salario es superior al salario promedio de su departamento.

SELECT employee_name, salary
FROM employees e1
WHERE salary > (
    SELECT AVG(salary)
    FROM employees e2
    WHERE e1.department_id = e2.department_id
);

En esta consulta, la consulta externa (consulta principal) y la consulta interna (subconsulta) están relacionadas por department_id, y se verifica si el salario de cada empleado es superior al salario promedio de su departamento.

Ventajas de las subconsultas correlacionadas

Las subconsultas correlacionadas tienen las siguientes ventajas:

  • Flexibilidad: Permiten establecer condiciones complejas y realizar diferentes cálculos y comparaciones para cada fila de la consulta principal.
  • Extracción de datos dinámica: Generan resultados dinámicamente en función de los datos de la consulta principal.

A continuación, presentaremos cómo combinar múltiples subconsultas para realizar extracciones de datos complejas.

Cómo combinar múltiples subconsultas

Al combinar múltiples subconsultas, es posible realizar extracciones y análisis de datos extremadamente complejos y detallados. Aquí explicamos cómo utilizar múltiples subconsultas de manera efectiva.

Subconsultas anidadas

Al anidar una subconsulta dentro de otra subconsulta, se puede realizar una extracción de datos jerárquica. En el ejemplo siguiente, se obtiene el nombre del departamento del empleado con el salario más alto.

SELECT department_name
FROM departments
WHERE department_id = (
    SELECT department_id
    FROM employees
    WHERE salary = (
        SELECT MAX(salary)
        FROM employees
    )
);

Esta consulta encuentra al empleado con el salario más alto y luego obtiene el nombre del departamento al que pertenece ese empleado.

Combinación con subconsultas correlacionadas

También es posible combinar subconsultas correlacionadas con otras subconsultas. En el ejemplo siguiente, se verifica si el salario de cada empleado es superior al salario promedio de su departamento, y luego se obtiene el nombre del departamento correspondiente.

SELECT employee_name, department_name
FROM employees e1
JOIN departments d ON e1.department_id = d.department_id
WHERE salary > (
    SELECT AVG(salary)
    FROM employees e2
    WHERE e1.department_id = e2.department_id
);

Esta consulta utiliza una subconsulta correlacionada para verificar si el salario de cada empleado es superior al salario promedio de su departamento, y luego obtiene el nombre del departamento basado en ese resultado.

Subconsultas utilizando múltiples cláusulas WITH

Cuando se utilizan múltiples subconsultas, el uso de la cláusula WITH (Expresión de Tabla Común, CTE) puede hacer que la consulta sea más legible y fácil de mantener. A continuación se muestra un ejemplo que utiliza CTE.

WITH MaxSalary AS (
    SELECT department_id, MAX(salary) AS max_salary
    FROM employees
    GROUP BY department_id
),
HighEarners AS (
    SELECT e.employee_name, d.department_name, e.salary
    FROM employees e
    JOIN departments d ON e.department_id = d.department_id
    JOIN MaxSalary m ON e.department_id = m.department_id AND e.salary = m.max_salary
)
SELECT * FROM HighEarners;

En esta consulta, primero se obtiene a los empleados con los salarios más altos en cada departamento y luego se seleccionan los nombres y los departamentos de esos empleados.

A continuación, se muestra un ejemplo práctico de subconsulta anidada que es útil en la vida real.

Ejemplo práctico 1: Subconsulta anidada

Las subconsultas anidadas se utilizan para realizar extracciones de datos jerárquicas. En esta sección, explicaremos cómo usar subconsultas anidadas a través de ejemplos prácticos.

Ejemplo: Obtener el empleado con el salario más alto en un departamento específico

En este ejemplo, se obtiene el empleado con el salario más alto en un departamento específico (por ejemplo, el departamento con ID 5).

SELECT employee_name, salary
FROM employees
WHERE salary = (
    SELECT MAX(salary)
    FROM employees
    WHERE department_id = 5
);

En esta consulta, la subconsulta interna encuentra el salario más alto entre los empleados del departamento con ID 5, y la consulta externa utiliza ese resultado para obtener el nombre y salario del empleado correspondiente.

Ejemplo: Obtener el empleado con el salario más alto en cada departamento

Un ejemplo más complejo muestra cómo obtener al empleado con el salario más alto en cada departamento.

SELECT employee_name, department_id, salary
FROM employees e1
WHERE salary = (
    SELECT MAX(salary)
    FROM employees e2
    WHERE e1.department_id = e2.department_id
);

Esta consulta utiliza una subconsulta correlacionada para encontrar al empleado con el salario más alto en cada departamento. La subconsulta interna obtiene el salario máximo basado en el department_id pasado desde la consulta externa, y esa consulta externa selecciona al empleado correspondiente.

Ejemplo: Obtener detalles del empleado con el salario más alto en cada departamento

Finalmente, se muestra cómo obtener los detalles del empleado con el salario más alto en cada departamento (nombre, salario, nombre del departamento).

SELECT e1.employee_name, e1.salary, d.department_name
FROM employees e1
JOIN departments d ON e1.department_id = d.department_id
WHERE e1.salary = (
    SELECT MAX(e2.salary)
    FROM employees e2
    WHERE e2.department_id = e1.department_id
);

Esta consulta encuentra primero al empleado con el salario más alto en cada departamento y luego obtiene los detalles del empleado correspondiente junto con el nombre del departamento.

A continuación, explicaremos cómo organizar subconsultas complejas utilizando la cláusula WITH.

Ejemplo práctico 2: Subconsultas utilizando la cláusula WITH

El uso de la cláusula WITH (Expresión de Tabla Común, CTE) permite organizar consultas complejas de una manera más comprensible y fácil de mantener. En esta sección, se muestra cómo resumir subconsultas utilizando la cláusula WITH a través de ejemplos prácticos.

Ejemplo: Obtener al empleado con el salario más alto en cada departamento

Primero, se muestra cómo obtener al empleado con el salario más alto en cada departamento utilizando la cláusula WITH.

WITH MaxSalaries AS (
    SELECT department_id, MAX(salary) AS max_salary
    FROM employees
    GROUP BY department_id
)
SELECT e.employee_name, e.salary, d.department_name
FROM employees e
JOIN MaxSalaries m ON e.department_id = m.department_id AND e.salary = m.max_salary
JOIN departments d ON e.department_id = d.department_id;

En esta consulta, se utiliza un CTE llamado MaxSalaries para calcular el salario máximo en cada departamento, y luego se utiliza en la consulta principal. Esto hace que la consulta sea más legible.

Ejemplo: Obtener al vendedor con mayores ventas

A continuación, se muestra un ejemplo para obtener la información detallada del vendedor con las mayores ventas.

WITH SalesData AS (
    SELECT salesperson_id, SUM(sales_amount) AS total_sales
    FROM sales
    GROUP BY salesperson_id
),
TopSalesperson AS (
    SELECT salesperson_id, MAX(total_sales) AS max_sales
    FROM SalesData
)
SELECT s.salesperson_name, sd.total_sales
FROM SalesData sd
JOIN TopSalesperson ts ON sd.salesperson_id = ts.salesperson_id AND sd.total_sales = ts.max_sales
JOIN salespersons s ON sd.salesperson_id = s.salesperson_id;

En esta consulta, se utiliza un CTE llamado SalesData para calcular las ventas totales de cada vendedor y un CTE llamado TopSalesperson para identificar al vendedor con las mayores ventas. Finalmente, se obtiene la información detallada de ese vendedor.

Ejemplo: Obtener las ventas promedio mensuales de un año específico

Finalmente, se muestra cómo obtener las ventas promedio mensuales de un año específico utilizando la cláusula WITH.

WITH MonthlySales AS (
    SELECT DATE_TRUNC('month', sale_date) AS month, AVG(sales_amount) AS avg_sales
    FROM sales
    WHERE EXTRACT(year FROM sale_date) = 2023
    GROUP BY DATE_TRUNC('month', sale_date)
)
SELECT month, avg_sales
FROM MonthlySales
ORDER BY month;

En esta consulta, se utiliza un CTE llamado MonthlySales para calcular las ventas promedio mensuales de 2023, y el resultado se utiliza en la consulta principal. Esto permite obtener las ventas promedio mensuales de manera sencilla.

A continuación, presentaremos consejos y técnicas para optimizar el rendimiento de consultas SQL que utilizan subconsultas.

Optimización del rendimiento

Las consultas SQL que utilizan subconsultas son poderosas, pero también pueden causar problemas de rendimiento. Aquí, presentamos consejos y técnicas para optimizar el rendimiento de consultas SQL que utilizan subconsultas.

Uso de índices

Crear índices en las columnas utilizadas por las subconsultas puede mejorar significativamente la velocidad de ejecución de la consulta. Es importante establecer índices en las columnas que se utilizan con frecuencia dentro de las subconsultas.

CREATE INDEX idx_department_id ON employees(department_id);

En este ejemplo, se crea un índice en la columna department_id para acelerar la búsqueda.

Evitar subconsultas innecesarias

Algunas subconsultas son redundantes y pueden simplificarse utilizando JOINs. Eliminar subconsultas innecesarias puede mejorar el rendimiento de la consulta.

-- Ejemplo con subconsulta
SELECT e.employee_name, d.department_name
FROM employees e
WHERE e.department_id = (SELECT department_id FROM departments WHERE department_name = 'Sales');

-- Ejemplo optimizado con JOIN
SELECT e.employee_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = 'Sales';

En este ejemplo, la subconsulta se reemplaza por un JOIN, lo que simplifica y acelera la consulta.

Optimización utilizando EXISTS

Cuando se utiliza una subconsulta para verificar la existencia de resultados, el operador EXISTS puede mejorar el rendimiento. EXISTS finaliza el procesamiento tan pronto como encuentra una fila coincidente, lo que lo hace eficiente.

-- Ejemplo con subconsulta
SELECT employee_name
FROM employees
WHERE department_id IN (SELECT department_id FROM departments WHERE location = 'New York');

-- Ejemplo optimizado con EXISTS
SELECT employee_name
FROM employees e
WHERE EXISTS (
    SELECT 1
    FROM departments d
    WHERE e.department_id = d.department_id AND d.location = 'New York'
);

En este ejemplo, se reemplaza el operador IN por EXISTS para mejorar la eficiencia de la consulta.

Uso de vistas

Cuando se ejecutan frecuentemente consultas que incluyen subconsultas complejas, convertir esas subconsultas en vistas puede mejorar el rendimiento. Las vistas almacenan el resultado de la consulta como una tabla virtual, lo que facilita su reutilización.

-- Creación de una vista
CREATE VIEW HighSalaryEmployees AS
SELECT employee_name, salary, department_id
FROM employees
WHERE salary > 100000;

-- Consulta utilizando la vista
SELECT e.employee_name, d.department_name
FROM HighSalaryEmployees e
JOIN departments d ON e.department_id = d.department_id;

En este ejemplo, se crea una vista llamada HighSalaryEmployees y se utiliza para mejorar la legibilidad y el rendimiento de la consulta.

Actualización de estadísticas

Actualizar periódicamente las estadísticas de la base de datos permite al optimizador de consultas generar un plan de ejecución óptimo. Las estadísticas incluyen información sobre índices y cardinalidad de tablas.

-- Actualización de estadísticas (Ejemplo: PostgreSQL)
ANALYZE employees;

En este ejemplo, se actualizan las estadísticas de la tabla employees para optimizar el rendimiento de las consultas.

Conclusión

En este artículo, hemos explicado cómo escribir consultas SQL que combinan múltiples subconsultas. Hemos cubierto lo básico de las subconsultas, subconsultas correlacionadas, combinaciones de múltiples subconsultas, ejemplos prácticos de subconsultas anidadas y utilizando la cláusula WITH, y finalmente, optimización del rendimiento. Al aplicar estas técnicas, podrás crear consultas SQL más eficientes y poderosas. Aprovecha estas habilidades para mejorar tu capacidad de extracción y análisis de datos complejos con SQL.

Índice