2009-01-20 17 views
19

Si tengo una tabla de usuario comoSQL seleccione miembro enésima del grupo

class | age 
-------------- 
1  20  
3  56 
2  11 
1  12 
2  20 

Entonces puedo conseguir fácilmente el usuario más joven de cada clase a través de

select class, min(age) 
from user 
group by class; 

Del mismo modo, mediante la sustitución min con un máximo, Puedo obtener el más viejo. Pero, ¿cómo puedo obtener el 10º más joven (o el más antiguo) en cada clase? Por cierto, estoy usando MySql v.5.0.

Saludos,

Respuesta

0

Es bastante fácil en SQL Server:

select 
    * 
from(
    select 
     *, 
     row_number() over(order by age asc) as eldest 
    from class order by age asc) a 
where a.eldest = 10 

Siguiendo ese patrón, para MySQL, creo que te gustaría ver esto: http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/

+0

El método en el enlace funciona pero para ello es un poco de un truco. También es muy rápido. Por una vez multa, para la producción no! –

11
SELECT a.class, 
(
    SELECT b.age 
    FROM users b 
    WHERE b.class = a.class 
    ORDER BY age 
    LIMIT 1,1 
) as age 
FROM users a 
GROUP BY a.class 

Tendría el segundo más joven en cada clase. Si quisieras el décimo más joven, harías LIMIT 9,1 y si querías el 10mo más viejo, harías ORDER BY age DESC.

+1

Eso me dará la décima más antigua en general, no la décima más antigua en cada clase. –

+0

Vaya, no se dio cuenta de que lo quería agrupar. Reparar ... –

+0

Eso no parece funcionar para MySQL v5.5: ERROR 1235 (42000): Esta versión de MySQL aún no es compatible con 'LIMIT & IN/ALL/ANY/ALGUNA subconsulta' – Marcus

0
SELECT 
    userid, 
    class, 
    age, 
    ( SELECT COUNT(1) FROM user 
      WHERE class = c.class AND age > u.age 
    ) AS oldercount 
FROM user AS u 
WHERE oldercount = 9 
GROUP BY class 

o

SELECT userid, 
     class, 
     age 
    FROM user AS u  
    WHERE (SELECT COUNT(1) FROM class WHERE class = c.class AND age > u.age) = 9 
GROUP BY class 
+0

También necesita una clave única si dos personas tienen la misma edad y solo desea devolver una. –

+0

La primera consulta provoca el error: "Columna desconocida 'más joven' en 'where clause'" –

+0

Ambas vuelven a escanear toda la clase para cada registro en la tabla de origen. Debería ser factible sin pegarle a una ley cuadrada ... – MatBailie

1

La manera independiente sólo SQL (incluso si usted no tiene subconsultas MySQL < 5)

select u1.class, u1.age, count(*) from  user u1 join user u2 
on u1.class = u2.class and u1.age >= u2.age 
group by u1.class, u1.age 
having count(*) = [number] 

se obtiene el [número] más antiguo por clase

select u1.class, u1.age, count(*) from  user u1 join user u2 
on u1.class = u2.class and u1.age <= u2.age 
group by u1.class, u1.age 
having count(*) = [number] 

obtiene el [número] más joven por clase

Si dos personas tienen la misma edad, es posible que no funcione ya que ambas se devuelven. Si solo desea devolver uno de ellos, necesitará una clave única y la consulta será más complicada.

0

Cualquier respuesta que se une a una mesa sobre la que uno mismo va a crear una ley del cuadrado ...

- a JOIN b ON a.class = b.class AND a.age >= b.age 
- on average the >= condition will be true for half the class 

- 6 people in a class 
->6*6/2 = 18 

- 10 people in a class 
->10*10/2 = 50 

-> very rapid growth 

Como los tamaños de mesa amplíe el rendimiento se degradará rápidamente. Si mantiene las cosas pequeñas y no crecerán mucho, ¿es un problema? Su llamada no ...

Una alternativa implica más código, pero crece linealmente ...

  • En primer lugar, insertar todos los registros intoa nueva tabla, con un campo de identidad, a continuación, ordenados por clase Edad
  • Ahora, para cada clase, encontrar el MIN (id)
  • Ahora, para cada clase, rinf el registro donde es = MIN (id) + 8 (para la novena mayor)

Hay un montón de formas de hacer los últimos 2 pasos. Yo personalmente usaría ...

SELECT 
    [USER_WITH_IDS].id, 
    [USER_WITH_IDS].class, 
    [USER_WITH_IDS].age 
FROM 
    [USER_WITH_IDS] 
WHERE 
    [USER_WITH_IDS].id = (
          SELECT 
           MIN([min].ID) + 8 
          FROM 
           [USER_WITH_IDS] AS [min] 
          WHERE 
           [min].class = [USER_WITH_IDS].class 
         ) 

Lo que esto le da a ...

  • Un pase para crear los nuevos ID
  • Un pase para obtener el MIN (ID) para cada clase
  • Un pase para obtener los registros que necesita

  • Y dependiendo de lo bueno el optimizador es, usando un índice (clase luego id) le permitiría combinar los últimos 2 pases en 1 pase.

2 o 3 pasadas, sin importar qué tan grande sea la mesa o el tamaño de clase. Lineal, no la ley del cuadrado ...

7

Aquí N presenta Nth registro oldest

SELECT * 
FROM users k 
WHERE N = (SELECT 
      COUNT(DISTINCT age) 
      FROM users u 
      WHERE k.age >= u.age 
       AND k.class = u.class 
      GROUP BY u.class) 

y da Nth registro youngest

SELECT * 
FROM users k 
WHERE N = (SELECT 
      COUNT(DISTINCT age) 
      FROM users u 
      WHERE k.age <= u.age 
       AND k.class = u.class 
      GROUP BY u.class) 
+0

¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ – mzalazar

+0

¡increíble! esto debe marcarse como respuesta –

Cuestiones relacionadas