Precaución al usar la función SUM()

3 comentarios

A veces puede parecer que se obtendrá el mismo resultado escribiendo un SELECT que tiene una función SUM() de una forma o de otra, pero lo que se obtiene no es lo esperado. Veamos un ejemplo:

SUMA1

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

Listado 1.

SELECT
   SUM(MOV_PRECIO) / SUM(MOV_CANTID) AS RESULTADO
FROM
   MOVIMDET

SUMA2

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

Listado 2.

SELECT
   SUM(MOV_PRECIO / MOV_CANTID) AS RESULTADO
FROM
   MOVIMDET

SUMA3

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

¿Por qué no se obtiene el mismo resultado? ¿Acaso ambos resultados no deberían ser idénticos?

Pues no, en el Listado 1. se le pide que sume todos los valores de la columna MOV_PRECIO y los divida por la suma de todos los valores de la columna MOV_CANTID

Suma de MOV_PRECIO = 200

Suma de MOV_CANTID = 2

Al dividir ambas sumas el resultado es 100

Sin embargo, en el Listado 2. para cada fila primero se halla el resultado de la división y luego se realiza la suma.

100 / 1 = 100

100 / 1 = 100

Al sumar ambos resultados se obtiene 200

El motivo por el cual se obtienen resultados diferentes es que en el Listado 1. se suman todas las filas de una sola vez, en cambio en el Listado 2. se suman de una en una.

Cuidado con esto, si no entiendes bien este concepto podrías estar obteniendo resultados incorrectos.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

 

Anuncios

Hallar los movimientos ocurridos entre dos fechas (otro método)

5 comentarios

En este artículo ya habíamos visto un método para hallar todos los movimientos (compras, ventas, cobranzas, pagos, etc.) que ocurrieron entre dos fechas dadas, y si en una fecha no hubo movimientos entonces mostrarla igual pero con un total de cero.

https://firebird21.wordpress.com/2014/04/29/hallando-todas-las-ventas-entre-dos-fechas-dadas/

Ahora, veremos otro método con el cual podremos obtener los mismos resultados, gracias a la colaboración de Claudio Martín.

Aquí, lo que haremos será crear un stored procedure seleccionable que nos devolverá todas las fechas de un rango dado, y luego cuando las necesitemos mediante un LEFT JOIN o un RIGHT JOIN las obtendremos.

Este método tiene la ventaja de que el stored procedure seleccionable que escribimos es uno solo y lo podemos utilizar en multitud de ocasiones diferentes, todas las veces que necesitemos un rango de fechas.


CREATE PROCEDURE RANGO_FECHAS(
      tdFecIni DATE,
      tdFecFin DATE)
   RETURNS(
      ftdFecha DATE)
AS
   DECLARE VARIABLE ldFecha DATE;
BEGIN

   ldFecha = tdFecIni;

   WHILE (ldFecha <= tdFecFin) DO BEGIN
      ftdFecha = ldFecha;
      SUSPEND;
      ldFecha = ldFecha + 1;
   END

END;

Entonces, usando la misma tabla que en el artículo anterior, escribiríamos:

SELECT
   R.ftdFecha,
   SUM(COALESCE(M.MVC_TOTALX, 0)) AS TOTAL_VENTAS_DIA
FROM
   RANGO_FECHAS('01/01/2014', '01/07/2014') R
LEFT JOIN
   MOVIMCAB M
      ON R.ftdFecha = M.MVC_FECHAX
GROUP BY
   R.ftdFecha

Y obtendríamos este resultado:

VENTAS1

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

El cual, como puedes verificar, es exactamente igual al obtenido con el otro método. Pero la ventaja de este nuevo método es que el stored procedure seleccionable podemos usarlo siempre que necesitemos obtener todas las fechas de un rango dado.

 Conclusión:

Una de las muchas cosas buenas que tiene el Firebird es que nos permite obtener los mismos resultados usando métodos diferentes, queda a nuestro criterio elegir el que nos parece más conveniente para cada situación particular.

En este caso, podemos tener un stored procedure que cuando las necesitemos nos devolverá todas las fechas de un rango, para ello simplemente lo juntamos mediante LEFT JOIN o RIGHT JOIN a la otra tabla y listo, ya está.

Artículos relacionados:

Hallando todas las ventas entre dos fechas dadas

Entendiendo a los Stored Procedures

El índice del blog Firebird21

 

Algunos ejemplos de funciones agregadas

Deja un comentario

En otros artículos ya habíamos visto las funciones agregadas, aquí hay algunos ejemplos más de como usarlas.

SELECT
   SUM(IIF(MOV_CODSUC = 0, MOV_CANTID * MOV_PRECIO, 0)) AS TOTAL0,
   SUM(IIF(MOV_CODSUC = 1, MOV_CANTID * MOV_PRECIO, 0)) AS TOTAL1
FROM
   MOVIMDET

En esta consulta, si el Código de la Sucursal es 0 se realiza la multiplicación y se halla el Total de esa Sucursal. Lo mismo con la Sucursal 1.

SELECT
   COUNT(DISTINCT IIF(MOV_CODSUC = 0, MOV_CANTID, NULL)) AS TOTAL0,
   COUNT(DISTINCT IIF(MOV_CODSUC = 1, MOV_CANTID, NULL)) AS TOTAL1
FROM
   MOVIMDET

En esta consulta contamos cuantas cantidades distintas hay en la Sucursal 0 y en la Sucursal 1 de la tabla MOVIMDET.

SELECT
   COUNT(DISTINCT IIF(MOV_CODSUC = 0, MOV_IDEPRD, NULL)) AS TOTAL0,
   COUNT(DISTINCT IIF(MOV_CODSUC = 1, MOV_IDEPRD, NULL)) AS TOTAL1
FROM
   MOVIMDET

Y en esta consulta contamos cuantos productos distintos hay en la tabla MOVIMDET (la columna MOV_IDEPRD es el Identificador del Producto).

Conclusión:

Lo interesante de los ejemplos es que muestran que dentro de las funciones agregadas se pueden escribir otras funciones.

Artículo relacionado:

El índice del blog Firebird21