Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Mysql »

INNER JOIN con tres tablas y función SUM

Estas en el tema de INNER JOIN con tres tablas y función SUM en el foro de Mysql en Foros del Web. Hola Buen día tengo un serio problema con sum y los inner join en SQL... Espero puedan ayudarme Bueno quiero hacer una consulta a 3 ...
  #1 (permalink)  
Antiguo 28/06/2013, 11:39
luis_enr27
Invitado
 
Mensajes: n/a
Puntos:
Busqueda Problema: INNER JOIN con tres tablas y función SUM

Hola Buen día tengo un serio problema con sum y los inner join en SQL... Espero puedan ayudarme
Bueno quiero hacer una consulta a 3 tablas y poder obtener la suma del campo ventas_TM y suma de ventas_TM de la tabla de ventas, a su vez la suma de gasto de la tabla gastos y tambien la suma de depositos de la tabla depositos; Todo esto que cumpla la condicion que pido en donde el rango de fechas seleccionado, de la farmacia seleccionada y del turno donde sea diferente a completo.

TABLAS:
ventas (id_venta,fecha,farmacia, usuario_TM, ventas_TM,usuario_TB,ventas_TV)
gastos (id_gasto,fecha,farmacia,usuario,turno,gasto)
depositos (id_deposto, fecha,farmacia,usuario,turno,deposito)

CONSULTA:
SELECT
ventas.fecha,
usuario_TM,
SUM( DISTINCT ventas_TM) as TM,
usuario_TV,
SUM(DISTINCT ventas_TV) as TV,
SUM(DISTINCT (ventas_TM+ventas_TV)) as TOTAL_VENTAS,
CASE WHEN COUNT(gasto)>1 THEN ifnull((SUM(gasto)/count(DISTINCT
id_deposito)), (SUM(gasto)/1))
ELSE ifnull(SUM(DISTINCT gasto),0)
END,
CASE WHEN COUNT(deposito)>1 THEN ifnull((SUM(deposito)/count(distinct id_gasto)), (SUM(deposito)/1))
ELSE ifnull(SUM(DISTINCT deposito),0)
END
FROM ventas INNER JOIN gastos INNER JOIN depositos
ON ventas.fecha=gastos.fecha AND gastos.fecha=depositos.fecha
WHERE ventas.farmacia='nombre_farmacia' AND ventas.fecha between '2013-06-01' AND '2013-06-15' AND
gastos.turno!='COMPLETO' AND depositos.turno!='COMPLETO'
GROUP BY ventas.fecha
ORDER BY ventas.fecha ASC;

El problema es que utilizo un while para la obtencion de informacion y llenado de un reporte pero me devuelve informacion erronea cuando hago una consulta, ya que me multiplica la informacion(sumas) por el numero de registros de la tabla de union es por ello qe hago case, pero aun asi cuando no hay un registro en la otra tabla que cumpla la condicion no regresa ningun dato.
relaciono las tablas por fecha y por farmacia ya que con el id no puedo, ya que hay ocacionesque alguna de las tres tablas puede tener de 0 a muchos registros. espero entiendan
  #2 (permalink)  
Antiguo 28/06/2013, 12:53
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: INNER JOIN con tres tablas y función SUM

Hola luis_enr27:

Este problema es bastante típico, y por lo general se ocasiona porque no se tiene claro el función de los JOIN's... vayamos por partes...

Cita:
El problema es que utilizo un while para la obtencion de informacion y llenado de un reporte pero me devuelve informacion erronea cuando hago una consulta, ya que me multiplica la informacion(sumas) por el numero de registros de la tabla de union es por ello qe hago case
En este punto el problema puede estar en la cardinalidad de tus tablas, es decir cómo están relacionadas tus tablas... (puede ser 1 a 1, 1 a n o 0 a n)... el detalle al decir que te está "multiplicando" la información me hace suponer que tienes una relación 1 a n, pero la suma no la haces de manera consolidada... Veamos este ejemplo. Supongamos que tienes estos datos:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM ventas;
  2. +---------+-------+
  3. | idventa | monto |
  4. +---------+-------+
  5. |       1 |   100 |
  6. |       2 |   200 |
  7. |       3 |   300 |
  8. +---------+-------+
  9. 3 rows in set (0.00 sec)
  10.  
  11. mysql> SELECT * FROM depositos;
  12. +------------+---------+-------+
  13. | iddeposito | idventa | monto |
  14. +------------+---------+-------+
  15. |          1 |       1 |    25 |
  16. |          2 |       1 |    20 |
  17. |          3 |       2 |   100 |
  18. |          4 |       1 |    20 |
  19. |          5 |       2 |    50 |
  20. +------------+---------+-------+
  21. 5 rows in set (0.00 sec)

es decir, tres ventas con un monto y varios depósitos para cada venta a manera de abonos a la cuenta... (no uso los mismos campos que tú, pero la idea es la misma)... supongamos que quieres saber cuánto se ha depositado a cada venta... La idea es SUMAR todos los depósitos e igualarlos para cada venta, pero observa que tienes una relación 0 a n, es decir, puede haber depósitos o no para cada venta... si haces un JOIN entre las tablas, olvidándote por ahora de las sumas observa qué pasa:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM ventas
  2.     -> INNER JOIN depositos ON ventas.idventa = depositos.idventa;
  3. +---------+-------+------------+---------+-------+
  4. | idventa | monto | iddeposito | idventa | monto |
  5. +---------+-------+------------+---------+-------+
  6. |       1 |   100 |          1 |       1 |    25 |
  7. |       1 |   100 |          2 |       1 |    20 |
  8. |       2 |   200 |          3 |       2 |   100 |
  9. |       1 |   100 |          4 |       1 |    20 |
  10. |       2 |   200 |          5 |       2 |    50 |
  11. +---------+-------+------------+---------+-------+
  12. 5 rows in set (0.00 sec)

Observa en primer lugar, que por cada registro en tu tabla depósitos se está repitiendo el monto de la venta... por lo tanto, si agrupas por venta y quieres obtener el monto de la venta, pues daría la impresión de que se multiplicó... además, la venta 3 no tiene ningún depósito, por lo tanto al utilizar INNER JOIN no se presenta...

Código MySQL:
Ver original
  1. mysql> SELECT ventas.idventa,
  2.     -> SUM(ventas.monto) total_venta, SUM(depositos.monto) total_depositos
  3.     -> FROM ventas
  4.     -> INNER JOIN depositos ON ventas.idventa = depositos.idventa
  5.     -> GROUP BY ventas.idventa;
  6. +---------+-------------+-----------------+
  7. | idventa | total_venta | total_depositos |
  8. +---------+-------------+-----------------+
  9. |       1 |         300 |              65 |
  10. |       2 |         400 |             150 |
  11. +---------+-------------+-----------------+
  12. 2 rows in set (0.00 sec)

Como dije al inicio, el problema es la cardinalidad de tus tablas... debes convertir tu relación 1 a n en una relación 1 a 1... es decir, sumar primeramente todos los depósitos antes de hacer el JOIN... además, en lugar de utilizar un INNER JOIN, debes hacer uso de LEFT JOIN o RIGTH JOIN, para que las relaciones no sean obligadas. sería más o menos así:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM ventas LEFT JOIN
  2.     -> (  SELECT idventa, SUM(monto) total_depositos
  3.     ->    FROM depositos GROUP BY idventa
  4.     -> ) depositos ON ventas.idventa = depositos.idventa;
  5. +---------+-------+---------+-----------------+
  6. | idventa | monto | idventa | total_depositos |
  7. +---------+-------+---------+-----------------+
  8. |       1 |   100 |       1 |              65 |
  9. |       2 |   200 |       2 |             150 |
  10. |       3 |   300 |    NULL |            NULL |
  11. +---------+-------+---------+-----------------+
  12. 3 rows in set (0.00 sec)

de esta manera las sumas son correctas y además presenta todos los registros, no solo aquellos que tengan registros en la otra tabla...

observa que en el JOIN se hace una subconsulta, agrupando previamente. de esta manera se evita la "multiplicación" de las cantidades.

Dale un vistazo y trata de implementar este tipo de consultas a lo que quieres hacer.

Saludos
Leo.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 19:19.