Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Reporte Anual (https://www.clubdelphi.com/foros/showthread.php?t=80158)

jooooseph 06-09-2012 22:10:45

Reporte Anual
 
1 Archivos Adjunto(s)
Hola...

Tengo un poco de dificultad en desarrollar un reporte anual. Para ello tengo una tabla de mis clientes y otra con los ingresos que van aportando durante el mes durante un año. algo asi...

Tabla Cliente
Código:

cod_client | Nombre
-----------+-------
1          | pedro
2          | Juan
3          | Cesar


Tabla Ingresos
Código:

cod_Ingr | Nombre | Fecha      | Monto
---------+--------+------------+-------
1        | Juan  | 02/01/2012 | 120.00
2        | Cesar  | 03/01/2012 | 100.00
3        | Juan  | 03/01/2012 | 80.00
4        | Pedro  | 07/01/2012 | 100.00
5        | Cesar  | 02/02/2012 | 20.00


Solo unos pocos ingresos para una prueba. Lo que necesito es que me muestre si es posible de la siguiente forma.
Código:

Nombre ... | Enero  | Febrero | Marzo | ...... hasta | Diciembre
-----------+--------+---------+-------+-------------------------
Cesar .... | 100.00 | 20.00  | -    | ...... -
Juan ....  | 200.00 | -      | -    | ...... -
Pedro .... | 100.00 | -      | -    | ...... -


Gracias de antemano a cualquier tipo de ayuda.

ecfisa 06-09-2012 23:23:25

Hola jooooseph.

Una forma sencilla de mostrar los datos tabulados es organizarlos en el block de notas, copiarlos y luego pegarlos entre las etiquetas [code] [/code] .

Para que pudieras ver el efecto lo hice sobre tu mensaje, tiene la ventaja de ahorrarte el tiempo de preparar las imágenes ;)

Saludos. :)

Loviedo 06-09-2012 23:58:23

No se si esta es una manera correcta, pero es lo que yo hago.
1º - Creo una tabla temporal con los campos nombre(string) y los 12 campos meses(decimal). 'TCientDataset'.
2º - Con un bucle recorro tu tabla y busco en la tabla temporal el nombre, y hago un append o un edit (Si existe ó No).
3º - Con la función MonthOf(campo fecha de tu tabla) determino el mes.
4º - En tabla temporal edito el campo del mes obtenido con el importe.
Saludos.

D-MO 07-09-2012 00:00:01

¿Qué motor de base de datos utilizas?

Me parece que lo que necesitas es armar un PivotTable, pero cada motor de BD trabaja de diferente manera.

Saludos

movorack 07-09-2012 00:03:03

Hola jooooseph.

Para hacer esto tienes muchas posibilidades y como no das mucha información acerca de como estás construyendo el reporte si con un reporteador o si debe ir en archivos de texto, si lo debes hacer desde algun programa o desde un procedimiento almacenado. ni siquiera dices que motor de DB usas... en fin.

Si lo hicieras con una consulta (sería complicado pero se podria contemplar) tendrias que hacer primero una consulta base de clientes esto dejarla en una subconsulta y sobre esta hacer subconsultas por cada mes.

Algo así:

Código SQL [-]
SELECT
  S1.IDCLIENTE,
  (SELECT SUM(MONTO) FROM VENTAS WHERE IDCLIENTE = S1.IDCLIENTE AND DATEPART(FECHAVENTA, DP_MONTH) = 1) -- ENERO
  ..  
  (SELECT SUM(MONTO) FROM VENTAS WHERE IDCLIENTE = S1.IDCLIENTE AND DATEPART(FECHAVENTA, DP_MONTH) = 12) -- DICIEMBRE
FROM (
  SELECT DISTINCT IDCLIENTE
  FROM CLIENTES
  WHERE FECHA BETWEEN FECHA1 AND FECHA 2
) AS S1

Claro está esta consulta tendrá un costo bastante alto por lo que me iria a la siguiente opción si tu motor lo permite

Si lo hicieras desde un sp que alimente una tabla podrias primero buscar los clientes que tuvieron registros a lo largo del año y luego procesarlos en los meses respectivos y obtenida la linea de registro llevarla a la tabla para despues procesarla en algun programa.

En el caso de que lo hicieras desde el programa seria lo mismo que el SP pero obviando el registro en tabla y llevandolo directamente al diseño del reporte.

Espero poder haberte colaborado.

Un saludo.

jooooseph 07-09-2012 00:06:14

GRACIAS A AMBOS...

Ya voy a poder enviar mejor mis consultas..

Con respecto a usar una tabla tempora.... es correcto lo que dices, antiguamente lo realizaba de esa forma. Pero me imagino que se puede crear algun storProcedure o algun select complejo que lo pueda hacer. ahora estoy trabajando es eso. Cuando tenga la respuesta se los paso... Pero si alguien mas tiene alguna de como hacerlo, le estare agradecido.^\||/

Estoy usando Firebird... en delphi EX2...

roman 07-09-2012 07:06:34

Cita:

Empezado por jooooseph (Mensaje 442141)
Lo que necesito es que me muestre si es posible de la siguiente forma.
Código:

Nombre ... | Enero  | Febrero | Marzo | ...... hasta | Diciembre
-----------+--------+---------+-------+-------------------------
Cesar .... | 100.00 | 20.00  | -    | ...... -
Juan ....  | 200.00 | -      | -    | ...... -
Pedro .... | 100.00 | -      | -    | ...... -


En MySQL podemos hacer esto:

Código SQL [-]
select
  nombre,
  sum(if(extract(month from fecha) = 1, monto, 0)) as enero,
  sum(if(extract(month from fecha) = 2, monto, 0)) as febrero,
  ...
  sum(if(extract(month from fecha) = 12, monto, 0)) as diciembre
from ingresos
group by nombre

que, me parece, da el resultado que quieres y sin usar subconsultas ni tablas temporales. Supongo que en Firebird se puede hacer algo similar si tiene un condicional IF y alguna función para extraer las partes de una fecha.

Por cierto, tu tabla de ingresos debería llevar el código del cliente en lugar de su nombre, ¿no crees?

// Saludos

fjcg02 07-09-2012 09:56:11

Mira este hilo ver qué te parece.

Tira por lo que indi ca Román.

http://www.clubdelphi.com/foros/show...ighlight=pivot

saludos

Casimiro Notevi 07-09-2012 10:10:16

Cita:

Empezado por roman (Mensaje 442243)
Por cierto, tu tabla de ingresos debería llevar el código del cliente en lugar de su nombre, ¿no crees?

Es en lo primero que me fijé.

Código:

cod_Ingr | cod_cliente | Fecha      | Monto
---------+-------------+------------+-------
1        |    2      | 02/01/2012 | 120.00
2        |    3      | 03/01/2012 | 100.00
3        |    2      | 03/01/2012 | 80.00
4        |    1      | 07/01/2012 | 100.00
5        |    3      | 02/02/2012 | 20.00


roman 07-09-2012 16:52:28

Cita:

Empezado por fjcg02 (Mensaje 442252)
Mira este hilo ver qué te parece.

Tira por lo que indi ca Román.

http://www.clubdelphi.com/foros/show...ighlight=pivot

saludos

¡Ah! Pues mira, parece ser el mismo caso. Entonces, ¿firebird no tiene función extract o equivalente?

// Saludos

Casimiro Notevi 07-09-2012 16:58:04

Cita:

Empezado por roman (Mensaje 442275)
¡Ah! Pues mira, parece ser el mismo caso. Entonces, ¿firebird no tiene función extract o equivalente?

Sí tiene la functión extract.

movorack 07-09-2012 16:58:05

Cita:

Empezado por roman (Mensaje 442275)
¡Ah! Pues mira, parece ser el mismo caso. Entonces, ¿firebird no tiene función extract o equivalente?

// Saludos

Aquí dice que si tiene la funcion extract... http://www.firebirdsql.org/refdocs/l...c-extract.html

Edito: Ya lo habia respondido Casimiro :D

Casimiro Notevi 07-09-2012 17:22:34

Cita:

Empezado por movorack (Mensaje 442278)
Edito: Ya lo habia respondido Casimiro :D

Sí, pero no tan bien como tú :D

roman 07-09-2012 17:28:41

Sí, yo lo comentaba porque en el hilo que cita fjcg02, la solucíon pasa por hacer un CAST de la fecha a string y luego un SUBSTR para extraer el mes.

Y, ¿firebird tiene función IF o sólo el CASE?

// Saludos

movorack 07-09-2012 17:38:46

Creo que solo tiene CASE...

Algo así funcionaria? hace rato no trabajo firebird y la idea está como confusa... yo me iria mejor por el lado del SP o de trabajar todo en el programa si a la final no se debe almacenar en ningun lado y si es un reporte de datos anuales la sentencia va a ser bastante costosa. Un amigo DBA de oracle me dice mejor hacer muchas sentencias efectivas y con poco costo y no una gran sentencia con un costo excesivo.

Código SQL [-]
SELECT
  IDCLIENTE,
  (CASE EXTRACT(MONTH, FECHAVENTA)
    WHEN 1 THEN SUM(VALORVENTA)
  END) AS ENERO
  ..
  (CASE EXTRACT(MONTH, FECHAVENTA)
    WHEN 12 THEN SUM(VALORVENTA)
  END) AS DICIEMBRE
FROM VENTAS

roman 07-09-2012 17:53:52

Pero con el CASE también funciona y evitas las subconsultas.

// Saludos

jooooseph 07-09-2012 18:55:35

Cita:

Empezado por roman (Mensaje 442243)
En MySQL podemos hacer esto:

Código SQL [-]select nombre, sum(if(extract(month from fecha) = 1, monto, 0)) as enero, sum(if(extract(month from fecha) = 2, monto, 0)) as febrero, ... sum(if(extract(month from fecha) = 12, monto, 0)) as diciembre from ingresos group by nombre


que, me parece, da el resultado que quieres y sin usar subconsultas ni tablas temporales. Supongo que en Firebird se puede hacer algo similar si tiene un condicional IF y alguna función para extraer las partes de una fecha.

Por cierto, tu tabla de ingresos debería llevar el código del cliente en lugar de su nombre, ¿no crees?

// Saludos

Hola Roman. Gracias por el Aporte, estoy viendo una nueva forma de consulta que voy a ver como funciona, pero la consulta que tengo desarrollada ya me esta funcionando. que es la siguiente

Código SQL [-]
SELECT
  CLIENTE.NOMBRE,
  (SELECT SUM(INGRESO.MONTO) FROM INGRESO WHERE CLIENTE.NOMBRE = INGRESO.NOMBRE AND (EXTRACT(MONTH FROM FECHA_INGRESO) = 1) AND (EXTRACT(YEAR FROM FECHA_INGRESO) = 2012)) As "ENERO",
  (SELECT SUM(INGRESO.MONTO) FROM INGRESO WHERE CLIENTE.NOMBRE = INGRESO.NOMBRE AND (EXTRACT(MONTH FROM FECHA_INGRESO) = 2) AND (EXTRACT(YEAR FROM FECHA_INGRESO) = 2012)) As "FEBRERO"
FROM ( SELECT DISTINCT NOMBRE
           FROM CLIENTE)

Este tipo de consulta me hace el reporte anual de diferentes años, claro esta que el 2012 debera ser ingresado como variable.

Voy a modificar mi consulta por una de tu tipo ROMAN.


Gracias por la AYUDA a todos^\||/

roman 07-09-2012 19:01:57

Cita:

Empezado por jooooseph (Mensaje 442330)
claro esta que el 2012 debera ser ingresado como variable.

Cierto. En la consulta que puse habría que añadir una condición WHERE para el año. La consulta que pones puede servir, pero el problem es que las subconsultas siempre son más lentas.

// Saludos

jooooseph 07-09-2012 19:59:55

Cita:

Empezado por roman (Mensaje 442332)
Cierto. En la consulta que puse habría que añadir una condición WHERE para el año. La consulta que pones puede servir, pero el problem es que las subconsultas siempre son más lentas.

// Saludos

En difinitiva. He probado tu tipo de consulta y me parece mas efectivo, el unico problema es que en mi reporte no solo quiero que aparezca solo aquellas personas que han hecho algun tipo de ingreso, sino aquellas que derrepente no han hecho ningun ingreso. Es por ello la consulta o el join con dos tablas..... Pero el tuyo me parece genial, que lo voy a usar para otro tipo de reporte . Gracias por la colaboracion.^\||/

roman 07-09-2012 20:19:34

Cita:

Empezado por jooooseph (Mensaje 442340)
el unico problema es que en mi reporte no solo quiero que aparezca solo aquellas personas que han hecho algun tipo de ingreso, sino aquellas que derrepente no han hecho ningun ingreso.

Creo que eso puede arreglarse sin recurrir a las subconsultas:

Código SQL [-]
select
  clientes.nombre,
  sum(if(extract(month from fecha) = 1, monto, 0)) as enero,
  sum(if(extract(month from fecha) = 2, monto, 0)) as febrero,
  ...
  sum(if(extract(month from fecha) = 12, monto, 0)) as diciembre
from clientes
left join ingresos on clientes.nombre = ingresos.nombre
where extract(year from fecha) = 2012
group by nombre

// Saludos


La franja horaria es GMT +2. Ahora son las 18:27:29.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi