2017-02-24 119 views
0

我试图从每个类别获得前2最新行,这样就可以在以后缩放,所以我可能例如获得前4行,而不是顶部2.MySQL的选择前N行每一类

这里是我的表看起来像

Id | category_id | created_at 
------ | ----------- ---------- 
    1 |  1  | 2017-12-01 
    2 |  2  | 2017-12-02 
    3 |  4  | 2017-12-03 
    4 |  2  | 2017-12-04 
    5 |  1  | 2017-12-05 
    6 |  1  | 2017-12-06 
    7 |  3  | 2017-12-07 
    8 |  4  | 2017-12-08 
    9 |  4  | 2017-12-09 
    10 |  3  | 2017-12-10 
    11 |  5  | 2017-12-11 

我想获得最新的2行(基于created_at列)的ID,所以我所要的输出是这样的

 Ids  
    ------ 
     5 
     6 
     2 
     4 
     7 
     10 
     8 
     9 
     11 

我做像

select * from table 
inner join (
    select * from table 
    order by category_id, created_at 
    limit 2 
) as tb 
on tb.id = table.id and tb.category_id = table.category_id 

显然它不工作,只是想分享我到目前为止达成的目标。 有没有办法在MySQL中做到这一点?

编辑

其实我这样做,它还挺工作

SELECT * 
    FROM 
    (SELECT *, 
        @count := IF(@current_category = category_id, @count + 1, 1) AS count, 
        @current_category := category_id 
     FROM table 
     ORDER BY category_id, created_at DESC 
    ) ranked 
    WHERE count <= 2; 
+0

[获得每组分组结果的前n条记录]的可能重复(http://stackoverflow.com/questions/12113699/get-top-n-records-for-each-group-of-grouped-results ) –

回答

3

这是比较MySQL中的痛苦比它应该是。也许最简单的方法是使用变量:

select * from table group by category_id order by created_at limit 2 

我的MySQL技能有点生疏,但这个(或它的概念)应该做的:

select t.* 
from (select t.*, 
      (@rn := if(@c = category_id, @rn + 1, 
         if(@c := category_id, 1, 1) 
         ) 
      ) as rn 
     from t cross join 
      (select @rn := 0, @c := -1) params 
     order by category_id, created desc 
    ) t 
having rn <= 2; 
+0

我上面编辑了我的问题,它的工作原理,你的答案有点类似于我的。感谢你的回答。 –

+0

您的答案不能保证可行,因为您设置了变量,然后在不同的表达式中使用它们。 MySQL不保证'select'中表达式的评估顺序。 –

-1

我会像这样的东西去招。

+0

只会得到整个结果的前2行 –

+0

按'created_at'排序,所以它会返回前2项 – magicleon

+0

是的,我想要的是从**每个**类别中获得前两名按created_at排序。所以如果我有多个类别,那么无论由created_at排序的类别如何,您的查询都会使我成为整个结果中的前两名。 –