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

Orden en Select

Estas en el tema de Orden en Select en el foro de Mysql en Foros del Web. Buenas Noches Tengo un problema con una 'select' en al cual hay varios 'left join', para generar sumas, todos funcionan bien pero el compras no, ...
  #1 (permalink)  
Antiguo 11/05/2012, 16:49
Usuario no validado
 
Fecha de Ingreso: abril-2009
Ubicación: Buenos Aires
Mensajes: 413
Antigüedad: 15 años
Puntos: 3
Orden en Select

Buenas Noches

Tengo un problema con una 'select' en al cual hay varios 'left join', para generar sumas, todos funcionan bien pero el compras no, las que tienen 1 compra da 40, sin compras da 0.
Funciona OK cuando saco el 'left join cuentacorriente', JUSTO SE DA QUE 40 ES LA CANTIDAD DE REGISTROS QUE TENGO CON MI 'IDUSUARIO' EN 'CUENTACORRIENTE', puede tener que ver??

Les paso el código, es un poco extenso:

select publicaciones.*,tipopublicaciones.destagen,tipopub licaciones.destasec,paises.nombre as nompai,provincias.nombre as nompro,localidades.nombre as nomloc,usuarios.usuario as codusu,usuarios.nombre as nomusu,tipomonedas.simbolo as moneda,tipoarticulos.nombre as nomtar,publicaciones.cantidad-sum(if(compras.cantidad is not null,compras.cantidad,0)) as quedan,sum(if(compras.cantidad is not null,compras.cantidad,0)) as vendido,sum(if(tipomovimientos.signo='+',importe,i f(tipomovimientos.signo='-',importe*-1,0))) as saldo from publicaciones left join tipopublicaciones on tipopublicaciones.idtipopublicacion=publicaciones. idtipopublicacion left join usuarios on usuarios.idusuario=publicaciones.idusuario left join tipomonedas on tipomonedas.idtipomoneda=publicaciones.idtipomoned a left join tipoarticulos on tipoarticulos.idtipoarticulo=publicaciones.idtipoa rticulo left join paises on paises.idpais=publicaciones.idpais left join provincias on provincias.idprovincia=publicaciones.idprovincia left join localidades on localidades.idlocalidad=publicaciones.idlocalidad left join compras on compras.idpublicacion=publicaciones.idpublicacion left join cuentacorriente on cuentacorriente.idusuario=publicaciones.idusuario left join tipomovimientos on tipomovimientos.idtipomovimiento=cuentacorriente.i dtipomovimiento group by 1;

Muy Agradecido si pueden ayudarme.
  #2 (permalink)  
Antiguo 11/05/2012, 21:05
Avatar de 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, 4 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)
  #3 (permalink)  
Antiguo 12/05/2012, 14:28
Usuario no validado
 
Fecha de Ingreso: abril-2009
Ubicación: Buenos Aires
Mensajes: 413
Antigüedad: 15 años
Puntos: 3
Respuesta: Orden en Select

Sii!!, me parece que estoy entendiendo lo que me escribiste, voy a empezar a ponerlo en práctica y te voy comentando como voy, Muchas Gracias por esta gran desinteresada explicación, me es muy util.
  #4 (permalink)  
Antiguo 14/05/2012, 11:18
Usuario no validado
 
Fecha de Ingreso: abril-2009
Ubicación: Buenos Aires
Mensajes: 413
Antigüedad: 15 años
Puntos: 3
Respuesta: Orden en Select

GNZSOLOYO Buenas Tardes,
Amigo estoy aprolijándolo y llegue a esto por ahora:

SELECT
P.*,
TP.destagen,
TP.destasec,
PA.nombre AS nompai,
PR.nombre nompro,
LC.nombre nomloc,
US.usuario codusu,
US.nombre nomusu,
TM.simbolo moneda,
TA.nombre nomtar,
p.cantidad-sum(IF(CO.cantidad IS NOT NULL,CO.cantidad,0)) quedan,
SUM(IF(CO.cantidad IS NOT NULL,CO.cantidad,0)) vendido,
SUM(IF(TV.signo='+', importe, IF(TV.signo = '-',importe* - 1, 0))) saldo
FROM
publicaciones P
INNER JOIN tipopublicaciones TP ON P.idtipopublicacion = TP.idtipopublicacion
INNER JOIN usuarios US ON P.idusuario = US.idusuario
INNER JOIN tipomonedas TM ON P.idtipomoneda = TM.idtipomoneda
INNER JOIN tipoarticulos TA ON P.idtipoarticulo = TA.idtipoarticulo
INNER JOIN paises PA ON P.idpais = PA.idpais
INNER JOIN provincias PR ON P.idprovincia = PR.idprovincia
INNER JOIN localidades LC ON P.idlocalidad = LC.idlocalidad
LEFT JOIN compras CO ON P.idpublicacion = CO.idpublicacion
LEFT JOIN cuentacorriente CC ON P.idusuario = CC.idusuario
INNER JOIN tipomovimientos TV ON CC.idtipomovimiento = TV.idtipomovimiento
GROUP BY 1,2,3,4,5,6,7,8,9,10,11;

No entiendo bien el tema de las subconsulta para las sumas, sería casi lo mismo ya que suma dependiendo de la cantidad vendida para esa publicación o del signo de tipo del movimiento.
El problema esta en el VENDIDO que arrastra al QUEDAN.

Donde pondría el SELECT SUM(IF(CO.cantidad IS NOT NULL,CO.cantidad,0)) vendido FROM compras WHERE idpublicacion=p.idpublicacion.

Si es posible te agradecería me guies un poco mas.
Muchas Gracias
  #5 (permalink)  
Antiguo 15/05/2012, 14:22
Avatar de fahs82  
Fecha de Ingreso: abril-2012
Ubicación: guadalajara
Mensajes: 139
Antigüedad: 12 años
Puntos: 12
Respuesta: Orden en Select

para obtener las sumas el join lo pones seguido de una subconsulta para obtener la suma seria algo asi inner join (consulta select sum()) as totalardex

un ejemplo sencillo seria un select asi

select t1.vendedor,t2.devoluciones from vendedores as t1 inner join(select sum(cantidad)) as devoluciones from tabla_devoluciones group by vendedor as t2

espero que con este ejemplo sencillo te de una idea y puedas aplicarlo a tu consulta suerte

Última edición por fahs82; 15/05/2012 a las 14:28
  #6 (permalink)  
Antiguo 15/05/2012, 14:54
Usuario no validado
 
Fecha de Ingreso: abril-2009
Ubicación: Buenos Aires
Mensajes: 413
Antigüedad: 15 años
Puntos: 3
Respuesta: Orden en Select

La verdad no se porque no anda, ahora quedo asi:

select pu.idpublicacion,
(select sum(ifnull(cantidad,0)) from compras co where pu.idpublicacion=co.idpublicacion)
from publicaciones as pu

Cuando no tiene registros en compras suma null, teoricamente debería sumar 0

Gracias si pueden ayudarme
  #7 (permalink)  
Antiguo 15/05/2012, 15:10
Avatar de 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, 4 meses
Puntos: 2658
Respuesta: Orden en Select

El IFNULL() debe encerrar al SUM(), no al revés.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #8 (permalink)  
Antiguo 15/05/2012, 15:35
Usuario no validado
 
Fecha de Ingreso: abril-2009
Ubicación: Buenos Aires
Mensajes: 413
Antigüedad: 15 años
Puntos: 3
Respuesta: Orden en Select

Muchas Gracias, funciono perfecto!!

Etiquetas: join, orden, registros, select
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 06:19.