10th Jan 2024 Lectura de 10 minutos ¿Se Pueden Utilizar Múltiples Sentencias WITH en SQL? Ignacio L. Bisso SQL aprender SQL WITH CTE expresiones comunes para las tablas Índice ¿Se Pueden Utilizar Múltiples Sentencias WITH en SQL? La cláusula WITH en SQL Uso de varias sentencias WITH en SQL Uso de Sentencias Múltiples y Anidadas WITH en SQL Uso de la Cláusula WITH para Crear Consultas recursivas y expresiones de tabla comunes Continúe Aprendiendo Acerca de las Sentencias Múltiples WITH en SQL Una completa guía sobre las sentencias WITH múltiples en SQL, perfecta tanto para principiantes como para expertos. La cláusula SQL WITH le permite definir una CTE (expresión común de tabla). Una CTE es como una tabla que se rellena durante la ejecución de la consulta. Puede utilizar varias sentencias WITH en una consulta SQL para definir varias CTE. En este artículo, explicaremos cómo definir múltiples CTEs en una sola consulta. También mostraremos cómo este enfoque lleva el poder expresivo de una consulta SQL al siguiente nivel. ¿Se Pueden Utilizar Múltiples Sentencias WITH en SQL? Sí, a continuación se muestra una consulta simple que utiliza dos cláusulas WITH: WITH wine_exporting_country AS ( SELECT country FROM product WHERE product_name = ‘wine’ AND qty_exported > 0 ), car_exporting_country AS ( SELECT country FROM product WHERE product_name = ‘car’ AND qty_exported > 0 ) SELECT country FROM wine_exporting_country INTERSECT car_exporting_country En la consulta anterior, hay dos CTEs. El primero (en rojo) se llama wine_exporting_country y el segundo (en azul) es car_exporting_country. La consulta principal (en negro) hace referencia a ambas sentencias WITH como tablas regulares utilizando INTERSECT. La intersección de las dos tablas devolverá sólo los países presentes en ambos resultados CTE. Observe que la palabra clave WITH sólo aparece una vez. Después de la cláusula WITH, debe poner el nombre del CTE, luego la palabra clave AS y finalmente entre paréntesis la consulta SELECT para definir el CTE. Si quieres aprender a utilizar varias sentencias WITH en una misma consulta, te recomiendo nuestro curso interactivo Consultas recursivas y expresiones de tabla comunes interactivo. Te enseña los detalles de la sintaxis de la cláusula WITH en más de 100 ejercicios prácticos. Cubre la sintaxis básica, múltiples sentencias WITH, y consultas recursivas - el uso más complejo de la sintaxis WITH. La cláusula WITH en SQL Expliquemos primero cómo funciona la cláusula WITH. Crea una especie de tabla virtual (la CTE) sobre la marcha, que se crea y rellena durante la ejecución de una única sentencia SQL; después de la ejecución SQL, la 'tabla' CTE se elimina automáticamente. Para una mejor comprensión de la cláusula WITH, sugiero el artículo ¿Qué es una CTE? En este artículo, utilizaremos una tabla de base de datos llamada product que realiza un seguimiento de los países y los productos más populares que producen (por ejemplo, aceite de oliva, vino, coches). Registra la cantidad producida, importada y exportada por cada país. La tabla también contiene el precio del producto y la población del país. countryproduct familyproduct nameqty_ producedqty_ importedqty_ exportedunitsUnit pricecountry_ population Francefoodwine18000000013000150000000liter3067000000 Francevehiclecar300000650004000000unit1000067000000 Germanyvehiclecar400000350002000000unit1000083000000 Germanyfoodwine3000000800001450000liter3083000000 Germanyfoodbeer40000000035000200000000liter483000000 Spainfoodwine3000000100002000000liter4047000000 Spainfoodolive oil3000000090000028000000liter2047000000 Finlandtechnologysmartphone3000000500002500000dollar2005500000 Greecefoodolive oil1000000200000800000liter1810000000 Veamos un ejemplo sencillo de consulta que utiliza una cláusula WITH para definir un CTE. Supongamos que queremos obtener una lista de los países que exportan más aceite de oliva del que importan. Queremos los resultados ordenados por la cantidad producida por cada país. Esta es la consulta: WITH olive_oil_exporter AS ( SELECT country, qty_produced FROM product WHERE product_name = ‘olive oil’ AND qty_exported > qty_imported ) SELECT country FROM olive_oil_exporter ORDER BY qty_produced DESC; En esta consulta, tenemos un CTE llamado olive_oil_exporter, que es como una tabla con dos columnas: country y qty_produced. Las filas del CTE sólo contienen los países que exportan más aceite de oliva del que importan. A continuación, utilizamos una sentencia regular SELECT para consultar el CTE olive_oil_exporter en busca de los nombres de los países, que ordenamos de forma descendente según la cantidad de aceite de oliva producida en ese país. Uso de varias sentencias WITH en SQL Supongamos que queremos clasificar los países en países productores de alimentos y países productores de tecnología. Para ser productor de alimentos, un país debe exportar más de 100 millones de dólares en productos alimenticios. Para ser productor de alta tecnología, un país debe producir más de 1.000 dólares en productos tecnológicos por habitante. Queremos un informe con los nombres de todos los países y dos columnas llamadas is_a_food_producer y is_a_hightech_producer. La consulta SQL para este informe es WITH food_producer AS ( SELECT country FROM products WHERE product_family = ‘food’ GROUP BY country HAVING SUM( qty_exported * unit_price) > 100000000 ) hightech_producer AS ( SELECT country FROM products WHERE product_family = ‘technology’ GROUP BY country HAVING SUM( qty_produced / country_population) > 1000 ) SELECT DISTINCT p.country, CASE WHEN fp.country IS NULL THEN ‘No’ ELSE ‘Yes’ END AS is_a_food_produced, CASE WHEN htp.country IS NULL THEN ‘No’ ELSE ‘Yes’ END AS is_a_hightech_produced, FROM products p LEFT JOIN food_producer fp ON fp.country = p.country LEFT JOIN hightech_producer htp ON htp.country = p.country En la consulta anterior, podemos identificar claramente tres consultas separadas. Las dos primeras utilizan la cláusula WITH para definir dos tablas CTE: food_producer y hightech_producer. La tercera consulta es la consulta principal, que consume las dos tablas CTE creadas anteriormente. Después de la cláusula WITH, se puede ver el nombre de la tabla CTE (food_producer), luego la subcláusula AS y finalmente (entre paréntesis) la consulta para ese CTE. Para el segundo CTE, la cláusula WITH no es necesaria; basta con poner una coma, y luego repetir la misma sintaxis empezando por el nombre del CTE. Los dos CTE food_producer y hightech_producer sólo tienen una columna: country. La consulta principal toma los nombres de todos los países de la tabla producty, a continuación, se realiza una LEFT JOIN con cada uno de los CTE. Cuando el LEFT JOIN no tiene una fila coincidente, significa que la respuesta para este país es "No"; cuando hay una fila coincidente, el valor para este país es "Sí". Antes de pasar a la siguiente sección, me gustaría sugerirte el artículo Cómo escribir múltiples CTEs. En él puedes encontrar muchos ejemplos y explicaciones sobre CTEs. Uso de Sentencias Múltiples y Anidadas WITH en SQL En algunos casos, necesitamos una segunda CTE basada en la primera CTE: una CTE anidada. En otras palabras, la consulta para definir la segunda CTE debe tener una referencia a la primera CTE. Veamos un ejemplo. Queremos obtener el importe total en dólares exportado por países en productos alimenticios. En el mismo informe, queremos mostrar el porcentaje que representa este importe en el total de exportaciones de ese país para todo tipo de productos. La consulta es: WITH country_export_by_product AS ( SELECT country, product_family, SUM(qty_exported * unit_price) AS total_exports FROM product GROUP BY country, product_family ), country_export_total AS ( SELECT country, SUM(total_exports) AS total_exports_country FROM country_export_by_product GROUP BY country ) SELECT cp.country, product_family, cp.total_exports_food , ROUND((cp.total_exports_food / ct.total_exports_country) * 100, 2) AS percentage_of_total_exports FROM country_export_by_product cp JOIN country_export_total ct ON ct.country = cp.country ORDER BY country, product_family; En esta consulta, creamos un CTE llamado country_export_by_product que tiene las columnas country, product_family y total_exports (que representa el importe total de este producto exportado por este país (en dólares)). Observe que la cláusula GROUP BY utiliza las columnas country y product_family. El siguiente CTE se llama country_export_total y se basa en el CTE anterior country_export_by_product. La idea de este CTE es obtener la cantidad total exportada por cada país basándose en el CTE anterior. Obsérvese que en el segundo CTE utilizamos una cláusula de país GROUP BY. La necesidad de distintos niveles de la cláusula GROUP BY es la razón por la que tenemos dos CTE. La consulta principal hace referencia a ambos CTE, uniéndolos por el valor del país. A continuación, la expresión TRUNC((cp.total_exports_food / ct.total_exports_country) * 100, 2) ... se utiliza para calcular el porcentaje que representa cada producto en las exportaciones totales de ese país. En términos de sintaxis, puede hacer que un CTE haga referencia a otro CTE en la misma consulta. Esto es lo que hemos hecho en nuestra consulta: al definir el CTE country_export_total, hemos hecho referencia al CTE country_export_by_product definido anteriormente. Observe que podemos hacer referencia a la sentencia WITH definida antes de la sentencia WITH actual, pero no a las posteriores. Puede hacer referencia a cada sentencia WITH varias veces en otra sentencia WITH o en una consulta principal. En nuestro ejemplo, hemos hecho referencia a la primera sentencia WITH definida (la sentencia country_export_by_product CTE) en dos lugares: En el segundo WITH (el CTE country_export_total ) y en la consulta principal. Otras limitaciones relacionadas con la sintaxis de la cláusula WITH son: Debe utilizar la palabra clave WITH sólo una vez, antes de la primera CTE. Todos los CTEs están separados por comas, pero no hay coma antes de la consulta principal. Esto sigue el patrón sintáctico: WITH cte_name1 AS (query1), cte_name2 AS (query2) main_query Sugiero el artículo Explicación de las CTEs de SQL con ejemplos para varios ejemplos más de consultas WITH; demuestran cómo mejorar la organización y legibilidad de sus consultas SQL utilizando CTEs. Uso de la Cláusula WITH para Crear Consultas recursivas y expresiones de tabla comunes La cláusula WITH se utiliza en SQL para definir consultas recursivas. Las consultas recursivas le ayudan a consultar estructuras jerárquicas (por ejemplo, organigramas, árboles o gráficos). Puede obtener más información sobre la consulta de estructuras jerárquicas aquí. Las consultas recursivas se basan en la cláusula WITH. Para crear una consulta recursiva, sólo necesita una cláusula WITH, pero la consulta dentro de WITH consta de dos partes. Las consultas recursivas son útiles cuando las tablas o el modelo de datos de la base de datos tienen una especie de jerarquía implícita. Quizá la tabla de ejemplo más común para explicar este tema sea la típica tabla employee con las columnas employee_id y manager_employee_id. Si queremos que un informe muestre todos los empleados con los nombres de sus jefes y el nivel jerárquico del empleado, podemos utilizar la siguiente consulta recursiva: WITH RECURSIVE company_hierarchy AS ( SELECT employee_id, firstname, lastname, manager_employee_id, 0 AS hierarchy_level FROM employees WHERE manager_employee_id IS NULL UNION ALL SELECT e.employee_id, e.firstname, e.lastname, e.manager_employee_id, hierarchy_level + 1 FROM employees e, company_hierarchy ch WHERE e.manager_employee_id = ch.employee_id ) SELECT ch.firstname AS employee_first_name, ch.lastname AS employee_last_name, e.firstname AS boss_first_name, e.lastname AS boss_last_name, hierarchy_level FROM company_hierarchy ch LEFT JOIN employees e ON ch.manager_employee_id = e.employee_id ORDER BY ch.hierarchy_level, ch.manager_employee_id; En esta consulta, podemos ver la cláusula WITH RECURSIVE, que se utiliza para crear un CTE recursivo llamado company_hierarchy. El CTE tendrá todos los nombres de los empleados con los nombres de sus gerentes. Observe que el CTE tiene dos sentencias SELECT conectadas por UNION ALL. La primera SELECT es para obtener el primer empleado en la consulta recursiva (CEO John Smith). La segunda SELECT de UNION es una consulta que se ejecuta varias veces. En cada ejecución, devuelve el empleado o empleados del siguiente nivel en la jerarquía. Por ejemplo, su primera ejecución devuelve todos los empleados que dependen directamente de John Smith. Por último, hay una tercera sentencia SELECT; está fuera del CTE. Selecciona los nombres de los empleados, los nombres de sus jefes y el nivel jerárquico. Los datos se toman del CTE y se unen con la tabla employees. Utilizamos LEFT JOIN porque queremos todos los datos del CTE (incluido John Smith, que tiene un valor NULL en la columna manager_id). Los resultados se muestran en orden ascendente: primero por el nivel jerárquico, luego por el del jefe employee_id. A continuación se muestra el resultado de la consulta: employee_first_nameemployee_last_nameboss_first_nameboss_last_namehierarchy_level JohnSmithNULLNULL1 MaryDoeJohnSmith2 PeterGraueMaryDoe3 TomDorinMaryDoe4 Para obtener más información sobre las consultas recursivas, consulte el artículo ¿Qué es una CTE recursiva en SQL? Continúe Aprendiendo Acerca de las Sentencias Múltiples WITH en SQL En este artículo, cubrimos el uso de múltiples sentencias WITH en una sola consulta SQL. También mencionamos como utilizar la cláusula WITH en consultas recursivas. Si desea continuar aprendiendo sobre la cláusula WITH, le recomiendo nuestro curso Consultas recursivas y expresiones de tabla comunes curso, que ofrece una excelente oportunidad para practicar el tipo más desafiante de consultas SQL. Las sentencias WITH múltiples son más útiles cuando se escriben informes SQL complejos. Si ése es tu caso, también te recomiendo nuestra hoja gratuita SQL for Data Analysis Cheat Sheet, que hemos diseñado específicamente para ayudarte a escribir consultas complejas para el análisis de datos. Si quieres practicar SQL a un nivel avanzado, echa un vistazo a nuestra pista de prácticas SQL avanzado. Contiene más de 200 ejercicios que le ayudarán a practicar conceptos avanzados de SQL. Cada dos meses, publicamos un nuevo curso práctico de SQL avanzado en nuestra pista mensual Ejercicio de SQL. También puede obtener todos estos cursos y más en nuestro Todo, para siempre plan. El plan te da acceso de por vida a todos nuestros cursos de SQL en varios niveles de competencia y en cuatro dialectos de SQL. Inscríbase hoy mismo. Tags: SQL aprender SQL WITH CTE expresiones comunes para las tablas