Tablas Recursivas e Interactivas en SQL con Common Table Expressions
Resumen
¿Qué son las Common Table Expressions (CTEs) en PostgreSQL?
Las Common Table Expressions (CTEs) en PostgreSQL son una herramienta poderosa que permite ejecutar consultas más eficientes y optimizadas. Estas expresiones se utilizan para ahorrar memoria al permitir que las tablas se expresen de manera más compacta. Además, ofrecen una forma más interactiva de ejecutar procesos que el SQL estándar no permite.
¿Cuáles son las ventajas de usar CTEs?
Las CTEs proporcionan varias ventajas significativas que mejoran la eficiencia y la capacidad de las consultas SQL:
Reducción del uso de memoria: Las CTEs ayudan a evitar las anidaciones complejas en las consultas, que a menudo consumen muchos recursos del servidor.
Procesos interactivos: Permiten realizar procesos interactivos, algo que el SQL estándar no puede hacer de forma nativa.
Compatibilidad con estructuras de control: Aunque SQL está diseñado principalmente para consultar datos, las CTEs permiten integrar estructuras de control y otros procesos interactivos.
Facilidad en la modificación de datos: Ayudan a iterar y modificar datos en tablas de una manera organizada, lo cual es útil en operaciones complejas como la actualización de registros específicos.
¿Cómo crear y usar una CTE recursiva en PostgreSQL?
Para crear una CTE recursiva en PostgreSQL, se utiliza la palabra clave WITH RECURSIVE. Esta técnica permite definir una tabla que se alimenta de sí misma durante su ejecución, lo cual habilita procesos iterativos y recursivos.
Pasos para implementar una CTE recursiva
Definición de la CTE:
Al definir una CTE recursiva, se inicia con la palabra WITH RECURSIVE y se define el nombre de la tabla recursiva que se desea generar, junto con los parámetros que va a utilizar.
WITH RECURSIVE tabla_recursiva AS(SELECT1AS n
UNIONALLSELECT n +1FROM tabla_recursiva
WHERE n <100)
Declaración del valor inicial y proceso recursivo:
La CTE inicia con un valor base, en este caso SELECT 1 AS n.
Luego se realiza un UNION ALL para ir sumando 1 en cada iteración y continuar hasta que se cumpla la condición n < 100.
Ejecución de la consulta final:
Finalmente, puedes ejecutar una consulta sobre la CTE creada para hacer operaciones adicionales, como sumar los valores.
SELECTSUM(n)FROM tabla_recursiva;
Aplicaciones prácticas de las CTEs recursivas
Este tipo de expresión es útil cuando se necesita procesar datos de manera iterativa dentro de una tabla. Algunos ejemplos de uso son:
Migración de datos: Al extraer datos de una tabla y transformarlos para insertarlos en otra.
Corrección de errores en datos: Para modificar registros específicos de manera automática, basándose en ciertas condiciones lógicas dentro de la CTE.
Generación de secuencias de datos: Facilita la creación de secuencias numéricas o la agregación de valores de manera recursiva.
¿Por qué elegir PostgreSQL para trabajar con CTEs?
PostgreSQL se destaca por sus amplias capacidades para manejar CTEs, lo cual lo convierte en una excelente elección para desarrollar consultas interactivas y optimizadas:
Soporte robusto: PostgreSQL ofrece un entorno robusto para crear, gestionar y ejecutar CTEs tanto simples como recursivas.
Versatilidad y flexibilidad: Los desarrolladores pueden realizar operaciones complejas que no se pueden ejecutar con consultas SQL tradicionales.
Eficiencia en la gestión de recursos: Al reducir el uso de memoria y las operaciones complejas en el servidor, PostgreSQL permite mantener un sistema eficiente y ágil.
Siempre es importante continuar profundizando en las herramientas y funcionalidades que PostgreSQL ofrece para sacar el máximo provecho en la gestión de bases de datos. ¡Sigue explorando este poderoso entorno y descubre todo lo que puedes lograr!
Básicamente son estructuras de contro en PosgreSQL. En este caso el profesor solo hizo un bucle y retornó un número, pero podría haber ejecutado algo más interesante como una serie de Updates u otra cosa.
.
A veces, cuando estás programando, te puede pasar que tengas que hacer un bucle en Python, PHP, JS o el lenguajes que estés usando (a partir de ahora diré Python para simplificar) y que dentro del bucle tengas que ejecutar una sentencia SQL. Realizar cálculos en Python y volver a insertar datos. En estos casos, en cada vuelta del loop Python tendrá que llamar internamente al conector que le permite leer la base de datos, luego realizará los cálculos y conectará otra vez para con la DB para insertar el valor final.
Bueno, en estos casos puedes hacer uso de las Common Table Expressions para hacer to loop directamente en PostgreSQL, realizar tus calculos y volver a insertar sin tener que llamar al conector en cada itineración. Ahorrarás tiempos, recursos, dinero, la aplicación será más rápida y te darán un ascenso... bueno... puede que lo último no pase solo por eso, pero si lo sabes vender impresiones puede que impresiones a algo y te ayude a conseguirlo en el largo plazo.
Para saber más: Leer la documentación oficial
Buena explicación creo que le dedicare la tarde a ahondar en el tema gracias Kenny
Me tome una tarde para leer y tratar de entender esta clase, les dejo el tutorial que hice, espero les sirva, el feedback es bien recibido
Dejo el codigo que en el tutorial explico a detalle
-- tabla temporal 1WITH peliculas_rentadas AS(SELECT pelicula_id,COUNT(fecha_renta)AS rentas_acumuladas
FROM inventarios
JOIN rentas
ON inventarios.inventario_id= rentas.inventario_idGROUPBY inventarios.pelicula_idORDERBY rentas_acumuladas DESC),-- tabla temporal 2peliculas_categoria_horror AS(SELECT pelicula_id, nombre
FROM peliculas_categorias
JOIN categorias
ON peliculas_categorias.categoria_id= categorias.categoria_idWHERE categorias.nombre='Horror')SELECT peliculas.titulo, peliculas.clasificacion, peliculas_categoria_horror.nombreAS genero, peliculas_rentadas.rentas_acumuladasAS rentas_acumuladas, precio_renta *(peliculas_rentadas.rentas_acumuladas)AS monto_rentas_acumulado
FROM peliculas
JOIN peliculas_categoria_horror
ON peliculas.pelicula_id= peliculas_categoria_horror.pelicula_idJOIN peliculas_rentadas
ON peliculas.pelicula_id= peliculas_rentadas.pelicula_idWHERE peliculas.duracion>100 and peliculas.precio_renta<1;
Esta herramienta es poderosísima y el tutorial de @rusbelBermudez está muy bien explicado. Lo entendí mejor con su tutorial y su real aplicación al caso del proyecto.
Me tomé el tiempo para entenderlo e interpretarlo con mis propias palabras. Les comparto...
Interpretación del tutorial
Lo que hace las CTE es crear tablas de consulta virtuales/temporales (sin output de datos) equivalentes a los campos que solicita el Query principal.
Luego, con un SELECT externo al WITH, se hace el llamado para unir los SELECT dentro del WITH y así visualizar la consulta solicitada principalmente. Para el ejemplo, era la solicitud “las películas de genero Horror mas rentadas con un precio de renta mayor a $1 y con mas de 100 minutos de duración”
Donde podemos resumir que se requieren los siguientes datos:
Conteo de rentas total (rentas_acumuladas)
Agrupación por película
Filtro 1 por categoría “Horror” (genero)
Filtro 2 duración mayor a 100 minutos
Filtro 3 precio de renta mayor a $1
Entonces, al iniciar con la sentencia WITH se da creación a las tablas temporales; tantas como campos solicite el Query principal y que se puedan consolidar en una consulta con JOIN simples.
**--DECLARACIÓN DE LA CTE CON *WITH*--**WITH**--PRIMERA TABLA TEMPORAL--**peliculas_rentadas AS(SELECT pelicula_id,COUNT(fecha_renta)AS rentas_acumuladas
FROM inventarios
JOIN rentas
ON inventarios.inventario_id = rentas.inventario_id
GROUPBY inventarios.pelicula_id
ORDERBY rentas_acumuladas DESC),
Esta primera expresión, responde al apartado ‘conteo de rentas total’ o ‘rentas_acumuladas’ y por consiguiente a la respectiva ‘agrupación por película’. Luego continúa la segunda tabla temporal, igualmente dentro de la sentencia WITH.
**--SEGUNDA TABLA TEMPORAL--**peliculas_categoria_horror AS(SELECT pelicula_id, nombre
FROM peliculas_categorias
JOIN categorias
ON peliculas_categorias.categoria_id = categorias.categoria_id
WHERE categorias.nombre ='Horror')
La segunda expresión del WITH llamada ‘peliculas_categoria_horror’ responde al filtro 1, el cual solo desea ver las películas de la categoría/genero ‘Horror’. Seguido a esto se cierra la sentencia WITH para este CTE con paréntesis y se inicia la consulta externa.
**--CONSULTA EXTERNA PARA VISUALIZAR RESULTADOS--**SELECT peliculas.titulo, peliculas_categoria_horror.nombre AS genero, peliculas_rentadas.rentas_acumuladas AS rentas_acumuladas, precio_renta *(peliculas_rentadas.rentas_acumuladas)AS monto_rentas_acumulado
FROM peliculas
JOIN peliculas_categoria_horror
ON peliculas.pelicula_id = peliculas_categoria_horror.pelicula_id
JOIN peliculas_rentadas
ON peliculas.pelicula_id = peliculas_rentadas.pelicula_id
En esta parte del Query, simplemente se hace un SELECT que llama los campos generados en las tablas temporales. Además, se hacen JOIN para relacionarlos y traer también los nombres de las películas en vez de solamente el ID de cada una de ellas.
**--FILTROS 2 Y 3 DE LA CONSULTA EXTERNA--**WHERE peliculas.duracion >100and peliculas.precio_renta <1;
Finalmente se aplican los filtros 2 y 3 que al ser dependientes de la tabla ‘películas’, la cual se relacionó en la consulta externa anterior, se escriben solamente al final de esta.
Wao, super bien explicado, sobre todo el hacer las comparaciones entre los temas ya vistos.. Ademas que aclaras la impotancia de utilizar las CTE’s de cuando tenemos muchos datos
Falto explicar un poco mejor este tema
Así es, creo que el ejemplo elegido fue desafortunado. Los CTE se ocupan mas para simplificar consultas complejas con varios JOINs o con consultas anidadas
Sí me quedaron muchas dudas...
No entendí por que daba 5050 al final, pero indagando un poco es la suma recursiva de todos los números hasta el 100
Traducido a Python sería algo así:
suma =0for i inrange(101): suma = suma + i
Dejó el aporte por si alguien tuvo la misma duda.
Hola amigo! Creo que si usamos funciones recursivas sería algo así:
def sumar(i):if i <1:return0else:return i +sumar(i-1)print(sumar(100))
Así es, es la suma recursiva de los números 1 hasta el 100, otra forma de verlo sencillo, es sumando el numero mayor con el menor sucesivamente algo como: 100+1=101, 99+2=101, 98+3=101, y así sucesivamente y te vas a dar cuenta que con esas sumas se repite 101 50 veces, por lo tanto quedaría 101x50=5050... y como sabemos que se multiplica por 50?, simplemente viendo que el 100 es numero par, y si lo dividimos entre 2, da 50, eso quiere decir que se van hacer 50 pares de sumas de 101, que es lo que hicimos arriba (100+1)(100/2)=5050
Bueno este tema es algo más denso, creo que sería ideal usar un par de ejemplos adicionales para comprender mejor el tema, más sin embargo sintetizando lo que comenta Isra en esta clase:
Es una herramienta que usa expresiones de tablas para agilizar en postgres cálculos en casos de uso específicos.
Ofrecen una mayor aplicabilidad a casos de usos iterantes, casos en los cuales su estructura bajo lenguaje SQL es dispendiosa tanto en su construcción como su ejecución para el servidor.
Es necesario ahondar más en este tema ya que su versatilidad es interesante.
utilizar PostgreSQL CTE (expresiones de tabla comunes) para simplificar consultas complejas.
Introducción a las expresiones de tabla comunes de PostgreSQL o CTE
Una expresión de tabla común es un conjunto de resultados temporal que se puede hacer referencia en otro comando SQL incluyendo SELECT, INSERT, UPDATEo DELETE.
Las expresiones de tabla comunes son temporales en el sentido de que solo existen durante la ejecución de la consulta.
A continuación, se muestra la sintaxis de la creación de un CTE:
WITH cte_name (column_list) AS (
CTE_query_definition
)
statement;
En esta sintaxis:
Primero, especifique el nombre del CTE seguido de una lista de columnas opcional.
En segundo lugar, dentro del cuerpo de la WITHcláusula, especifique una consulta que devuelva un conjunto de resultados. Si no especifica explícitamente la lista de columnas después del nombre de CTE, la lista de selección de CTE_query_definitionse convertirá en la lista de columnas de CTE.
En tercer lugar, utilizar el CTE como una tabla o vista en la statementque puede ser una SELECT, INSERT, UPDATE, o DELETE.
Las expresiones de tabla comunes o CTE se utilizan normalmente para simplificar uniones y subconsultas complejas en PostgreSQL.
Podrian explicarme un poco mas para q usamos un Common table expression??
Las Common table expression pueden usar para simplificar el código, con ellas puede crear tablas temporales de un query determinado y luego poder hacer un query sobre el resultado final.
por ejemplo generar una tabla resumen y luego hacer un query de esa tabla, de esta forma puede evitar hacer sub-queries o queries anidados que son difíciles de leer.
en la clase se enseño solo una version de las common tables expressions "recursiva", que hace exactamente lo mismo que lo que dije anteriormente pero en lugar de crear varias tablas temporales, usa los resultados de ella misma hasta que tenga una condición de parada.
A mi me gustando mucho las clases con Israel pero creo que este curso se debió haber dividido en 2, hay muchos temas que se abordan muy por encima y sin buenas bases
Miren, tampoco entendí muy bien xD, pero estuve leyendo comentarios, foros y vi unos videos y puedo simplificar a que:
Common Table Expressions (CTE) / Expresión de Tabla Común:
Son creadas en tiempo de ejecución.
Es necesario asignarle un nombre (AS).
Tienen una consulta interna.
Hay una consulta externa que hace uso de la consulta interna.
Algo a considerar es que las CTE permiten simplificar queries bastante complejas pero sobre todo permiten cargar en memoria subsets de registros lo cual aumenta la optimización y rendimiento del query final.
Para los que no Entendieron
Las Common Table Expressions (CTEs) son una característica de SQL que permite definir una consulta nombrada dentro de otra consulta. Esto proporciona una forma de modularizar y reutilizar partes de una consulta SQL, lo que puede hacer que las consultas sean más legibles y mantenibles.
Aquí tienes ejemplos de CTEs en niveles básico, intermedio y avanzado:
## Nivel Básico
En este ejemplo, utilizaremos una CTE para calcular la suma de los primeros 10 números naturales:
WITH numeros AS(SELECTgenerate_series(1,10)AS numero
)SELECTSUM(numero)AS suma_total
FROM numeros;
En este caso, la CTE llamada numeros genera una serie de números del 1 al 10. Luego, fuera de la CTE, realizamos una consulta que suma todos los números generados.
## Nivel Intermedio
En este ejemplo, utilizaremos una CTE para encontrar los empleados que ganan más que el salario promedio en una tabla de empleados:
WITH salario_promedio AS(SELECTAVG(salario)AS salario_promedio
FROM empleados
)SELECT nombre, salario
FROM empleados
WHERE salario >(SELECT salario_promedio FROM salario_promedio);
Aquí, la CTE salario_promedio calcula el salario promedio de todos los empleados. Luego, la consulta principal selecciona los empleados cuyos salarios son mayores que el salario promedio calculado en la CTE.
## Nivel Avanzado
En este ejemplo, utilizaremos múltiples CTEs y combinaremos los resultados utilizando una consulta final:
WITH cte_ventas AS(SELECT producto_id,SUM(monto)AS total_ventas
FROM ventas
GROUPBY producto_id
), cte_productos_mas_vendidos AS(SELECT producto_id
FROM cte_ventas
WHERE total_ventas >1000)SELECT p.nombre, v.total_ventasFROM cte_productos_mas_vendidos c
JOIN cte_ventas v ON c.producto_id= v.producto_idJOIN productos p ON p.id= v.producto_id;
En este ejemplo, la primera CTE (cte_ventas) calcula el total de ventas para cada producto. Luego, la segunda CTE (cte_productos_mas_vendidos) selecciona los productos que tienen ventas totales superiores a 1000. Finalmente, la consulta principal une las CTEs y selecciona el nombre del producto y el total de ventas para cada producto que cumple con el criterio especificado.
Wow, es super satisfactorio cuando despues del miedo a fallar e intentos logras dar con un query, comparto la forma en la que utilize las common table expressions para hallar las pelis con mayor duracion en su renta:
WITH pelis_mas_rentadas as(SELECTMAX(duracion_renta)as duracion_renta, pelicula_id as pelicula_identificador
from peliculas
group by pelicula_identificador
),pelis_generos_populares as(SELECT categorias.categoria_id, categorias.nombreas categoria_nombre
from categorias
)SELECT*FROM pelis_generos_populares JOIN peliculas_categorias
ON pelis_generos_populares.categoria_id= peliculas_categorias.categoria_idJOIN pelis_mas_rentadas
ON pelis_mas_rentadas.pelicula_identificador= peliculas_categorias.pelicula_id order by pelis_mas_rentadas.duracion_renta desc;
las common table expressions son muy parecidas a lo que se conoce como Tally Tables en SQL Server, son muy utiles también cuando quieres por ejemplo ir sumando un dia consecutivo a una fecha inicial.
Siento los CTE como una mezcla entre un for y las funciones recursivas, pensando muy programáticamente :D . Pero tienen un gran potencial.
Yo ya las usaba pero no sabia que hacian un ahorro de memoria, yo lo utilizaba porque era mas simple de leer o porque eran como tu dices, funciones jajaja
No esta tan clara esta clase desde mi punto de vista.
¿Cómo o dónde puedo guardar estas expresiones para efectivamente utilizarlas como control? Saludos.
Este tipo de consultas son más veloces que las queries tradicionales?
Como ejemplo de como funciona la recursividad en PostgreSQL utilizando las Common Table Expression esta bien, sin embargo a la clase le hizo falta un ejemplo real del uso de ésta funcionalidad, el curso nos dio una base de datos a la que le podemos sacar mucho provecho y hubiera estado mucho mejor uno o más ejemplo de las CTE utilizando queries sobre la BBDD platzimovies.
Es compleja estas expresiones creo que falto un ejemplo mas aplicado al proyecto.
Básicamente lo que hace trabajar con una tabla recursiva sin necesidad de utilizar una que puede ocupar memoria o mas trabajo en el disco como explico el profesor es por eso que cuando hace la unión tiene una tabla nueva lo pudo haber hecho con las que tenemos pero lo que quiso mostrar es ver que se puede trabajar con valores iterativos. confunde un poco pero denle su tiempo y ordenen el código y entiendan como funciona.