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

Tener X resultados pero para cada...

Estas en el tema de Tener X resultados pero para cada... en el foro de Mysql en Foros del Web. Disculpen si el título no es bueno, pero si intentaba explicar más en el título creo que lo empeoraría. Estoy en esas ocasiones en que ...
  #1 (permalink)  
Antiguo 13/12/2008, 15:31
 
Fecha de Ingreso: junio-2008
Mensajes: 71
Antigüedad: 15 años, 9 meses
Puntos: 0
Tener X resultados pero para cada...

Disculpen si el título no es bueno, pero si intentaba explicar más en el título creo que lo empeoraría.

Estoy en esas ocasiones en que creo que no habrá una solución elegante al problema, por eso vengo aquí donde corro en esos casos

Verán este es el caso. Quiero hacer una consulta, por ejemplo para obtener empleados por departamento.

1.- Si quiero tener X empleados del Departamento A, lo mato con esta consulta

Código:
SELECT tabla.empleados FROM tabla WHERE departamento = A LIMIT X
2.- Si quiero tener todos los empleados en los Departamentos A,...,H, sería.

Código:
SELECT tabla.empleados FROM tabla WHERE departamento IN (A,...,H)
3.- Pero lo que quiero es tener X empleados, en A,...,H departamentos.

Es decir, por ejemplo: 5 empleados del departamento A, 5 del B, 5 del C, etc, etc.

Es decir X resultados, por cada IN del WHERE.

¿como puedo hacer en ese caso? ¿tendré que hacer varias querys?

Y de todas formas aviso que eso es un ejemplo simplificado porque el real tiene JOIN y demás cosas; pero este ejemplo creo que servirá para indicar cual es el problema puntual que tengo.

Gracias adelantadas.
  #2 (permalink)  
Antiguo 13/12/2008, 15:44
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 17 años, 11 meses
Puntos: 2135
Respuesta: Tener X resultados pero para cada...

Mmm quieres la cuenta de empleados de cada departamento?

Saludos.
  #3 (permalink)  
Antiguo 13/12/2008, 15:45
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, 5 meses
Puntos: 2658
Respuesta: Tener X resultados pero para cada...

No puedes hacerlo en una sola consulta. Deberías crear dinámicamente (en la aplicación que la invoca) una consulta con X selects unidos por cláusulas UNION, tantos SELECT como conjuntos distintos tengas.
Código SQL:
Ver original
  1. SELECT a, b, c, d FROM tabla1 WHERE a = 'w' LIMIT X1
  2. UNION
  3. SELECT a, b, c, d FROM tabla1 WHERE a = 'x' LIMIT X1
  4. UNION
  5. SELECT a, b, c, d FROM tabla1 WHERE a = 'y' LIMIT X2
  6. UNION
  7. SELECT a, b, c, d FROM tabla1 WHERE a = 'z' LIMIT X3;
De esa forma obtendrías los valores en una sola tabla.
Si además quieres que esa tabla se ordene en base a otro criterio, deberás incluir todo el conjunto en una subconsulta... pero eso es un poquito más complicado.

Esto parece más complicado de lo que es en realidad al momento de codificar.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #4 (permalink)  
Antiguo 13/12/2008, 15:59
 
Fecha de Ingreso: junio-2008
Mensajes: 71
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Tener X resultados pero para cada...

Cita:
Iniciado por GatorV Ver Mensaje
Mmm quieres la cuenta de empleados de cada departamento?

Saludos.
Quiero hacer algo similar al Ejemplo 1, donde tengo X resultados para el Departamento A.

Pero la cuestión es que quiero X resultados para el Departamento A y X resultados para el B y X resultados para el C, es decir, todos los que estén en el WHERE - IN


Cita:
Iniciado por gnzsoloyo Ver Mensaje
No puedes hacerlo en una sola consulta. Deberías crear dinámicamente (en la aplicación que la invoca) una consulta con X selects unidos por cláusulas UNION, tantos SELECT como conjuntos distintos tengas.
Código SQL:
Ver original
  1. SELECT a, b, c, d FROM tabla1 WHERE a = 'w' LIMIT X1
  2. UNION
  3. SELECT a, b, c, d FROM tabla1 WHERE a = 'x' LIMIT X1
  4. UNION
  5. SELECT a, b, c, d FROM tabla1 WHERE a = 'y' LIMIT X2
  6. UNION
  7. SELECT a, b, c, d FROM tabla1 WHERE a = 'z' LIMIT X3;
De esa forma obtendrías los valores en una sola tabla.
Si además quieres que esa tabla se ordene en base a otro criterio, deberás incluir todo el conjunto en una subconsulta... pero eso es un poquito más complicado.

Esto parece más complicado de lo que es en realidad al momento de codificar.
Creo que si me has entendido, lo probaré a ver. solo espero que no me resulte costoso.

Y si, cuando se me ocurrió hacerlo creí que era "rutina" pero al ponerme en eso resultó más complicado y por eso vine a preguntar.

Muchas gracias a todos y si a alguien se le ocurre algo más no dude en postear.
  #5 (permalink)  
Antiguo 07/01/2009, 15:41
 
Fecha de Ingreso: junio-2008
Mensajes: 71
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Tener X resultados pero para cada...

Hice la opción de los UNION y funcionó a la perfección.

Sin embargo, el problema ha vuelto. Por cosas que no dependen de mi, ahora resulta que no debo hacerlo con UNION, cosas tipo "UNION solo sirve para MySQL > 4.0" (por solo decir MySQL), "la clase para manejo de Base de Datos hace limpieza de UNION por seguridad", etc.

Entonces, ahora creo que me dejan entre la espada y la pared: una solución (que luce imposible) que haga lo mismo pero sin usar UNION; o simplemente hacer los SELECT por separado uno a uno

¿alguien tiene idea de si es posible hacer lo mismo pero sin UNION? francamente no se me ha ocurrido nada en este sentido y de ahí fue que vine la primera vez , y las cosas siguen igual, dudo mucho que haya forma de esa manera.

Gracias adelantadas.
  #6 (permalink)  
Antiguo 07/01/2009, 15:54
Colaborador
 
Fecha de Ingreso: marzo-2008
Ubicación: Cáceres
Mensajes: 3.735
Antigüedad: 16 años, 1 mes
Puntos: 300
Respuesta: Tener X resultados pero para cada...

¿Cómo vas a usar los datos que saques? ¿No te interesará hacer una consulta de departamentos y luego con programación mostrar los 5 de cada departamento?
Todo dependerá de cómo vayas a usar los datos. Si trabajas con PHP te resultará fácil con dos consultas, que en realidad serán tantas como departamentos haya, más la de departamentos. Puedes o mostrarlas por separado o cargarlas en un array y mostrarlas luego todas sin problema. Pero esto es de programación, no de bases de datos. Además no tendrás que preocuparte de saber los departamentos que tienen, pues lo hará de todos los que tengan...
  #7 (permalink)  
Antiguo 07/01/2009, 16:07
Avatar de Thumper  
Fecha de Ingreso: agosto-2004
Ubicación: Jesús María - Lima - Perú
Mensajes: 270
Antigüedad: 19 años, 8 meses
Puntos: 6
Respuesta: Tener X resultados pero para cada...

En el codigo, para tener datos creo una varaible tipo tabla q simula ser tu tabla y al menos cuado ejecuto sale correcto.

Código SQL:
Ver original
  1. DECLARE @TABLE TABLE( idint INT, tipo CHAR(1))
  2.  
  3. INSERT INTO @TABLE VALUES( 1, 'A' )
  4. INSERT INTO @TABLE VALUES( 2, 'A' )
  5. INSERT INTO @TABLE VALUES( 3, 'A' )
  6. INSERT INTO @TABLE VALUES( 4, 'B' )
  7. INSERT INTO @TABLE VALUES( 5, 'B' )
  8. INSERT INTO @TABLE VALUES( 6, 'B' )
  9. INSERT INTO @TABLE VALUES( 7, 'C' )
  10. INSERT INTO @TABLE VALUES( 8, 'C' )
  11. INSERT INTO @TABLE VALUES( 9, 'C' )
  12.  
  13. SELECT  t.idint, t.tipo
  14. FROM    @TABLE t
  15. WHERE   t.tipo IN ( 'A', 'C' ) AND
  16.     t.idint IN ( SELECT top 2 t1.idint
  17.              FROM @TABLE t1
  18.              WHERE t1.tipo = t.tipo )

Por si no manejas SQL, Top 2 = Limit 2 creo q lo demas es =.

Saludos
__________________
Martín Alexis Valdivia S.
-----------------------------
"Quisiéramos cambiar el mundo, pero Dios no nos daría el código fuente." CAP
"Si Saber No Es Un Derecho, Seguro Será Un Izquierdo." WD

Última edición por Thumper; 07/01/2009 a las 16:13
  #8 (permalink)  
Antiguo 07/01/2009, 16:39
 
Fecha de Ingreso: junio-2008
Mensajes: 71
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Tener X resultados pero para cada...

Cita:
Iniciado por jurena Ver Mensaje
¿Cómo vas a usar los datos que saques? ¿No te interesará hacer una consulta de departamentos y luego con programación mostrar los 5 de cada departamento?
Todo dependerá de cómo vayas a usar los datos. Si trabajas con PHP te resultará fácil con dos consultas, que en realidad serán tantas como departamentos haya, más la de departamentos. Puedes o mostrarlas por separado o cargarlas en un array y mostrarlas luego todas sin problema. Pero esto es de programación, no de bases de datos. Además no tendrás que preocuparte de saber los departamentos que tienen, pues lo hará de todos los que tengan...
Eso sonó como a la segunda opción

Los datos sobre la cantidad de departamentos ya están cargados en un array, así que ese no entra en mis preocupaciones (y tampoco debería serlo ya que se trata de una sola consulta y de rutina).

Sí uso php, y así como antes construía la query con los UNION, podría hacer lo mismo con querys individuales, pero la idea de tener que hacer mysqlquery(...) 10, 20, o 40 veces, con su respectivo mysql_fetch_assoc, de verdad no me atrae mucho que digamos .

Siendo sincero, no tengo mucha idea de como funciona el motor SQL, le tengo cierta idea incluso, "no me importa trabajar más en programación", siempre y cuando force lo menos posible la DB con consultas, llamadas y demás. De ahí viene cierto prejuicio y por eso busco hacer las cosas optimizando la sentencia para hacer pocas llamadas a la DB en lugar de fastidiarla a cada rato.

Como dije arriba, "no se como funciona internamente el motor SQL", y quizás de una u otra forma la carga sea exactamente la misma, y solo es idea mía que con un ciclo de querys, querys, querys, hago más pesada la cuestión.

Me parece que solo me quedará hacer eso que dices, que es justo lo que quería evitar y encontrar una forma "mejor".

Gracias (si alguien más tiene alguna idea, no dude en decirla).

Cita:
Iniciado por Thumper Ver Mensaje
En el código, para tener datos creo una varaible tipo tabla q simula ser tu tabla y al menos cuando ejecuto sale correcto.

Código SQL:
Ver original
  1. DECLARE @TABLE TABLE( idint INT, tipo CHAR(1))
  2.  
  3. INSERT INTO @TABLE VALUES( 1, 'A' )
  4. INSERT INTO @TABLE VALUES( 2, 'A' )
  5. INSERT INTO @TABLE VALUES( 3, 'A' )
  6. INSERT INTO @TABLE VALUES( 4, 'B' )
  7. INSERT INTO @TABLE VALUES( 5, 'B' )
  8. INSERT INTO @TABLE VALUES( 6, 'B' )
  9. INSERT INTO @TABLE VALUES( 7, 'C' )
  10. INSERT INTO @TABLE VALUES( 8, 'C' )
  11. INSERT INTO @TABLE VALUES( 9, 'C' )
  12.  
  13. SELECT  t.idint, t.tipo
  14. FROM    @TABLE t
  15. WHERE   t.tipo IN ( 'A', 'C' ) AND
  16.     t.idint IN ( SELECT top 2 t1.idint
  17.              FROM @TABLE t1
  18.              WHERE t1.tipo = t.tipo )

Por si no manejas SQL, Top 2 = Limit 2 creo q lo demas es =.

Saludos
Muchas gracias por el curro, esto lo voy a guardar y estudiarlo para ver que saco para futuras ocaciones; pero para este caso, ya tengo la limitación con los UNION, así que será igual con este sub SELECT.

Muchas gracias
  #9 (permalink)  
Antiguo 08/01/2009, 00:29
Colaborador
 
Fecha de Ingreso: marzo-2008
Ubicación: Cáceres
Mensajes: 3.735
Antigüedad: 16 años, 1 mes
Puntos: 300
Respuesta: Tener X resultados pero para cada...

Sebassebas,
con PHP sólo usarás dos mysql_fetch_assoc o mysql_fetch_array, y no harás ningún UNION. Es más, si ya tienes los departamentos en un array, te bastará con 1. El programa sustituirá la variable de departamento en cada iteración y cargará en otro array los datos. Es decir, un foreach de tu array de departamentos dentro del cual lanzas una consulta en que el nombre del departamento buscado en el where es el $valor del array y pones un limit 5, y luego, dentro de la iteración cargas en otro array que has creado fuera del foreach. Y ya está.
Te indico los pasos.
Si ya tienes un array con los departamentos ordenados llamado arraydepartamentos,
1) creas otro array para cargar arraycarga
2) haces una iteración según los datos del arraydepartamentos usando como variable el valor en cada paso: foreach(array as valor){consulta = SELECT usuaruios... where departamento = valor GROUP ... LIMIT 5
...mysql_query, etc.
3) otra iteración con while (datos = mysql_fetch_array(consulta)) {cargas el resultado de cada consulta en el arraycarga}
}
4) muestras, si quieres los datos del array carga mediante otro foreach...

Esta es la idea.
Si no tuvieras el arraydepartamentos, tendrías que hacer una consulta previa...

Última edición por jurena; 08/01/2009 a las 01:33
  #10 (permalink)  
Antiguo 08/01/2009, 04:30
Colaborador
 
Fecha de Ingreso: marzo-2008
Ubicación: Cáceres
Mensajes: 3.735
Antigüedad: 16 años, 1 mes
Puntos: 300
Respuesta: Tener X resultados pero para cada...

perdón, responí cuando quería editar.
  #11 (permalink)  
Antiguo 08/01/2009, 07:15
 
Fecha de Ingreso: junio-2008
Mensajes: 71
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Tener X resultados pero para cada...

Sí, te entiendo perfectamente, incluso, eso era lo que podía hacer desde el comienzo pero no "me gustó" debido a lo que mencioné antes. Quizás mi temor sea falso o real, lo cierto es que me considero un iniciado en BD, y eso en cuanto al lenguaje, y ese "prejuicio" se iría si fuese un gurú de como funcionan esos motores SQL.

Cuando digo que hay que hacer 10, 20, 40, X llamadas a la DB con su respectivo mysql_fetch_assoc, es que aunque esté en un ciclo y solo lo escriba una sola vez, o "escrito uno por uno"; en ejecución se harán 10, 20, 40, X veces llamadas a la DB con su respectivo mysql_fetch_assoc.

Muchas gracias.
  #12 (permalink)  
Antiguo 09/01/2009, 09:32
 
Fecha de Ingreso: julio-2008
Mensajes: 40
Antigüedad: 15 años, 9 meses
Puntos: 1
Respuesta: Tener X resultados pero para cada...

usa group by a
  #13 (permalink)  
Antiguo 09/01/2009, 11:37
 
Fecha de Ingreso: junio-2008
Mensajes: 71
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Tener X resultados pero para cada...

Cita:
Iniciado por kronenmix Ver Mensaje
usa group by a
¿que, que? ¿como, como?

No se si sabes algo que yo no sé, pero que sepa con GROUP solo voy a tener un resultado por elemento de agrupación, y lo que quiero es tener X resultados por (en este caso) departamento.

------------------------------------------------------------------------------------------------------------

Lo que menciono varias veces de que "...no me gusta una forma y busco otra..." yo lo califico como idea o sugestión, pero para que entiendan mi sensación puedo usar este ejemplo.

Supongamos que se quieren leer 4 campos de una tabla.

Se usaría esta consulta.

Código PHP:
SELECT campo1campo2campo3campo4 
       FROM tabla1
       WHERE a 
'w' LIMIT 1 
Pero también se podría usar esto:

Código PHP:
SELECT campo1
       FROM tabla1
       WHERE a 
'w' LIMIT 1;
SELECT campo2
       FROM tabla1
       WHERE a 
'w' LIMIT 1;
SELECT campo3
       FROM tabla1
       WHERE a 
'w' LIMIT 1;
SELECT campo4
       FROM tabla1
       WHERE a 
'w' LIMIT 1
O

Código PHP:
// array en php
$campo_arr = array ('campo1''campo2''campo3''campo4');

// foreach en php, mysql_query, etc, etc

SELECT ' . $campo . '
       
FROM tabla1
       WHERE a 
'w' LIMIT 1
Pero no habría duda que todos en coro dirían que no debería hacer las dos últimas alternativas por nada del mundo y se recomendaría usar la primera.

Sé que son casos diferentes, y que hay casos donde no queda más remedio.

Bien, el objetivo de este tema tiene que ver con esto. Mis conocimientos solo daban para usar la solución del foreach, etc; pero me sentía como si no estuviese haciendo las cosas bien, y estuviese haciendo lo mismo que mostré en el ejemplo .

De ahí hice el tema y fue que me dieron la muy buena solución de los UNION, pero por un motivo extra ya no puedo emplearla.

Gracias.
  #14 (permalink)  
Antiguo 09/01/2009, 13:34
Colaborador
 
Fecha de Ingreso: marzo-2008
Ubicación: Cáceres
Mensajes: 3.735
Antigüedad: 16 años, 1 mes
Puntos: 300
Respuesta: Tener X resultados pero para cada...

Sebassebas,

no pueden compararse las opciones, pero creo que el problema es el uso de limit en MySQL en subconsultas. Desde luego en MySQL 6 mejorará algo, pero no sé si permitirá hacer lo que quieres.
De todas formas, te haré otra propuesta. Esta con una sola consulta, pero usando el GROUP_CONCAT ordenando y luego mediante un substring_index, recortando el número del limit
tipo es texto: sería el departamento;
id sería el id de usuario. Hay que hacer un cast a char pues group_concat solo devuelve cadena y el campo id que puse es un número. Si se trata de un campo de texto puedes quitar el cast... as char. Separo con una coma y con substrin_index luego me quedo con los que están entre comas hasta un número, tras haberlos ordenado descendente. Busco en IN los departamentos que quiera (es tu array). Lo que obtengo son líneas con los cinco en orden descendente de cada departamento. Si hay menos, me trae los que haya, y si en el departamento no hay ninguno, lo descarta. Es un poco chapuza, pero se trata de una sola consulta. Luego las cadenas separadas por coma las podrás trabajar perfectamente en PHP. Realmente es sólo un experimento mío.

SELECT tipo, substring_index(GROUP_concat( cast( id AS char ) ORDER BY ID DESC
SEPARATOR ','),',',5) dato
FROM `tabla`
WHERE tipo
IN (
'A', 'B'
) group by tipo having count(*) > 0

Última edición por jurena; 10/01/2009 a las 07:02
  #15 (permalink)  
Antiguo 09/01/2009, 15:43
 
Fecha de Ingreso: junio-2008
Mensajes: 71
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Tener X resultados pero para cada...

Código PHP:
SELECT `departamento` , SUBSTRING_INDEXGROUP_CONCAT( `empleados`
ORDER BY ID DESC
SEPARATOR 
',' ) , ',')
FROM `prueba`
WHERE `departamento`
IN ('A''C''G''H')
GROUP BY `departamento`
HAVING COUNT( * ) >
¡¡¡Perfecto, eres un PRO!!!

Es una alternativa bastante ingeniosa y hasta donde he podido ver, funciona totalmente.

El separar los datos luego y encontrar un separador adecuado es un problema menor, mi interés era sacar toda la información fastidiando la DB el menor número de veces posible y esto lo hace en una sola llamada.

Muchas gracias
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 20:18.