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

Consulta Select "compleja"

Estas en el tema de Consulta Select "compleja" en el foro de Mysql en Foros del Web. Estimados, como andan ? Hace unos días estoy rompiendome la cabeza con una consulta que no puedo hacer andar; seguramente es algo simple... pero no ...
  #1 (permalink)  
Antiguo 14/11/2017, 09:05
Avatar de bacc  
Fecha de Ingreso: febrero-2009
Ubicación: Argentina
Mensajes: 33
Antigüedad: 11 años
Puntos: 1
Pregunta Consulta Select "compleja"

Estimados, como andan ?

Hace unos días estoy rompiendome la cabeza con una consulta que no puedo hacer andar; seguramente es algo simple... pero no le encuentro la vuelta.. acá les explico:

Tengo una tabla con estos campos, lo que necesito es extraer lo que dejo acá abajo

id / id_padre / id_informatica / nivel
1 3 1 3
2 3 9 3

Por cada persona (id_padre) hay un rubro de informatica (id_informatica) que a su vez tiene un nivel del 1 al 3 (nivel)

Yo necesito que me traiga las personas que tengan id_informatica en 1 y en 9; y no los que solo tengan 1 o 9...tienen que cumplir ambas condiciones (y cumplir con el nivel).

Si yo hago:

SELECT * FROM <TABLA>
WHERE
(id_informatica='1' AND nivel>='2')
AND
(id_informatica='9' AND nivel>='1')

no me devuelve nada; y si uso OR, me trae los que tienen una sola condición...

Alguien puede darme una mano ? GRACIAS!!
  #2 (permalink)  
Antiguo 14/11/2017, 09:21
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 13 años, 1 mes
Puntos: 447
Respuesta: Consulta Select "compleja"

Hola Bacc:

Tal como tienes tu consulta, es imposible que te arroje resultados, ya que al utilizar sólo el operador AND estás poniendo el equivalente a decir que quieres una camisa negra que al mismo tiempo sea blanca

por lo tanto, es necesario que utilices el operador OR, pero con un pequeño "truco" veamos el ejemplo. Supongamos que tienes esta tabla;

Código MySQL:
Ver original
  1. mysql> SELECT * FROM tabla;
  2. +------+----------+----------------+-------+
  3. | id   | id_padre | id_informatica | nivel |
  4. +------+----------+----------------+-------+
  5. |    1 |        3 |              1 |     3 |
  6. |    2 |        3 |              9 |     3 |
  7. |    3 |        4 |              1 |     3 |
  8. |    4 |        5 |              9 |     3 |
  9. |    5 |        6 |              2 |     3 |
  10. |    6 |        7 |              3 |     3 |
  11. +------+----------+----------------+-------+
  12. 6 rows in set (0.00 sec)

entonces, si utilizamos el operador OR, tenemos esto:

Código MySQL:
Ver original
  1. mysql> SELECT *
  2.     -> FROM tabla
  3.     -> WHERE
  4.     -> (id_informatica = 1 AND nivel >= 2)
  5.     -> OR
  6.     -> (id_informatica = 9 AND nivel >= 1);
  7. +------+----------+----------------+-------+
  8. | id   | id_padre | id_informatica | nivel |
  9. +------+----------+----------------+-------+
  10. |    1 |        3 |              1 |     3 |
  11. |    2 |        3 |              9 |     3 |
  12. |    3 |        4 |              1 |     3 |
  13. |    4 |        5 |              9 |     3 |
  14. +------+----------+----------------+-------+
  15. 4 rows in set (0.03 sec)

ya que los id's 5 y 6 no tienen los id_informática 1 y 9 que te interesan... sin embargo, el ID 4 y el ID 5 sólo tienen uno cada uno de ellos...

¿Qué pasaría si haces un COUNT() de las veces que aparece el id_padre en esta lista?, resultaría que para el ID=3 el COUNT sería = 2, mientras que para los ID's 4 y 5 sería de 1 cierto?

LUEGO ENTONCES, puedes utilizar FILTRAR este COUNT para que sólo te muestre aquellos que tienen un COUNT() = 2. (recuerda que para filtrar un COUNT utilizas la cláusula HAVING).

Haz la prueba y nos comentas.

Saludos
Leo.
  #3 (permalink)  
Antiguo 14/11/2017, 14:52
Avatar de bacc  
Fecha de Ingreso: febrero-2009
Ubicación: Argentina
Mensajes: 33
Antigüedad: 11 años
Puntos: 1
Respuesta: Consulta Select "compleja"

Hola Leo, gracias por tomarte tu tiempo en responder !

En parte me sirvió, en parte no.

Si analizo la consulta "sola" esta bárbaro y lo solucione quedando asi:
Código MySQL:
Ver original
  1. SELECT *, COUNT(id_padre) as cant
  2.  
  3.  WHERE (id_informatica='1' AND nivel>='1') OR (id_informatica='9' AND nivel>='1')
  4.  GROUP BY id_padre
  5.  HAVING COUNT(cant) >= 2

Peeeero (siempre hay un pero ja) esta consulta es un poco mas complicada y no quería marearlos con toda la consulta; por eso solo puse un pedazo. La consulta completa es esta:

Código MySQL:
Ver original
  1. SELECT DISTINCT(usrs.id)
  2.  FROM usrs
  3.  LEFT JOIN usrs_p1 ON usrs.id= usrs_p1.id_padre LEFT JOIN usrs_p2 ON usrs.id= usrs_p2.id_padre LEFT JOIN usrs_p3 ON usrs.id= usrs_p3.id_padre LEFT JOIN usrs_p4 ON usrs.id= usrs_p4.id_padre LEFT JOIN usrs_p5 ON usrs.id= usrs_p5.id_padre LEFT JOIN usrs_p6 ON usrs.id= usrs_p6.id_padre LEFT JOIN usrs_p7 ON usrs.id= usrs_p7.id_padre LEFT JOIN usrs_p8 ON usrs.id= usrs_p8.id_padre LEFT JOIN usrs_p9 ON usrs.id= usrs_p9.id_padre LEFT JOIN usrs_p10 ON usrs.id= usrs_p10.id_padre LEFT JOIN usrs_p11 ON usrs.id= usrs_p11.id_padre
  4.  WHERE (usrs_p7.id_informatica='1' AND usrs_p7.nivel>='1') AND (usrs_p7.id_informatica='9' AND usrs_p7.nivel>='1')
  5.  ORDER BY usrs.lastlogin DESC LIMIT 50

Son unas 11 tablas anidadas (cada tabla tiene distinto tipo de info). En este caso aplica solo a la tabla p7 (tengo que hacer algo similar para la p6).

Quiero sacarme dos dudas,
1. Es malo, bueno, o da igual que los datos esten distribuidos en distintas tablas ? (para futuros proyectos)
2. Que tan complicado sería llevar lo que me pasaste a esa consulta con JOIN?

En este punto mis conocimientos de MySQL no son tan profundos para saber como "separar" dentro de un JOIN.
Mi fuerte es la programación, así que voy a ver de hacer lo que me dijiste y el validador de COUNT lo hago a través de PHP.

Desde ya mil gracias!!
  #4 (permalink)  
Antiguo 14/11/2017, 15:04
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 13 años, 6 meses
Puntos: 774
Respuesta: Consulta Select "compleja"

Se aplicaria la misma logica, no importa si tienes una, 2, 3 4 5 tablas en tu join, seria algo asi:


Código MySQL:
Ver original
  1. SELECT DISTINCT(usrs.id), count(usrs.id) as cant
  2.  FROM usrs
  3.  LEFT JOIN usrs_p1 ON usrs.id= usrs_p1.id_padre LEFT JOIN usrs_p2 ON usrs.id= usrs_p2.id_padre LEFT JOIN usrs_p3 ON usrs.id= usrs_p3.id_padre LEFT JOIN usrs_p4 ON usrs.id= usrs_p4.id_padre LEFT JOIN usrs_p5 ON usrs.id= usrs_p5.id_padre LEFT JOIN usrs_p6 ON usrs.id= usrs_p6.id_padre LEFT JOIN usrs_p7 ON usrs.id= usrs_p7.id_padre LEFT JOIN usrs_p8 ON usrs.id= usrs_p8.id_padre LEFT JOIN usrs_p9 ON usrs.id= usrs_p9.id_padre LEFT JOIN usrs_p10 ON usrs.id= usrs_p10.id_padre LEFT JOIN usrs_p11 ON usrs.id= usrs_p11.id_padre
  4.  WHERE (usrs_p7.id_informatica='1' AND usrs_p7.nivel>='1') AND (usrs_p7.id_informatica='9' AND usrs_p7.nivel>='1')
  5. group by usrs.id
  6. having (count) cant>=2
  7.  ORDER BY usrs.lastlogin DESC LIMIT 50

Lo mejor es tener los datos separados en varias tablas, siempre y cuando se cumplan las reglas de normalizacion(en donde han leido que tener muchas tablas es malo???)

P.D: Donde esta lo complicado de la consulta?
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #5 (permalink)  
Antiguo 14/11/2017, 15:16
Avatar de bacc  
Fecha de Ingreso: febrero-2009
Ubicación: Argentina
Mensajes: 33
Antigüedad: 11 años
Puntos: 1
Respuesta: Consulta Select "compleja"

libras, gracias por responderme.

Te comento que lo único complicado es mi bajo nivel de mysql je

Por otro lado, la consulta tal cual la planteas me da error:

Query: SELECT DISTINCT(usrs.id), count(usrs.id) as cant FROM usrs LEFT JOIN usrs_p1 ON usrs.id= usrs_p1.id_padre LEFT JOIN usrs_p2 ON u...

Error Code: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'cant>=2
ORDER BY usrs.lastlogin DESC LIMIT 50

Por otro lado, si le saco el having deja de dar error, pero me devuelve esto:

id cant
------ --------
563 3
142 12
475 3
901 56
84 8
1168 2
886 4
468 27
927 4
61 12
181 10
1170 1
974 24
1138 24
25 12
1167 2
878 8
773 18
1165 6
542 2
1160 504

No entiendo que me devuelve. Porque el contador máximo tiene que ser de 3 o 4 (conocimientos informáticos)

Voy a aclarar por las dudas; el sistema recibe un formulario y a medida que van completando los campos va filtrando (ej, estado civil; si esta completo agrega el WHERE correspondiente y va armando la consulta); el problema se me planteo cuando necesité poder pedir dos conocimientos informáticos (en lugar de uno).
  #6 (permalink)  
Antiguo 14/11/2017, 15:33
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 13 años, 6 meses
Puntos: 774
Respuesta: Consulta Select "compleja"

Prueba con esto
Código MySQL:
Ver original
  1. SELECT DISTINCT(usrs.id), count(campo_conocimientos_informaticos) as cant
  2.  FROM usrs
  3.  LEFT JOIN usrs_p1 ON usrs.id= usrs_p1.id_padre LEFT JOIN usrs_p2 ON usrs.id= usrs_p2.id_padre LEFT JOIN usrs_p3 ON usrs.id= usrs_p3.id_padre LEFT JOIN usrs_p4 ON usrs.id= usrs_p4.id_padre LEFT JOIN usrs_p5 ON usrs.id= usrs_p5.id_padre LEFT JOIN usrs_p6 ON usrs.id= usrs_p6.id_padre LEFT JOIN usrs_p7 ON usrs.id= usrs_p7.id_padre LEFT JOIN usrs_p8 ON usrs.id= usrs_p8.id_padre LEFT JOIN usrs_p9 ON usrs.id= usrs_p9.id_padre LEFT JOIN usrs_p10 ON usrs.id= usrs_p10.id_padre LEFT JOIN usrs_p11 ON usrs.id= usrs_p11.id_padre
  4.  WHERE (usrs_p7.id_informatica='1' AND usrs_p7.nivel>='1') AND (usrs_p7.id_informatica='9' AND usrs_p7.nivel>='1')
  5. group by usrs.id
  6. having count (cant)>=2
  7.  ORDER BY usrs.lastlogin DESC LIMIT 50

Te da mas numeros porque estoy contando los diferentes usuarios, no se cual es el campo que necesitas contar, yo puse ese nada mas para ejemplo
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #7 (permalink)  
Antiguo 14/11/2017, 15:45
Avatar de bacc  
Fecha de Ingreso: febrero-2009
Ubicación: Argentina
Mensajes: 33
Antigüedad: 11 años
Puntos: 1
Respuesta: Consulta Select "compleja"

Nop, me da error en el having y si se lo saco me da cualquier numero...

Lo más "cerca" que estoy es con esto :

Código MySQL:
Ver original
  1. SELECT DISTINCT(usrs.id), usrs_p7.id_padre, usrs_p7.id_informatica, usrs_p7.nivel
  2.  FROM usrs LEFT JOIN usrs_p1 ON usrs.id= usrs_p1.id_padre LEFT JOIN usrs_p2 ON usrs.id= usrs_p2.id_padre LEFT JOIN usrs_p3 ON usrs.id= usrs_p3.id_padre LEFT JOIN usrs_p4 ON usrs.id= usrs_p4.id_padre LEFT JOIN usrs_p5 ON usrs.id= usrs_p5.id_padre LEFT JOIN usrs_p6 ON usrs.id= usrs_p6.id_padre LEFT JOIN usrs_p7 ON usrs.id= usrs_p7.id_padre LEFT JOIN usrs_p8 ON usrs.id= usrs_p8.id_padre LEFT JOIN usrs_p9 ON usrs.id= usrs_p9.id_padre LEFT JOIN usrs_p10 ON usrs.id= usrs_p10.id_padre LEFT JOIN usrs_p11 ON usrs.id= usrs_p11.id_padre
  3.  WHERE (usrs_p7.id_informatica='1' AND usrs_p7.nivel>='1') OR (usrs_p7.id_informatica='9' AND usrs_p7.nivel>='1')

Devuelve esto:

id id_padre id_informatica nivel
------ -------- -------------- --------
3 3 1 3
3 3 9 3
4 4 1 3
7 7 1 3
8 8 9 2
6 6 1 3
9 9 1 3
6 6 9 3

Acá me interesa extraer los que cumplen la condición del valor id_padre (o id) 3 ; donde esta el id_informatica 1 y también el 9.

Pero hay que tener en cuenta que en el WHERE se le pueden agregar otras AND (por ej de estado civil) que no deberían interferir.

Se entiende ?
  #8 (permalink)  
Antiguo 14/11/2017, 15:52
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 13 años, 6 meses
Puntos: 774
Respuesta: Consulta Select "compleja"

Cual es el query que te da errores? podrias ponerlo, y se entiende tu problematica, que tengas mas condiciones no deberia de interferir porque vas a buscar en donde sea 1 y 9(el contador sea=2) otra cosa como ya te dijeron, no tenemos tus datos, asi que vas a tener que acomodar la logica por tu cuenta, aqui nada mas se te da una ayuda no la solucion
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #9 (permalink)  
Antiguo 14/11/2017, 15:58
Avatar de bacc  
Fecha de Ingreso: febrero-2009
Ubicación: Argentina
Mensajes: 33
Antigüedad: 11 años
Puntos: 1
Respuesta: Consulta Select "compleja"

Mirá con esta consulta logro lo que necesito, pero sin tener en cuenta los join :

Código MySQL:
Ver original
  1. SELECT usrs_p7.id_padre, usrs_p7.id_informatica, usrs_p7.nivel, COUNT(id_informatica)
  2.  FROM usrs_p7
  3.  WHERE (usrs_p7.id_informatica='1' AND usrs_p7.nivel>='1') OR (usrs_p7.id_informatica='9' AND usrs_p7.nivel>='1')
  4.  GROUP BY (id_padre)

Respuesta:
id_padre id_informatica nivel COUNT(id_informatica)
-------- -------------- ------ -----------------------
3 1 3 2
4 1 3 1
6 1 3 2
7 1 3 1

El padre 3 tienen el id_informatica 9 y 1; el 4 solo tiene el 1 el 6 el 9 y el 1 y el 7 solo el 1...

A eso tengo que agregarle el having; pero cuando lo quiero poner en la consulta con el JOIN se vuelve loco :(
  #10 (permalink)  
Antiguo 14/11/2017, 16:09
Avatar de bacc  
Fecha de Ingreso: febrero-2009
Ubicación: Argentina
Mensajes: 33
Antigüedad: 11 años
Puntos: 1
Respuesta: Consulta Select "compleja"

Si llevo esa misma consulta a la de JOINS queda así:

Código MySQL:
Ver original
  1. SELECT usrs_p7.id_padre, usrs_p7.id_informatica, usrs_p7.nivel, COUNT(usrs_p7.id_informatica)
  2.  FROM usrs LEFT JOIN usrs_p1 ON usrs.id= usrs_p1.id_padre LEFT JOIN usrs_p2 ON usrs.id= usrs_p2.id_padre LEFT JOIN usrs_p3 ON usrs.id= usrs_p3.id_padre LEFT JOIN usrs_p4 ON usrs.id= usrs_p4.id_padre LEFT JOIN usrs_p5 ON usrs.id= usrs_p5.id_padre LEFT JOIN usrs_p6 ON usrs.id= usrs_p6.id_padre LEFT JOIN usrs_p7 ON usrs.id= usrs_p7.id_padre LEFT JOIN usrs_p8 ON usrs.id= usrs_p8.id_padre LEFT JOIN usrs_p9 ON usrs.id= usrs_p9.id_padre LEFT JOIN usrs_p10 ON usrs.id= usrs_p10.id_padre LEFT JOIN usrs_p11 ON usrs.id= usrs_p11.id_padre
  3.  WHERE (usrs_p7.id_informatica='1' AND usrs_p7.nivel>='1') OR (usrs_p7.id_informatica='9' AND usrs_p7.nivel>='1')
  4.  GROUP BY (usrs_p7.id_padre)
  5.  HAVING COUNT(usrs_p7.id_informatica) > 1;

Pero el resultado es este :
id_padre id_informatica nivel count(usrs_p7.id_informatica)
-------- -------------- ------ -------------------------------
3 1 3 8
4 1 3 12
6 1 3 2
7 1 3 2

Por que me devuelve 8 en el primer registro?
  #11 (permalink)  
Antiguo 15/11/2017, 08:42
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 13 años, 6 meses
Puntos: 774
Respuesta: Consulta Select "compleja"

Porque devuele 8 eso si no lo se, seria ver en esa tabla cuantos registros tienes, aqui lo que esta pasando es que al hacer los joins hay mas de un registro que comparte las llaves primarias que estas usando.

revisa la tabla usrs para que veas cuantos registros tiene con las condiciones que estas usando:

Código MySQL:
Ver original
  1. select * from usrs where id_padre=3 and id_informatica=1 and nivel=3
Ahi te vas a dar cuenta el porque el 8
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #12 (permalink)  
Antiguo 16/11/2017, 06:22
Avatar de bacc  
Fecha de Ingreso: febrero-2009
Ubicación: Argentina
Mensajes: 33
Antigüedad: 11 años
Puntos: 1
Respuesta: Consulta Select "compleja"

Claro, varias de las tablas tienen como id_padre el id de usr.
Bueno, muchas gracias por la ayuda, voy a trabajar con cada tabla separada; mas programación y menos sql.

Saludos y gracias!!

Etiquetas: campo, condiciones, ram, select, 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 04:34.