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

[SOLUCIONADO] Restar dos Count MySQL

Estas en el tema de Restar dos Count MySQL en el foro de Mysql en Foros del Web. Buenos días, he estado intentando hacer una consulta mysql durante varias horas pero no hay manera, a ver si pueden ayudarme por favor. Tengo la ...
  #1 (permalink)  
Antiguo 19/11/2014, 05:58
 
Fecha de Ingreso: noviembre-2014
Mensajes: 4
Antigüedad: 9 años, 5 meses
Puntos: 0
Restar dos Count MySQL

Buenos días, he estado intentando hacer una consulta mysql durante varias horas pero no hay manera, a ver si pueden ayudarme por favor.

Tengo la tabla Facturas, la tabla Abonos y la Tabla Clientes.

La Relación de Facturas y Abonos se hace gracias al id del Cliente.

Necesito conseguir el resultado de restar el total de Facturas realizadas - el Total de Abonos realizados por los clientes.

Consigo hacerlo de forma individual, es decir, para un cliente en concreto, con la siguiente consulta
Código MySQL:
Ver original
  1. SELECT (SELECT COUNT(distinct factura_numero) FROM Facturas
  2.  INNER JOIN Ventas ON ventas_id = factura_ventas_id
  3.  INNER JOIN Clientes ON cliente_id=ventas_id_cliente
  4. # ----------------------------------------------
  5. WHERE cliente_id=121) -
  6. # ----------------------------------------------
  7. (SELECT COUNT(abonos_id) FROM Abonos
  8.  INNER JOIN Clientes ON cliente_id=abonos_id_cliente
  9. # ----------------------------------------------
  10. WHERE cliente_id=121
  11. # ----------------------------------------------
  12. ) AS RestaCount
Con esto consigo restar 23 facturas - 6 abonos para id 121 = 17. Hasta aquí correcto.

Lo ideal sería conseguirlo para todos los clientes, algo así como un group by clientes_id y obtener:
id 121, total 23
id 122, total 12
.....

Imagino que estoy haciendo algo mal, porque algunos clientes No han hecho abonos e incluso algunos clientes No han llegado a facturar todavía, entonces tal vez haya que meter un Left Join en algún sitio, pero no se donde.

Si introduzco un group by haciendo algo así:

Código MySQL:
Ver original
  1. SELECT t1.Total - t2.Total FROM(
  2. SELECT cliente_id, COUNT( DISTINCT factura_numero ) as Total
  3. FROM Facturas
  4. INNER JOIN Ventas ON ventas_id = factura_ventas_id
  5. INNER JOIN Clientes ON cliente_id = ventas_id_cliente
  6. GROUP BY cliente_id) as t1, (SELECT cliente_id, COUNT(abonos_id) as Total
  7.         FROM Abonos
  8.        INNER JOIN Clientes ON cliente_id=abonos_id_cliente group by cliente_id) as t2 WHERE t1.cliente_id=t2.cliente_id
Sencillamente se vuelve loco,

Un saludo y gracias

Última edición por gnzsoloyo; 20/11/2014 a las 06:37 Razón: Legibilidad de codigo SQL
  #2 (permalink)  
Antiguo 19/11/2014, 16:15
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: Restar dos Count MySQL

Hola guilens2:

El problema que tienes con tu consulta es que tienes dos relaciones 1 a muchos, que al unirse se convierten en muchos a muchos, lo cual puede ocasionar varios dolores de cabeza.

Tienes varias formas de afrontar esta consulta, una de las más simples desde mi punto de vista es Consolidar los totales en facturas y abonos, de tal manera que tu relación cambie de 1 a 1, no colocas mucha información de tus tablas, pero tratando de hacerle al adivino, creo que tienes algo como esto:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM clientes;
  2. +------------+-------------+
  3. | id_cliente | descripcion |
  4. +------------+-------------+
  5. |          1 | Cliente 1   |
  6. |          2 | Cliente 2   |
  7. |          3 | Cliente 3   |
  8. |          4 | Cliente 4   |
  9. +------------+-------------+
  10. 4 rows in set (0.00 sec)
  11.  
  12. mysql> SELECT * FROM facturas;
  13. +------------+------------+-------------+-------------+
  14. | id_factura | id_cliente | num_factura | descripcion |
  15. +------------+------------+-------------+-------------+
  16. |          1 |          1 |           1 | Factura 1.1 |
  17. |          2 |          1 |           2 | Factura 1.2 |
  18. |          3 |          2 |           3 | Factura 2.1 |
  19. |          4 |          2 |           4 | Factura 2.1 |
  20. |          5 |          3 |           5 | Factura 3.1 |
  21. +------------+------------+-------------+-------------+
  22. 5 rows in set (0.00 sec)
  23.  
  24. mysql> SELECT * FROM abonos;
  25. +----------+------------+-----------+-------------+
  26. | id_abono | id_cliente | num_abono | descripcion |
  27. +----------+------------+-----------+-------------+
  28. |        1 |          1 |        10 | Abono 1.1   |
  29. |        2 |          1 |        11 | Abono 1.2   |
  30. |        3 |          2 |        12 | Abono 2.1   |
  31. +----------+------------+-----------+-------------+
  32. 3 rows in set (0.00 sec)

es decir, hay clientes que tienen facturas y abonos, clientes que solo tienen facturas y clientes que no tienen ni facturas ni abonos...

Si observas las tablas de FACTURAS Y ABONOS, puedes CONSOLIDAR los totales, agrupando por ID del cliente, es decir, hacer algo como esto:

Código MySQL:
Ver original
  1. mysql> SELECT id_cliente, COUNT(*) total_facturas
  2.     -> FROM facturas
  3.     -> GROUP BY id_cliente;
  4. +------------+----------------+
  5. | id_cliente | total_facturas |
  6. +------------+----------------+
  7. |          1 |              2 |
  8. |          2 |              2 |
  9. |          3 |              1 |
  10. +------------+----------------+
  11. 3 rows in set (0.00 sec)

Observa que ahora puedes unir tu tabla CLIENTES con esta tabla, en una relación 1 a 1... lo mismo ocurre con los abonos.

Ahora bien, aquí es donde entran los LEFT JOIN's, para considerar aquellos que no tienen elementos en alguna de las tablas (o en ninguna), sería más o menos así:

Código MySQL:
Ver original
  1. mysql> SELECT C.id_cliente, C.descripcion, F.total_facturas, A.total_abonos
  2.     -> FROM clientes C
  3.     -> LEFT JOIN ( SELECT id_cliente, COUNT(*) total_facturas
  4.     ->             FROM facturas
  5.     ->             GROUP BY id_cliente) F ON C.id_cliente = F.id_cliente
  6.     -> LEFT JOIN ( SELECT id_cliente, COUNT(*) total_abonos
  7.     ->             FROM abonos
  8.     ->             GROUP BY id_cliente) A ON C.id_cliente = A.id_cliente ;
  9. +------------+-------------+----------------+--------------+
  10. | id_cliente | descripcion | total_facturas | total_abonos |
  11. +------------+-------------+----------------+--------------+
  12. |          1 | Cliente 1   |              2 |            2 |
  13. |          2 | Cliente 2   |              2 |            1 |
  14. |          3 | Cliente 3   |              1 |         NULL |
  15. |          4 | Cliente 4   |           NULL |         NULL |
  16. +------------+-------------+----------------+--------------+
  17. 4 rows in set (0.00 sec)

Observa que los LEFT JOIN's se hacen SOBRE LAS CONSULTAS CONSOLIDADAS, por lo que no debes tener problemas para hacer la resta.

Dale un vistazo para ver si te sirve.

Saludos
Leo.
  #3 (permalink)  
Antiguo 20/11/2014, 03:54
 
Fecha de Ingreso: noviembre-2014
Mensajes: 4
Antigüedad: 9 años, 5 meses
Puntos: 0
Respuesta: Restar dos Count MySQL

Hola Leo!,

Gracias por tu respuesta, se ve que le has dedicado tiempo, perdona por no haberte dado la información completamente detallada, soy novato hasta para preguntar, jejeje.

Todo lo que has estado explicando lo entiendo ahora mejor, tienes razón y a su vez, no sabía como enlazar los left join en la consulta.

No soy un experto en bases de datos que digamos...voy sobreviviendo como puedo.

Voy a probar esto que me adjuntas y en tenerlo, te digo el resultado.

Mil gracias por tu esfuerzo.

Un saludo!
  #4 (permalink)  
Antiguo 20/11/2014, 05:09
 
Fecha de Ingreso: noviembre-2014
Mensajes: 4
Antigüedad: 9 años, 5 meses
Puntos: 0
Respuesta: Restar dos Count MySQL

Hola de nuevo!

Funciona perfectamente!

He adaptado la consulta a mis necesidades, ya que necesito sacar el resultado de restar Número de Facturas - Número de Abonos realizados para cada cliente.

La relación de las tablas es de la siguiente manera:

Tabla Ventas: ventas_id, ventas_id_cliente
Tabla Clientes: cliente_id, cliente_compania
Tabla Facturas: facturas_id, facturas_ventas_id
Tabla Abonos: abonos_id, abonos_cliente_id

La tabla Facturas para llegar al cliente, necesita a la tabla ventas*.

Por lo tanto he hecho una adaptación de lo que tu me has dado, para quitar los NULL, hacer la resta de los totales y ordenarlos por nombre de compañia y queda así:
Código SQL:
Ver original
  1. SELECT C.cliente_id, C.cliente_compania, F.total_facturas - A.total_abonos
  2.  FROM clientes C
  3.  LEFT JOIN ( SELECT ventas_id_cliente, COUNT(*) total_facturas
  4.              FROM facturas
  5.  INNER JOIN ventas ON ventas_id=factura_ventas_id
  6.              GROUP BY ventas_id_cliente) F ON C.cliente_id = F.ventas_id_cliente
  7.  LEFT JOIN (SELECT abonos_id_cliente, COUNT(*) total_abonos
  8.              FROM abonos
  9.              GROUP BY abonos_id_cliente) A ON C.cliente_id = A.abonos_id_cliente
  10. -- -------------------
  11. WHERE total_abonos IS NOT NULL AND total_facturas IS NOT NULL ORDER BY cliente_compania
  12. -- -------------------
Resultado:
[B]cliente_id | cliente_compania | Total
38 COMPAÑIA UNO 10
48 COMPAÑIA DOS 6
53 COMPAÑIA TRES 4
54 COMPAÑIA CUATRO 2
56 COMPAÑIA CINCO 21
......

Un saludo y gracias de nuevo!

Última edición por gnzsoloyo; 20/11/2014 a las 06:34 Razón: Legibilidad de codigo SQL

Etiquetas: count, join, restar, select, sql, tabla
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 08:14.