5

例如我有下表:

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 进行交叉连接是可行的,但我正在寻找一种更具可扩展性的解决方案,可以应用于具有数百万条记录的表。谢谢

4

3 回答 3

8
select a.*
from Tablename a
where 
(
   select count(*) 
   from Tablename as b
   where a.group = b.group and a.id >= b.id
) <= 2
于 2013-04-09T06:34:55.443 回答
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
于 2013-04-09T07:15:08.783 回答
-1

您可以像往常一样选择、过滤和排序查询,然后

用于MSSQL

SELECT TOP 2 * FROM foo; 

据我记得SybaseOracle和可能的其他一些RDBMS使用这种语法。

对于MySQL,你做

SELECT * FROM foo LIMIT 2; 

更新:

是的,我看错了你的问题,对不起。似乎我们中的一些人这样做了:)

然后取决于您的RDBMS是否支持HAVING等。您可以使用HAVING或使用ININ子句中的子查询来构造查询。

对于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不支持的某些东西,反之亦然。

这里有些例子

为每个类别选择前 10 条记录

如何在 MySQL 中为每个 topic_id 选择最后两条记录

于 2013-04-09T06:33:42.983 回答