Así como podemos consultar filas de forma recursiva, también podemos actualizar esas filas recursivamente si es lo que necesitamos.
Veamos un caso:
Tenemos una tabla llamada CUENTAS que tiene estos datos:
Captura 1. Si haces clic en la imagen la verás más grande
En la columna CUE_IDENTI guardamos el identificador de cada fila; en la columna CUE_IDEPAD guardamos el identificador de su fila padre; en la columna CUE_TIMEST guardamos la fecha y la hora de la última actualización de una cuenta. Ahora supongamos que queremos que la cuenta CRÉDITOS y todas las cuentas que sean sus descendientes tengan la fecha y la hora actuales.
Listado 1.
UPDATE CUENTAS SET CUE_TIMEST = CURRENT_TIMESTAMP WHERE CUE_IDENTI IN ( WITH RECURSIVE MiCTE AS ( SELECT CUE_IDENTI FROM CUENTAS WHERE CUE_IDENTI = 6 UNION ALL SELECT T1.CUE_IDENTI FROM CUENTAS T1 JOIN MiCTE ON T1.CUE_IDEPAD = MiCTE.CUE_IDENTI ) SELECT CUE_IDENTI FROM MiCTE );
Captura 2. Si haces clic en la imagen la verás más grande
Tal y como podemos ver en la Captura 2. se actualizó la columna CUE_TIMEST de la cuenta que tiene CUE_IDENTI =6 y también de todos sus descendientes. En el Listado 1. podemos ver que la primera cuenta a ser actualizada es la que tiene CUE_IDENTI = 6, a continuación se actualizan las demás filas.
Desde luego que no solamente podemos cambiar la fecha y la hora al actualizar, podemos cambiar cualquier dato que necesitemos.
Explicación:
Como en la cláusula WHERE del UPDATE estamos usando IN eso significa que queremos actualizar varias filas. ¿Qué filas actualizaremos? Aquellas cuya columna CUE_IDENTI se encuentre en la tabla virtual que crearemos. En nuestra tabla virtual la primera fila es la que tiene CUE_IDENTI = 6, así que esa fila sí o sí será actualizada. A continuación hallamos el CUE_IDENTI de las demás filas que queremos actualizar. Como la tabla virtual es recursiva entonces se le irán agregando filas hasta que la condición del JOIN deje de cumplirse. El último SELECT es el que devuelve todas las filas de la tabla virtual, y todas esas filas tienen una sola columna, llamada CUE_IDENTI.
Entonces, nuestro UPDATE recursivo sería el equivalente a este UPDATE no recursivo.
Listado 2.
UPDATE CUENTAS SET CUE_TIMEST = CURRENT_TIMESTAMP WHERE CUE_IDENTI IN (6, 7, 8, 9, 10)
¿Cuál es la diferencia? Que en el Listado 2. debemos conocer todos los identificadores que deseamos actualizar, en cambio en el Listado 1., no. Allí solamente necesitamos conocer el identificador de la primera cuenta, nada más. Todas las cuentas que sean sus descendientes serán actualizadas, sean 4 como en este caso o sean 500 o sean 1000. La única limitación es que pueden ser como máximo 1024 porque el Firebird permite hasta 1024 recursiones.
El Listado 2. es más sencillo, pero requiere conocer los identificadores de todas las cuentas que queremos actualizar y si los usuarios están constantemente agregando cuentas tendremos que estar cambiando nuestro UPDATE a cada rato. Por el contrario con el Listado 1. lo único que debemos conocer es el identificador de la primera cuenta que deseamos actualizar y todas las cuentas que sean sus descendientes se actualizarán también.
Artículos relacionados:
Entendiendo a las tablas autoreferenciadas
Usando CTE (Common Table Expression)
Otro ejemplo de CTE: ventas semanales
Usando varias CTE en una vista o en un stored procedure
Ejemplo de recursión (1). Filas salteadas
Ejemplo de recursión (2). Numerar filas
Ejemplo de recursión (3). Fechas consecutivas
Comentarios recientes