Subconsultas y Operaciones Anidadas en MySQL

MySQLBeginner
Practicar Ahora

Introducción

En este laboratorio, explorará el poder de las subconsultas y las operaciones anidadas de MySQL. El enfoque principal está en el uso de subconsultas dentro de la cláusula WHERE para filtrar datos basándose en condiciones derivadas de otras tablas o de la misma tabla.

Aprenderá a conectarse a un servidor MySQL, crear una base de datos y tablas (clientes y pedidos), y luego a construir consultas SQL que utilicen subconsultas para identificar a los clientes que han realizado pedidos con un monto total que excede un valor específico. El laboratorio también cubre el uso de EXISTS con una subconsulta, la prueba de subconsultas correlacionadas y la comparación del rendimiento de las subconsultas.

Este es un Guided Lab, que proporciona instrucciones paso a paso para ayudarte a aprender y practicar. Sigue las instrucciones cuidadosamente para completar cada paso y obtener experiencia práctica. Los datos históricos muestran que este es un laboratorio de nivel principiante con una tasa de finalización del 89%. Ha recibido una tasa de reseñas positivas del 100% por parte de los estudiantes.

Escribir una Subconsulta en una Cláusula WHERE

En este paso, aprenderá a usar una subconsulta dentro de la cláusula WHERE de una sentencia SQL. Una subconsulta es una consulta anidada dentro de otra consulta. Es una herramienta poderosa para recuperar datos basándose en condiciones derivadas de otras tablas o de la misma tabla.

Comprendiendo las Subconsultas

Una subconsulta (o consulta interna) es una consulta SQL anidada dentro de una consulta más grande. La subconsulta se ejecuta primero y su resultado es utilizado por la consulta externa. Las subconsultas pueden aparecer en las cláusulas WHERE, SELECT, FROM y HAVING.

En la cláusula WHERE, una subconsulta se utiliza típicamente para filtrar los resultados de la consulta externa basándose en una condición. La subconsulta devuelve un único valor o un conjunto de valores que la consulta externa utiliza para la comparación.

Escenario

Imagine que tiene dos tablas: customers y orders. La tabla customers contiene información del cliente (por ejemplo, customer_id, name, city), y la tabla orders contiene información de los pedidos (por ejemplo, order_id, customer_id, order_date, total_amount).

Quiere encontrar todos los clientes que han realizado al menos un pedido con un monto total superior a $100.

Pasos

  1. Conectarse al Servidor MySQL:

    Abra su terminal y ejecute el siguiente comando para conectarse a su servidor MySQL como usuario root:

    sudo mysql -u root

    Debería ver el prompt de MySQL: mysql>.

  2. Crear la Base de Datos y las Tablas:

    Si aún no tiene una base de datos y tablas, créelas ahora. Creemos una base de datos llamada labdb y las tablas customers y orders. Ejecute los siguientes comandos SQL en el prompt de MySQL:

    CREATE DATABASE IF NOT EXISTS labdb;
    USE labdb;
    
    CREATE TABLE IF NOT EXISTS customers (
        customer_id INT PRIMARY KEY,
        name VARCHAR(255),
        city VARCHAR(255)
    );
    
    CREATE TABLE IF NOT EXISTS orders (
        order_id INT PRIMARY KEY AUTO_INCREMENT,
        customer_id INT,
        order_date DATE,
        total_amount DECIMAL(10, 2),
        FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
    );
  3. Insertar Datos de Ejemplo:

    Inserte algunos datos de ejemplo en las tablas. Ejecute los siguientes comandos SQL en el prompt de MySQL:

    INSERT INTO customers (customer_id, name, city) VALUES
    (1, 'Alice Smith', 'New York'),
    (2, 'Bob Johnson', 'Los Angeles'),
    (3, 'Charlie Brown', 'Chicago'),
    (4, 'David Lee', 'Houston');
    
    INSERT INTO orders (customer_id, order_date, total_amount) VALUES
    (1, '2023-01-15', 120.00),
    (2, '2023-02-20', 80.00),
    (1, '2023-03-10', 150.00),
    (3, '2023-04-05', 200.00),
    (2, '2023-05-12', 110.00),
    (4, '2023-06-18', 90.00);
  4. Escribir la Subconsulta en la Cláusula WHERE:

    Ahora, escriba la consulta para encontrar los clientes que han realizado pedidos con un monto total superior a $100. Ejecute el siguiente comando SQL en el prompt de MySQL:

    SELECT *
    FROM customers
    WHERE customer_id IN (SELECT customer_id FROM orders WHERE total_amount > 100);

    Explicación:

    • La subconsulta (SELECT customer_id FROM orders WHERE total_amount > 100) selecciona el customer_id de la tabla orders donde el total_amount es mayor que 100.
    • La consulta externa SELECT * FROM customers WHERE customer_id IN (...) selecciona todas las columnas de la tabla customers donde el customer_id está en el conjunto de customer_ids devueltos por la subconsulta.
  5. Observar la Salida:

    Debería ver la siguiente salida, mostrando los clientes que han realizado pedidos con un monto total superior a $100:

    +-------------+-------------+-----------+
    | customer_id | name        | city      |
    +-------------+-------------+-----------+
    |           1 | Alice Smith | New York  |
    |           2 | Bob Johnson | Los Angeles |
    |           3 | Charlie Brown | Chicago   |
    +-------------+-------------+-----------+
    3 rows in set (0.00 sec)

Usar EXISTS con una Subconsulta

En este paso, aprenderá a usar el operador EXISTS con una subconsulta en MySQL. El operador EXISTS se utiliza para verificar la existencia de filas en una subconsulta. Devuelve TRUE si la subconsulta devuelve alguna fila, y FALSE en caso contrario.

Comprendiendo EXISTS

El operador EXISTS se utiliza a menudo en la cláusula WHERE de una sentencia SQL para filtrar resultados basándose en la existencia de datos relacionados en otra tabla. Es una alternativa potente a usar operaciones IN o JOIN, y a veces puede ser más eficiente, especialmente al tratar con grandes conjuntos de datos.

A diferencia de IN, EXISTS no recupera realmente los datos de la subconsulta. Simplemente comprueba si se devuelven filas. Esto puede hacerlo más rápido que IN cuando solo necesita saber si existe una coincidencia, no los valores reales.

Escenario

Continuando con las tablas customers y orders del paso anterior, encontremos todos los clientes que han realizado al menos un pedido.

Prerrequisitos

Asegúrese de haber completado el paso anterior ("Escribir una Subconsulta en una Cláusula WHERE") y de tener la base de datos labdb, la tabla customers y la tabla orders pobladas con datos.

Pasos

  1. Escribir la Consulta usando EXISTS:

    Escriba la consulta para encontrar los clientes que han realizado al menos un pedido. Ejecute el siguiente comando SQL en el prompt de MySQL:

    SELECT *
    FROM customers c
    WHERE EXISTS (
        SELECT 1
        FROM orders o
        WHERE o.customer_id = c.customer_id
    );

    Explicación:

    • La consulta externa SELECT * FROM customers c selecciona todas las columnas de la tabla customers, con el alias c.
    • La cláusula WHERE EXISTS (...) comprueba si la subconsulta devuelve alguna fila.
    • La subconsulta SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id selecciona el valor 1 (podría ser cualquier valor constante) de la tabla orders, con el alias o, donde el customer_id en la tabla orders coincide con el customer_id en la tabla customers.
    • El operador EXISTS devuelve TRUE si la subconsulta devuelve al menos una fila, lo que indica que el cliente ha realizado al menos un pedido.
  2. Observar la Salida:

    Debería ver la siguiente salida, mostrando todos los clientes que han realizado al menos un pedido:

    +-------------+-------------+-----------+
    | customer_id | name        | city      |
    +-------------+-------------+-----------+
    |           1 | Alice Smith | New York  |
    |           2 | Bob Johnson | Los Angeles |
    |           3 | Charlie Brown | Chicago   |
    |           4 | David Lee   | Houston   |
    +-------------+-------------+-----------+
    4 rows in set (0.00 sec)
  3. Modificar la Consulta (Opcional):

    Modifiquemos la consulta para encontrar los clientes que no han realizado ningún pedido. Puede hacerlo utilizando NOT EXISTS. Ejecute el siguiente comando SQL en el prompt de MySQL:

    SELECT *
    FROM customers c
    WHERE NOT EXISTS (
        SELECT 1
        FROM orders o
        WHERE o.customer_id = c.customer_id
    );
  4. Observar la Salida:

    Dado que todos los clientes en nuestros datos de ejemplo han realizado pedidos, esta consulta debería devolver un conjunto de resultados vacío:

    Empty set (0.00 sec)

Probar una Subconsulta Correlacionada

En este paso, aprenderá sobre las subconsultas correlacionadas en MySQL. Una subconsulta correlacionada es una subconsulta que hace referencia a una columna de la consulta externa. Esto significa que la subconsulta se ejecuta una vez por cada fila de la consulta externa.

Comprendiendo las Subconsultas Correlacionadas

A diferencia de una subconsulta simple, que se ejecuta solo una vez, una subconsulta correlacionada depende de la consulta externa para sus valores. La subconsulta utiliza valores de la fila actual de la consulta externa para determinar su resultado. Esto hace que las subconsultas correlacionadas sean más potentes para ciertos tipos de consultas, pero también potencialmente menos eficientes que las subconsultas simples, especialmente para grandes conjuntos de datos.

Escenario

Continuando con las tablas customers y orders, encontremos todos los clientes que han realizado un pedido con un monto superior al monto promedio de todos los pedidos.

Prerrequisitos

Asegúrese de haber completado los pasos anteriores y de tener la base de datos labdb, la tabla customers y la tabla orders pobladas con datos.

Pasos

  1. Escribir la Subconsulta Correlacionada:

    Escriba la consulta para encontrar los clientes que han realizado un pedido con un monto superior al monto promedio. Ejecute el siguiente comando SQL en el prompt de MySQL:

    SELECT c.customer_id, c.name
    FROM customers c
    WHERE EXISTS (
        SELECT 1
        FROM orders o
        WHERE o.customer_id = c.customer_id
        AND o.total_amount > (SELECT AVG(total_amount) FROM orders)
    );

    Explicación:

    • La consulta externa SELECT c.customer_id, c.name FROM customers c selecciona el customer_id y el name de la tabla customers, con el alias c.
    • La cláusula WHERE EXISTS (...) comprueba si la subconsulta devuelve alguna fila.
    • La subconsulta correlacionada SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id AND o.total_amount > (SELECT AVG(total_amount) FROM orders) selecciona el valor 1 de la tabla orders, con el alias o, donde:
      • o.customer_id = c.customer_id: Esta es la correlación. La subconsulta hace referencia al customer_id de la tabla customers de la consulta externa.
      • o.total_amount > (SELECT AVG(total_amount) FROM orders): Esta condición comprueba si el monto del pedido es superior al monto promedio de todos los pedidos. La subconsulta AVG(total_amount) es una subconsulta no correlacionada que se ejecuta solo una vez para obtener el monto promedio del pedido.
  2. Observar la Salida:

    Debería ver la siguiente salida, mostrando los clientes que han realizado pedidos con un monto superior al monto promedio:

    +-------------+-------------+
    | customer_id | name        |
    +-------------+-------------+
    |           1 | Alice Smith |
    |           3 | Charlie Brown |
    +-------------+-------------+
    2 rows in set (0.00 sec)
  3. Otro Ejemplo: Encontrar el monto más alto de pedido para cada cliente

    Ejecute el siguiente comando SQL en el prompt de MySQL para recuperar el ID, nombre y el monto más alto de pedido de cada cliente. La subconsulta correlacionada calcula el monto máximo de pedido para cada cliente individualmente.

    SELECT c.customer_id, c.name, (
        SELECT MAX(o.total_amount)
        FROM orders o
        WHERE o.customer_id = c.customer_id
    ) AS highest_order_amount
    FROM customers c;
  4. Observar la Salida:

    Debería ver la siguiente salida:

    +-------------+-------------+-----------------------+
    | customer_id | name        | highest_order_amount  |
    +-------------+-------------+-----------------------+
    |           1 | Alice Smith |                150.00 |
    |           2 | Bob Johnson |                110.00 |
    |           3 | Charlie Brown |                200.00 |
    |           4 | David Lee   |                 90.00 |
    +-------------+-------------+-----------------------+
    4 rows in set (0.00 sec)

Comparar Rendimiento de Subconsultas

En este paso, aprenderá a comparar el rendimiento de diferentes tipos de subconsultas en MySQL. Comprender las características de rendimiento de las subconsultas es crucial para escribir consultas SQL eficientes, especialmente al tratar con grandes conjuntos de datos.

Consideraciones sobre el Rendimiento

El rendimiento de una subconsulta puede verse afectado por varios factores, entre ellos:

  • Tamaño de los Datos: El tamaño de las tablas involucradas en la consulta.
  • Tipo de Subconsulta: Si la subconsulta es correlacionada o no correlacionada.
  • Indexación: La presencia y efectividad de los índices en las tablas.
  • Versión de MySQL: La versión específica de MySQL que se está utilizando, ya que las técnicas de optimización de consultas pueden variar.

Escenario

Continuando con las tablas customers y orders, comparemos el rendimiento de una subconsulta que utiliza IN frente a una subconsulta que utiliza EXISTS para encontrar todos los clientes que han realizado al menos un pedido.

Prerrequisitos

Asegúrese de haber completado los pasos anteriores y de tener la base de datos labdb, la tabla customers y la tabla orders pobladas con datos. Para que la comparación de rendimiento sea más significativa, agregaremos más datos a la tabla orders.

Pasos

  1. Agregar Más Datos a la Tabla orders:

    Para que la comparación de rendimiento sea más realista, agreguemos una cantidad significativa de datos a la tabla orders. Insertaremos 1000 pedidos para cada cliente utilizando un procedimiento almacenado. Ejecute los siguientes comandos SQL en el prompt de MySQL:

    DELIMITER //
    CREATE PROCEDURE insert_many_orders()
    BEGIN
      DECLARE i INT DEFAULT 1;
      WHILE i <= 1000 DO
        INSERT INTO orders (customer_id, order_date, total_amount) VALUES (1, CURDATE(), 50.00);
        INSERT INTO orders (customer_id, order_date, total_amount) VALUES (2, CURDATE(), 75.00);
        INSERT INTO orders (customer_id, order_date, total_amount) VALUES (3, CURDATE(), 100.00);
        INSERT INTO orders (customer_id, order_date, total_amount) VALUES (4, CURDATE(), 125.00);
        SET i = i + 1;
      END WHILE;
    END//
    DELIMITER ;
    CALL insert_many_orders();
    DROP PROCEDURE insert_many_orders;

    Explicación:

    • Este script SQL crea un procedimiento almacenado llamado insert_many_orders.
    • El procedimiento inserta 1000 pedidos para cada uno de los cuatro clientes en la tabla orders.
    • Después de insertar los datos, el procedimiento se elimina.
  2. Consulta usando IN:

    Ejecute la siguiente consulta usando IN para encontrar todos los clientes que han realizado al menos un pedido:

    SELECT *
    FROM customers
    WHERE customer_id IN (SELECT customer_id FROM orders);
  3. Analizar el Plan de Ejecución de la Consulta usando EXPLAIN:

    Antes de ejecutar la consulta, utilice el comando EXPLAIN para analizar el plan de ejecución de la consulta. Esto le dará información sobre cómo MySQL planea ejecutar la consulta e identificará posibles cuellos de botella en el rendimiento. Ejecute el siguiente comando SQL en el prompt de MySQL:

    EXPLAIN SELECT *
    FROM customers
    WHERE customer_id IN (SELECT customer_id FROM orders);

    La salida de EXPLAIN le mostrará las tablas que se están accediendo, los índices que se están utilizando (si los hay) y el orden en que se realizan las operaciones. Preste atención a la columna type, que indica el tipo de join o método de acceso utilizado.

  4. Consulta usando EXISTS:

    Ejecute la siguiente consulta usando EXISTS para encontrar todos los clientes que han realizado al menos un pedido:

    SELECT *
    FROM customers c
    WHERE EXISTS (
        SELECT 1
        FROM orders o
        WHERE o.customer_id = c.customer_id
    );
  5. Analizar el Plan de Ejecución de la Consulta usando EXPLAIN:

    Utilice el comando EXPLAIN para analizar el plan de ejecución de la consulta EXISTS. Ejecute el siguiente comando SQL en el prompt de MySQL:

    EXPLAIN SELECT *
    FROM customers c
    WHERE EXISTS (
        SELECT 1
        FROM orders o
        WHERE o.customer_id = c.customer_id
    );

    Compare el plan de ejecución con el de la consulta IN. ¿Hay alguna diferencia en las tablas accedidas, los índices utilizados o los métodos de acceso?

  6. Observaciones:

    En general, EXISTS tiende a tener un mejor rendimiento que IN cuando la subconsulta devuelve un gran número de filas. Esto se debe a que IN necesita comparar los valores de la consulta externa con todos los valores devueltos por la subconsulta, mientras que EXISTS se detiene tan pronto como encuentra una coincidencia. Sin embargo, el rendimiento real puede variar dependiendo de la consulta específica, los datos y el sistema de base de datos. Puede utilizar la función BENCHMARK() (como se muestra en el documento original) para obtener una medición más precisa del tiempo de ejecución, pero para este laboratorio, analizar la salida de EXPLAIN proporciona información suficiente sobre los planes de consulta.

  7. Limpieza (Opcional):

    Si desea limpiar la base de datos y las tablas, puede ejecutar los siguientes comandos en el prompt de MySQL:

    DROP TABLE IF EXISTS orders;
    DROP TABLE IF EXISTS customers;
    DROP DATABASE IF EXISTS labdb;

    Cuando haya terminado todos los pasos, puede salir del cliente MySQL escribiendo:

    exit

Resumen

En este laboratorio, aprendió a utilizar subconsultas dentro de la cláusula WHERE de una sentencia SQL para filtrar datos basándose en condiciones derivadas de otras tablas o de la misma tabla. Practicó la conexión a un servidor MySQL, la creación de una base de datos y tablas, y la inserción de datos de ejemplo.

Exploró el uso del operador IN con una subconsulta para encontrar clientes basándose en datos relacionados en la tabla orders. También aprendió sobre el operador EXISTS como una alternativa a IN y practicó su uso para verificar la existencia de filas relacionadas.

Además, se le introdujeron las subconsultas correlacionadas, que hacen referencia a columnas de la consulta externa, y utilizó una para encontrar clientes con pedidos que superan el monto promedio del pedido. Finalmente, comparó el rendimiento de las subconsultas IN y EXISTS analizando sus planes de ejecución utilizando el comando EXPLAIN, obteniendo información sobre cómo MySQL procesa estas consultas.