27

如果我有一个像这样的 USER 表

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

然后我可以通过以下方式轻松获得每个班级中最年轻的用户

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

同样,通过将 min 替换为 max,我可以获得最旧的。但是我怎样才能得到每个班级中第 10 个最年轻(或最年长)的呢?顺便说一句,我使用的是 MySql v.5.0。

干杯,

4

7 回答 7

22
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

将获得每个班级第二年轻的。如果你想要第 10 个最小的,你会这样做LIMIT 9,1,如果你想要第 10 个最大的,你会这样做ORDER BY age DESC

于 2009-01-20T21:05:49.393 回答
12

这里N介绍Nth记录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)

它给出了Nth记录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)
于 2013-05-14T09:58:09.120 回答
5

唯一的 sql 独立方式(即使你没有子查询 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]

让你成为每个班级中年龄最大的 [number] 个

 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]

让你成为每个班级最年轻的 [number]

如果两个人的年龄相同,则可能无法正常工作,因为两者都会被退回。如果您只想返回其中一个,您将需要一个唯一键并且查询更加复杂。

于 2009-01-20T21:27:54.450 回答
1

任何在其上加入表格的答案都将创建一个平方律......

- 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

随着表大小的增长,性能将迅速下降。如果你把东西保持得很小并且它们不会增长太多,这是一个问题吗?你的电话在那里...

另一种方法涉及更多代码,但线性增长......

  • 首先,将所有记录插入到一​​个新表中,其中包含一个 IDENTITY 字段,按 Class 然后 Age 排序
  • 现在,对于每个类,找到 MIN(id)
  • 现在,对于每个班级,检查 is = MIN(id) + 8 的记录(对于第 9 个最老的)

有很多方法可以完成最后两个步骤。我个人会用...

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
                         )

这给出的是...

  • 一次创建新 ID
  • 一次通过即可获得每个班级的 MIN(id)
  • 一张通行证,获取您需要的记录

  • 并且根据优化器的好坏,使用索引(类然后 id)将允许它将最后 2 次传递合并为 1 次传递。

2 或 3 次通过,无论桌子或班级人数有多大。线性,而不是平方律...

于 2009-01-21T01:35:22.017 回答
1

另一种方法是将 SQL 查询放在一个 for 循环中,每次将新的最小值添加到一个不断增长的元组中,然后使用 WHERE ... NOT IN 子句将其过滤掉。我不确定这个速度,但对我来说,它对于一个非常大的数据集(> 180,000 条记录)工作得非常快。很抱歉混合使用 SQL 和 Python,我对两者都是新手。我知道可能有一种方法可以在 SQL 中执行循环,但我不知道。

        idx = tuple()
        for i in range(n):

            qry = '''SELECT class, min(age)
                     FROM user
                     WHERE age NOT IN {}
                     GROUP BY class'''.format(idx)

            cur.execute(qry)
            data = cur.fetchall()
            d = pd.DataFrame(data)

            idx = idx + tuple(d['min(age)'])
于 2020-04-09T17:39:00.463 回答
0

在 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

按照这种模式,对于 MySQL,我想你想看看这个:http ://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/

于 2009-01-20T20:59:35.630 回答
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

或者

 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
于 2009-01-20T21:22:45.630 回答