Ver Mensaje Individual
  #5 (permalink)  
Antiguo 25/03/2012, 07:54
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, 4 meses
Puntos: 2658
Respuesta: limit en left join

No es exactamente que esté "jodido", sino que para darte una propuesta hay que depurar bastante la consulta que haces, y eso hay que explicártelo paso a paso para que se entienda bien.
Empecemos por ver tu consulta (un poco mejor escrita):
Código MySQL:
Ver original
  1.     clientes
  2.     LEFT JOIN categorias CL ON CL.cl_categoria_id = CAT.c_id
  3.     LEFT JOIN canales CA ON CL.cl_canal_id = CA.ca_id
  4.     LEFT JOIN zonas ZO ON CL.cl_prov_id = ZO.z_id
  5.     LEFT JOIN operadores OP ON CL.cl_operador_id LIKE OP.o_id
  6.     LEFT JOIN usuarios US ON CL.cl_merchandiser = US.u_id
  7.     LEFT JOIN
  8.         (SELECT *, IF(datos.d_semana=$s,'SI','NO') hay
  9.         FROM datos
  10.         WHERE DA.d_semana='$s') DA  ON CL.cl_id=DA.d_cliente  
  11.     CL.cl_merchandiser='$elmercha'  
  12. GROUP BY clientes.cl_id
  13. ORDER BY $orden

Algunas de las cosas que se pueden considerar:
- El uso de LEFT JOIN indiscriminadamente como estás haciendo, sin que un resultado se relacione con otro (son lógicamente independientes), tiende a generar productos cartesianos.
- Si las relaciones son mandatorias, deberías usar INNER JOIN, y relacionar el resultado de un subconjunto al INNER JOIN siguiente.
- Hacer una subconsulta como tabla origen, pero poner una condición binaria de esa misma por fuera (d_semana='$s'), no tiene sentido. Para eso la pones por dentro de la subconsulta, donde será mas eficiente.
- Usas GROUP BY sin funciones agregadas, lo que es ineficiente por un lado, y posiblemente innecesario por otra. SI el objetivo es que devuelva un sólo registro por cada cliente, lo primero que debes asegurarte es que no se estén generando productos cartesianos por errores de JOIN, y no hacer un GROUP BY que al MySQL le insume mucho tiempo (y mucho más si hay P.C.).
- Por lo que dices el objeto final es obtener a los usuarios y verificar si para una semana dada existen o no datos relacionados. Para lograr eso no se ve necesario el uso de ninguna otra tabla que no sean Usuarios y Datos. Si esto es porque estás "refritando" una consulta diseñada para otro propósito a fin de lograr el resultado, eso es una pésima idea. Que dos conjuntos de resultados se parezcan, no implica que se usen las mismas consultas.
- Un JOIN no se usa con LIKE en el ON. Además, si lo que usas es el dato como lo planteas, sin comodines, sin búsqueda de patrones, resulta igual que usar "=", por lo que no tiene ningún sentido.
- Resolver las consultas en bucles (loops) es una soberana tontería, propia de programadores, pero no es una solución práctica en Bases de Datos. En BBDD sólo se usan bucles como último recurso, o bien por requerimientos específicos del sistema.

Vamos a hacer una aproximación.
- Primero define qué campos de necesitas realmente de cada tabla. Francamente no creo que necesites mostrar todos los datos de cada uno, especialmente porque el "*" te traerá información duplicada. No te olvides que una de las reglas de las consultas eficientes dice que no se debe pedir información que no sea estrictamente necesaria. Todo dato de más, son bytes basura en la transmisión de datos.
+ ¿Qué datos utilizarás de la tabla Clientes?
+ ¿Qué necesitas de Usuarios, Categoría, Zona y Canal?
+ ¿Para qué datos requieres la tabla Operadores?

- En segundo lugar, dinos cuáles son las relaciones mandatorias, es decir, que relaciones deben existir si o si en esa base:
+ ¿Todos los clientes tienen que tener categoría?
+ ¿Todos los clientes tienen un canal?
+ ¿Todos los clientes tienen una zona?
+ ¿A cada cliente le corresponde un único usuario?
+ ¿A cada cliente le está asignado un único operador?

Suponiendo que todos los JOIN fuesen mandatorios, la sentencia se debería parecer a esto:

Código MySQL:
Ver original
  1.     clientes
  2.     INNER JOIN categorias CL ON CL.cl_categoria_id = CAT.c_id
  3.     INNER JOIN canales CA ON CL.cl_canal_id = CA.ca_id
  4.     INNER JOIN zonas ZO ON CL.cl_prov_id = ZO.z_id
  5.     INNER JOIN usuarios US ON CL.cl_merchandiser = US.u_id
  6.     INNER JOIN
  7.         (SELECT d_cliente, IF(datos.d_semana=$s,'SI','NO') hay
  8.         FROM datos
  9.         WHERE DA.d_semana='$s') DA  ON CL.cl_id = DA.d_cliente  
  10.     LEFT JOIN operadores OP ON CL.cl_operador_id = OP.o_id
  11.     CL.cl_merchandiser='$elmercha'  
  12. GROUP BY clientes.cl_id
  13. ORDER BY $orden

Por favor, contesta las preguntas de una forma precisa.
No nos des generalidades porque las generalidades no sirven para casos como el tuyo. Trata de ser concreto.

Saludos.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)