Ver Mensaje Individual
  #2 (permalink)  
Antiguo 11/05/2012, 21:05
Avatar de gnzsoloyo
gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 5 meses
Puntos: 2658
Respuesta: Orden en Select

Mira, lo primero que tienes que tratar de hacer es ordenar la consulta, porque así como la escribes es inentendible.
Primero estructuremos la cosa:
Código MySQL:
Ver original
  1.     publicaciones.*,
  2.     tipopublicaciones.destagen,
  3.     tipopublicaciones.destasec,
  4.     paises.nombre as nompai,
  5.     provincias.nombre as nompro,
  6.     localidades.nombre as nomloc,
  7.     usuarios.usuario as codusu,
  8.     usuarios.nombre as nomusu,
  9.     tipomonedas.simbolo as moneda,
  10.     tipoarticulos.nombre as nomtar,
  11.     publicaciones.cantidad-sum(if(compras.cantidad is not null,compras.cantidad,0)) as quedan,
  12.     sum(if(compras.cantidad is not null,compras.cantidad,0)) as vendido,
  13.     sum(if(tipomovimientos.signo='+', importe,if(tipomovimientos.signo='-',importe*-1,0))) as saldo
  14.     publicaciones
  15.     left join tipopublicaciones on tipopublicaciones.idtipopublicacion=publicaciones.idtipopublicacion
  16.     left join usuarios on usuarios.idusuario = publicaciones.idusuario
  17.     left join tipomonedas on tipomonedas.idtipomoneda = publicaciones.idtipomoneda
  18.     left join tipoarticulos on tipoarticulos.idtipoarticulo=publicaciones.idtipoarticulo
  19.     left join paises on paises.idpais=publicaciones.idpais
  20.     left join provincias on provincias.idprovincia=publicaciones.idprovincia
  21.     left join localidades on localidades.idlocalidad=publicaciones.idlocalidad
  22.     left join compras on compras.idpublicacion=publicaciones.idpublicacion
  23.     left join cuentacorriente on cuentacorriente.idusuario=publicaciones.idusuario
  24.     left join tipomovimientos on tipomovimientos.idtipomovimiento=cuentacorriente.idtipomovimiento
Aquí lo que se ve es que no has aprendido a usar alias para tablas, por lo que resulta algo difícil seguir la lógica aplicada.
Depuremos:
Código MySQL:
Ver original
  1.     P.*,
  2.     TP.destagen,
  3.     TP.destasec,
  4.     PA.nombre nompai,
  5.     PR.nombre nompro,
  6.     LC.nombre nomloc,
  7.     US.usuario codusu,
  8.     US.nombre nomusu,
  9.     TM.simbolo moneda,
  10.     TA.nombre  nomtar,
  11.     p.cantidad-sum(IF(CO.cantidad IS NOT NULL,CO.cantidad,0)) quedan,
  12.     SUM(IF(CO.cantidad IS NOT NULL,CO.cantidad,0)) vendido,
  13.     SUM(IF(TM.signo='+', importe, IF(TM.signo = '-',importe* - 1, 0))) saldo
  14.     publicaciones P
  15.     LEFT JOIN tipopublicaciones TP  ON P.idtipopublicacion  =   TP.idtipopublicacion
  16.     LEFT JOIN usuarios US           ON P.idusuario          =   US.idusuario
  17.     LEFT JOIN tipomonedas TM        ON P.idtipomoneda       =   TM.idtipomoneda
  18.     LEFT JOIN tipoarticulos TA      ON P.idtipoarticulo     =   TA.idtipoarticulo
  19.     LEFT JOIN paises PA             ON P.idpais             =   PA.idpais
  20.     LEFT JOIN provincias PR         ON P.idprovincia        =   PR.idprovincia
  21.     LEFT JOIN localidades LC        ON P.idlocalidad        =   LC.idlocalidad
  22.     LEFT JOIN compras CO            ON P.idpublicacion      =   CO.idpublicacion
  23.     LEFT JOIN cuentacorriente CC    ON P.idusuario          =   CC.idusuario
  24.     LEFT JOIN tipomovimientos TM    ON CC.idtipomovimiento  =   TM.idtipomovimiento
Ahora podemos mirar un poco mejor lo que hay.

Lo primero que se puede observar es que estás definiendo todas las relaciones como opcionales, es decir, lo único seguro es que existe una publicación, que puede tener un tipo, puede corresponder a un usuario, puede tener un precio expresado en un tipo de moneda, puede tener un tipo de articulo, etc.
¿Realmente son todas opcionales? ¿No hay ninguna mandatoria?
Pregunto porque las mandatorias (obligatorias) se plantean con INNER JOIN, y no con LEFT JOIN. Eso simplifica mucho la consulta.
Por otro lado, en tu esquema original estás poniendo mal el ON de las tablas. Cuando usas el LEFT JOIN debes poner primero la tabla base (la que no es nula jamás) y luego la dependiente. En este caso el orden de los factores si altera el producto.
Además de eso, estás agrupando por un sólo campo, cuando en realidad deberías agrupar por todos los que no están afectados por la función (SUM()).
Si bien MySQL admite que se agrume por menos campos que los no afectados por funciones, eso si lo haces el resultado puede ser errático, ya que en los otros campos sólo dejará el primer valor que encuentre en el primer registro, escondiendo cualquier otro tipo de agrupamiento.

Finalmente, las sumas como las estás planteando, no están bien hechas. al menos en un caso estás sumando un valor simple contra el de un agrupamiento, con lo que la operación aritmética puede estar generando (y eso creo que es lo que te pasa) un producto cartesiano. Es decir: Está aplicando la suma a cada uno de los registros que suma, y no al total.
En esencia, lo que te conviene hacer es que el cálculo de suma se haga en una subconsulta que devuelva una tabla virtual en el FROM, y luego con esa tabla derivada haces el resto de los JOIN.
¿Se entiende la idea?
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)