例如,我有以下表格:
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的交叉连接可以工作,但我正在寻找一个更具可扩展性的解决方案,可以应用于具有数百万条记录的表。由于
select a.*
from Tablename a
where
(
select count(*)
from Tablename as b
where a.group = b.group and a.id >= b.id
) <= 2
- <
- SQLFiddle演示/gh>
我喜欢这个技巧,它利用了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
你选择,过滤和排序你的查询像正常的,然后
该
SELECT TOP 2 * FROM foo;
从我能记得的Sybase, Oracle和可能的其他几个RDBMS的使用这种语法。
for 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不支持,而另一方面。
下面是一些例子
为每个类别选择前10条记录
如何选择MySQL中每个topic_id的最后两条记录