通过“SELECT”命令选择每组的前两个记录的最佳方法是什么?

时间:2013-04-09 06:28:55

标签: php mysql sql group-by greatest-n-per-group

例如我有下表:

id group data
1 1 aaa
2 1 aaa
3 2 aaa
4 2 aaa
5 2 aaa
6 3 aaa
7 3 aaa
8 3 aaa

通过“SELECT”命令选择每组的前两个记录的最佳方法是什么? 如果没有好办法,你建议做什么例程?(在PHP中)

(模型结果)

1 1 aaa
2 1 aaa
3 2 aaa
4 2 aaa
6 3 aaa
7 3 aaa

我知道在子查询中通过a.id> = b.id进行交叉连接可以正常工作,但我正在寻找一种可扩展的解决方案,可以应用于具有数百万条记录的表。感谢

3 个答案:

答案 0 :(得分:8)

select a.*
from Tablename a
where 
(
   select count(*) 
   from Tablename as b
   where a.group = b.group and a.id >= b.id
) <= 2

答案 1 :(得分:3)

我喜欢这个技巧,它使用GROUP_CONCAT聚合函数和FIND_IN_SET:

SELECT
  Tablename.*
FROM
  Tablename INNER JOIN (
    SELECT `group`, GROUP_CONCAT(id ORDER BY id) ids
    FROM Tablename
    GROUP BY `group`) grp ON
  Tablename.`group` = grp.`group` AND
  FIND_IN_SET(Tablename.id, ids)<=2
ORDER BY
  Tablename.`group`, Tablename.id

表演不能太好,因为它无法使用索引。

或者你也可以使用它:

SELECT t1.id, t1.`group`, t1.data
from
  Tablename t1 INNER JOIN Tablename t2
  ON t1.`group` = t2.`group` AND t1.id>=t2.id
GROUP BY
  t1.id, t1.`group`, t1.data
HAVING
  COUNT(*)<=2
ORDER BY
  t1.`group`, t1.id, t1.data

答案 2 :(得分:-1)

您可以像平常一样选择,过滤和订购查询,然后

MSSQL

SELECT TOP 2 * FROM foo; 

我记得 Sybase Oracle 以及其他一些 RDBMS 使用此语法。

MySQL 你做

SELECT * FROM foo LIMIT 2; 

<强>更新

是的,我误解了你的问题,抱歉。好像我们中的一些人做过:)

那么这取决于您 RDBMS 是否支持 HAVING 等。您可以使用 HAVING 或使用 IN构建查询 IN 子句中的子查询。

对于 MSSQL ,我认为您可以执行类似(代码未测试)

的操作
SELECT id, data
    FROM (
        SELECT id, data, Rank() over (Partition BY group ORDER BY id DESC ) AS Rank
        FROM table
        ) rs WHERE Rank <= 2)

但是,由于这取决于您的 RDBMS ,我请您查看类似的问题,看看哪一个最适合您的情况,因为 MSSQL 支持一些事情 MySQL 没有,反过来。

以下是一些例子

Select top 10 records for each category

How to select the last two records for each topic_id in MySQL