Cuando deseamos tener un SELECT que nos muestre sumas acumuladas hay varias formas de conseguir nuestro objetivo. Lo más sencillo es escribir un stored procedure que recorra la tabla ordenadamente y que en una variable vaya guardando la suma acumulada. Otra alternativa es usando recursión, tal como hemos visto en el artículo:

https://firebird21.wordpress.com/2015/08/31/ejemplo-de-recursion-5-saldos-acumulados/

Y una tercera forma es usando CTE, y este artículo se refiere precisamente a eso.

Entonces, resumiendo, para obtener sumas acumuladas podemos:

  1. Escribir un stored procedure
  2. Usar recursión
  3. Usar tablas CTE

Obtener las sumas acumuladas mediante CTE tiene sus “bemoles”, ya que hay varios aspectos a considerar.

Primer caso. Se usa una sola clasificación

Esto es lo más fácil, tal como podemos ver a continuación:

Listado 1.

WITH SALDOS (VTC_FECHAX, VTC_TOTALX) AS
   (SELECT
       VTC_FECHAX,
       SUM(VTC_TOTALX)
    FROM
       VENTASCAB
    GROUP BY
       VTC_FECHAX)

SELECT
   T1.VTC_FECHAX,
   SUM(VTC_TOTALX) AS VENTAS_FECHA,
   (SELECT
       SUM(VTC_TOTALX)
    FROM
       SALDOS T2
    WHERE
       T2.VTC_FECHAX <= T1.VTC_FECHAX) AS 
   SALDO_ACUMULADO
FROM
   VENTASCAB T1
GROUP BY
   T1.VTC_FECHAX
ORDER BY
   T1.VTC_FECHAX

Si ejecutamos el Listado 1. obtendremos un resultado similar al siguiente:

SALDOS1

Captura 1. Si haces clic en la imagen la verás más grande

Donde como puedes ver, en la columna VENTAS_FECHA se muestra el total vendido en esa fecha y en la columna SALDO_ACUMULADO se muestra el total vendido hasta esa fecha.

Segundo caso. Se usan dos clasificaciones

Listado 2.

WITH SALDOS (ASI_IDENTI, ASI_MONTOX) AS
   (SELECT
       ASI_IDENTI,
       SUM(ASI_MONTOX)
    FROM
       ASIENTOSDET
    WHERE
       ASI_NUMCUE = '1.01.01.01.01'
    GROUP BY
       ASI_IDENTI)

SELECT
   T1.ASI_IDENTI,
   T1.ASI_NUMCUE,
   T1.ASI_MONTOX,
   (SELECT
       SUM(T2.ASI_MONTOX)
    FROM
       SALDOS T2
    WHERE
       T2.ASI_IDENTI <= T1.ASI_IDENTI AND
       T1.ASI_NUMCUE = '1.01.01.01.01') AS 
   SALDO_ACUMULADO
FROM
   ASIENTOSDET T1
WHERE
   T1.ASI_NUMCUE = '1.01.01.01.01'
ORDER BY
   T1.ASI_IDENTI

En el Listado 2. vemos que se usan dos clasificaciones. Una por Identificador del asiento y la otra por el número de la cuenta. El significado de las columnas es el siguiente:

  • ASI_IDENTI = Identificador del asiento
  • ASI_NUMCUE = Número de la cuenta contable
  • ASI_MONTOX = Importe asentado

Si ejecutamos el Listado 2. obtendremos un resultado similar al siguiente:

SALDOS2

Captura 2. Si haces clic en la imagen la verás más grande

Donde como puedes ver, se obtienen las sumas acumuladas pero escribir el SELECT fue un poco más complicado que en el primer caso.

Tercer caso. Se usan dos o más tablas

A veces las columnas se encuentran en dos (o más) tablas. En los casos anteriores se encontraban todas en una sola tabla, ya que la tabla CTE era simplemente una derivada de la tabla principal.

Listado 3.

WITH SALDOS (ASI_NUMCUE, ASI_MONTOX) AS
   (SELECT
       ASI_NUMCUE,
       SUM(ASI_MONTOX)
    FROM
       ASIENTOSDET
    GROUP BY
       ASI_NUMCUE)

SELECT
   CUE_NUMERO,
   CUE_NOMBRE,
   (SELECT
       SUM(T2.ASI_MONTOX)
    FROM
       SALDOS T2
    WHERE
       T1.CUE_NUMERO = T2.ASI_NUMCUE) AS 
   SALDO_ACUMULADO
FROM
   CUENTAS T1
WHERE
   CUE_ASENTA = 1
ORDER BY
   CUE_NUMERO

Ahora usamos dos tablas, la tabla principal (CUENTAS) tiene los datos de las cuentas y la tabla secundaria (ASIENTOSDET) tiene los datos de los asientos. El significado de las columnas es:

  • CUE_NUMERO = Número de la cuenta contable
  • CUE_NOMBRE = Nombre de la cuenta contable
  • CUE_ASENTA = Un 1 indica que la cuenta sí es asentable (o imputable)
  • ASI_NUMCUE = Número de la cuenta contable
  • ASI_MONTOX = Importe asentado

Si ejecutamos el Listado 3. obtendremos un resultado similar al siguiente:

SALDOS3

Captura 3. Si haces clic en la imagen la verás más grande

Donde tenemos el número y el nombre de cada cuenta contable y su saldo acumulado.

Conclusión:

Si necesitamos obtener sumas o saldos acumulados tenemos varias alternativas, podemos escribir un stored procedure seleccionable, o podemos escribir un SELECT con recursión o podemos escribir un SELECT sin recursión. Ya dependerá de nosotros y de las circunstancias.

Un punto a tener en cuenta con el método mostrado en este artículo es que en tablas muy grandes puede llegar a ser lento, así que debemos tener en cuenta ese aspecto también.

Artículos relacionados:

Ejemplo de recursión (5). Saldos acumulados

El índice del blog Firebird21

El foro del blog Firebird21

Anuncios