Oracle - Estas dos querys deberian ser iguales pero dan distinto resultado!

   
Vista:
Imágen de perfil de Sebastian

Estas dos querys deberian ser iguales pero dan distinto resultado!

Publicado por Sebastian (2 intervenciones) el 17/07/2015 15:26:09
Buenas!
Esto me da dos valores distintos para el debe y el haber

SELECT SUM(Importe) Haber FROM Recibo WHERE Anulado = 0 AND CodCliente= 2
SELECT SUM(Total) Debe FROM Factura WHERE CtaCte=1 AND CodEstadoFactura = 1 AND CodCliente= 2

Y cuando trato de unirlas en esta consulta, me da otro valor igual para debe y haber, pero distinto a los dos anteriores!

SELECT SUM(F.Total) Debe, SUM(R.Importe) Haber
FROM Factura F INNER JOIN Recibo R ON F.CodCLiente = R.CodCliente
WHERE F.CtaCte=1 AND F.CodEstadoFactura = 1 AND R.CodCliente= 2 AND R.Anulado = 0
GROUP BY R.CodCliente

Qué es lo que no estoy viendo??
Gracias!
Seba
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

Estas dos querys deberian ser iguales pero dan distinto resultado!

Publicado por leonardo_josue (44 intervenciones) el 17/07/2015 18:11:51
Hola Sebastían:

Este error es bastante típico entre los desarrolladores y se da porque tienes una relación muchos a muchos entre tus tablas, y quieres transformarla en una relación 1 a 1... veamos este caso, (voy a utilizar como BD's MySQL, pero el ejemplo es válido para cualquier DBMS). Supongamos que tenemos estos datos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
mysql> SELECT * FROM tabla1;
+------+-------------+-------+
| id_1 | descripcion | total |
+------+-------------+-------+
|    1 | haber 1.1   |     5 |
|    1 | haber 1.2   |    10 |
|    1 | haber 1.3   |     3 |
|    2 | haber 2.1   |     2 |
|    2 | haber 2.2   |    11 |
|    3 | haber 3.1   |     7 |
|    4 | haber 4.1   |     9 |
+------+-------------+-------+
7 rows in set (0.00 sec)
 
mysql> SELECT * FROM tabla2;
+------+-------------+-------+
| id_1 | descripcion | total |
+------+-------------+-------+
|    1 | debe 1.1    |     3 |
|    1 | debe 1.2    |     4 |
|    2 | debe 2.1    |     5 |
|    2 | debe 2.2    |     8 |
|    3 | debe 3.1    |    10 |
+------+-------------+-------+
5 rows in set (0.00 sec)

Si queremos encontrar el DEBE y el HABER de cada uno de los ID's, de manera separada, lo hacemos así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mysql> SELECT id_1, SUM(total) total_haber
    -> FROM tabla1
    -> GROUP BY id_1;
+------+-------------+
| id_1 | total_haber |
+------+-------------+
|    1 |          18 |
|    2 |          13 |
|    3 |           7 |
|    4 |           9 |
+------+-------------+
4 rows in set (0.00 sec)
 
mysql> SELECT id_1, SUM(total) total_debe
    -> FROM tabla2
    -> GROUP BY id_1;
+------+------------+
| id_1 | total_debe |
+------+------------+
|    1 |          7 |
|    2 |         13 |
|    3 |         10 |
+------+------------+
3 rows in set (0.00 sec)

Pero al hacer el INNER JOIN y querer obtener ambos valores en una sola consulta, obtenemos lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
mysql> SELECT t1.id_1, SUM(t1.total) total_haber, SUM(t2.total) total_debe
    -> FROM tabla1 t1
    -> LEFT JOIN tabla2 t2 ON t1.id_1 = t2.id_1
    -> GROUP BY T1.id_1;
+------+-------------+------------+
| id_1 | total_haber | total_debe |
+------+-------------+------------+
|    1 |          36 |         21 |
|    2 |          26 |         26 |
|    3 |           7 |         10 |
|    4 |           9 |       NULL |
+------+-------------+------------+
4 rows in set (0.06 sec)

Para los ID's 3 y 4 los resultados son correctos pero para los ID's 1 y 2 no lo son... ¿por qué pasa esto? como te comenté al inicio, es porque tienes una relación muchos a muchos, observa que pasa cuando haces el JOIN sin el SUM ni la agrupación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mysql> SELECT *
    -> FROM tabla1 t1
    -> LEFT JOIN tabla2 t2 ON t1.id_1 = t2.id_1;
+------+-------------+-------+------+-------------+-------+
| id_1 | descripcion | total | id_1 | descripcion | total |
+------+-------------+-------+------+-------------+-------+
|    1 | haber 1.1   |     5 |    1 | debe 1.1    |     3 |
|    1 | haber 1.2   |    10 |    1 | debe 1.1    |     3 |
|    1 | haber 1.3   |     3 |    1 | debe 1.1    |     3 |
|    1 | haber 1.1   |     5 |    1 | debe 1.2    |     4 |
|    1 | haber 1.2   |    10 |    1 | debe 1.2    |     4 |
|    1 | haber 1.3   |     3 |    1 | debe 1.2    |     4 |
|    2 | haber 2.1   |     2 |    2 | debe 2.1    |     5 |
|    2 | haber 2.2   |    11 |    2 | debe 2.1    |     5 |
|    2 | haber 2.1   |     2 |    2 | debe 2.2    |     8 |
|    2 | haber 2.2   |    11 |    2 | debe 2.2    |     8 |
|    3 | haber 3.1   |     7 |    3 | debe 3.1    |    10 |
|    4 | haber 4.1   |     9 | NULL | NULL        |  NULL |
+------+-------------+-------+------+-------------+-------+
12 rows in set (0.01 sec)

Observa que para los ID's 1 y 2 se genera una especie de Producto Cartesiano con cada elemento de la tabla2, es por eso que las cantidades ya no coinciden, ¿qué es lo que debes hacer? primero utilizar las consultas que pones al inicio para dejar sólo 1 id en cada una de las tablas y entonces hacer el JOIN... en otras palabras, pasas de una relación muchos a muchos a una relación 1 a 1, sería más o menos así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> SELECT T1.id_1, T1.total_haber, T2.total_debe
    -> FROM ( SELECT id_1, SUM(total) total_haber
    ->        FROM tabla1
    ->        GROUP BY id_1) T1
    -> LEFT JOIN
    ->      ( SELECT id_1, SUM(total) total_debe
    ->        FROM tabla2
    ->        GROUP BY id_1) T2
    -> ON T1.id_1 = T2.id_1;
+------+-------------+------------+
| id_1 | total_haber | total_debe |
+------+-------------+------------+
|    1 |          18 |          7 |
|    2 |          13 |         13 |
|    3 |           7 |         10 |
|    4 |           9 |       NULL |
+------+-------------+------------+
4 rows in set (0.00 sec)

Dale un vistazo y coméntanos si te sirve el código.

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
Imágen de perfil de Sebastian

Estas dos querys deberian ser iguales pero dan distinto resultado!

Publicado por Sebastian (2 intervenciones) el 17/07/2015 19:09:19
Leo, muchísimas gracias, diste en el clavo. Creo que ya me tenía tan loco que el árbol me tapaba el bosque.
Con algo así
SELECT T1.CodCliente, T2.Debe - T1.Haber Deuda
FROM
(SELECT CodCliente, SUM(Importe) Haber FROM Recibo WHERE Anulado = 0 GROUP BY CodCLiente) T1
INNER JOIN
(SELECT CodCliente, SUM(Total) Debe FROM Factura WHERE CtaCte=1 AND CodEstadoFactura = 1 GROUP BY CodCLiente) T2
ON T1.CodCliente = T2.CodCliente
Anduvo perfecto, ahora la debo optimizar para el reporte.
Muchas gracias de nuevo!
Sebastián
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Estas dos querys deberian ser iguales pero dan distinto resultado!

Publicado por leonardo_josue (44 intervenciones) el 17/07/2015 21:10:47
Hola de nuevo Sebastian:

Sólo un comentario al margen, desde mi punto de vista, es mejor utilizar LEFT JOIN que INNER JOIN... este es para el caso de elementos que tengan miembros sólo en una de las tablas... típicamente se da con compras/ventas recientes, en donde existe una factura, pero no hay aun pagos registrados... en mi ejemplo el ID 4 es este caso, hay un elemento en la tablas de los HABER, sin embargo, no hay elementos en la tabla de DEBE... si utilizas un INNER JOIN, este registro NO APARECERÍA, pues es mandatorio que existan registros en ambas tablas.

Me da gusto que te haya servido la consulta.

Saludos
Leo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar