2009-07-20 64 views
5

Quiero limitar el tamaño de los registros dentro de un grupo, y aquí está mi versión de prueba, ¿cómo hacerlo bien?límite de mysql dentro del grupo?

mysql> select * from accounts limit 5 group by type; 

ERROR 1064 (42000): Usted tiene un error en su sintaxis SQL; compruebe el manual que corresponde a su versión del servidor MySQL para la sintaxis correcta de utilizar 'grupo por tipo' cerca en la línea 1

+0

Creo que lo que quieres es un 'orden', no un' grupo'. Desea enumerar hasta 5 de cada tipo de cuenta, ¿verdad? – Plutor

+0

sí, ¿cómo lograr eso? – omg

+2

Just By The Way, debe poner el límite al final de la consulta. –

Respuesta

0

Grupo por se utiliza para las funciones de agregado (sumas, promedios ...)

Le permite dividir el resultado agregado en grupos. No has usado una de estas funciones.

0

No estoy seguro de que pueda usar un límite en el grupo. Probablemente pueda usarlo si su grupo by es una selección secundaria que devuelve una fila/valor. Por ejemplo:

seleccionar * de orden foo por (seleccione foo2.id del límite foo2 1)

sólo estoy adivinando que esto funcionaría.

1

Intente colocar la cláusula LIMIT después de la cláusula GROUP BY.

EDIT: Prueba esto:

SELECT * 
FROM accounts a1 
WHERE 5 > 
(
    SELECT COUNT(*) 
    FROM accounts a2 
    WHERE a2.type = a1.type 
    AND a2.balance > a1.balance 
) 

Esto devuelve un máximo de 5 cuentas de cada tipo con los mayores saldos.

+0

eso no es lo que quiero ... – omg

1

Parece que desea limitar el número de filas devueltas dentro de cada grupo de su conjunto de resultados general ... esto es difícil de hacer de una manera que se escala bien. Una técnica es realizar N uniones en la misma tabla con las condiciones tales que las únicas filas que coinciden son la N superior/inferior que desee.

this page puede ofrecer una visión adicional de su solución ... aunque devolver los 5 primeros en cada grupo se pondrá feo rápidamente.

0

Esto probablemente lo haga, aunque si type no está indexado, será sloooowwww. E incluso con uno, no es especialmente rápido:

SELECT a.* 
FROM accounts a 
    LEFT JOIN accounts a2 ON (a2.type = a.type AND a2.id < a.id) 
WHERE count(a2.id) < 5 
GROUP BY a.id; 

Una apuesta mejor sería simplemente order la lista por type y luego usar un bucle en la capa de negocio para eliminar las filas que no desea.

5

El punto de una función de agregado (y el GROUP BY requiere) es convertir muchas filas en una fila. Así que si lo que realmente quieres los mejores cuentas de ahorro y 5 de los 5 mejores cuentas corrientes y cuentas de los 5 mejores USD etc., lo que necesita es de la misma familia:

criterios: top 5 de especial tipo de cuenta por account_balance

SELECT account_type, account_balance FROM accounts WHERE account_type='savings' 
    ORDER BY account_balance DESC LIMIT 5 
UNION 
SELECT account_type, account_balance FROM accounts WHERE account_type='chequing' 
    ORDER BY account_balance DESC LIMIT 5 
UNION 
SELECT account_type, account_balance FROM accounts WHERE account_type='USD' 
    ORDER BY account_balance DESC LIMIT 5; 

No es bonito, pero si construye el SQL con un guión, entonces subplancar en los tipos de cuenta y concatenar juntos una consulta es directa.

5

que he tenido un poco de suerte con el uso de filas numeradas:

set @type = ''; 
set @num = 0; 

select 
    items.*, 
    @num := if(@type = item_type, @num + 1, 1) as dummy_1, 
    @type := item_type as dummy_2, 
    @num as row_number 
from items 
group by 
    item_type, 
    row_number 
having row_number < 3; 

Esto le dará 2 resultados por item_type. (Una Gotcha: asegúrese de volver a ejecutar las dos primeras declaraciones set de lo contrario los números de las filas estarán constantemente llegar más alto y más alto y la restricción row_number < 3 no funcionará

monté esto juntos desde a coupleof posts que se han relacionado en. other answers el SO.

+1

Esta es la mejor respuesta. Una cosa que puedes hacer es usar algo como esto: 'from items, (SELECT @type: = '', @num: = 0) v' y luego puedes establecer las variables dentro de la unión, en lugar de en una declaración separada . Eso puede ser útil en entornos que no permiten declaraciones múltiples. –

0

@ respuesta de dnagirl casi lo tiene, pero por alguna razón, mi versión de MySQL sólo devuelve el primer conjunto LIMIT'd. para conseguir alrededor de eso, puse cada afirmación en una subconsulta

SELECT * FROM (
    SELECT account_type, account_balance FROM accounts WHERE account_type='savings' 
     ORDER BY account_balance DESC LIMIT 5 
) as a 
UNION 
SELECT* FROM (
    SELECT account_type, account_balance FROM accounts WHERE account_type='chequing' 
     ORDER BY account_balance DESC LIMIT 5 
) as b 
UNION 
SELECT * FROM (
    SELECT account_type, account_balance FROM accounts WHERE account_type='USD' 
     ORDER BY account_balance DESC LIMIT 5 
) as c 

Esto dio m e respalde los resultados de cada conjunto en el conjunto de resultados final. De lo contrario, solo habría obtenido los primeros 5 de la primera consulta y nada más: no estoy seguro de si se trata de un funk de MySQL con mi versión