从表中选择最近n个所有用户的条目

时间:2016-08-11 11:48:00

标签: mysql mysql-workbench

我有一张下表,只想选择所有用户的最后两个条目。

来源表:

-------------------------------------
UserId | QuizId(AID)|quizendtime(AID)|
--------------------------------------
1         10          2016-5-12
2         10          2016-5-12 
1         11          2016-6-12
2         12          2016-8-12
3         12          2016-8-12
2         13          2016-8-12
1         14          2016-9-12
3         14          2016-9-12
3         11          2016-6-12

预期输出类似,(应仅列出所有用户的最近2个quizid条目)

-------------------------------------
UserId | QuizId(AID)|quizendtime(AID)|
--------------------------------------
1         14          2016-9-12
1         11          2016-6-12
2         13          2016-8-12
2         12          2016-8-12
3         14          2016-9-12
3         12          2016-8-12

任何想法都要产生这个输出。

2 个答案:

答案 0 :(得分:1)

使用MySQL user defined变量可以实现此目的:

SELECT 
t.UserId,
t.`QuizId(AID)`,
t.`quizendtime(AID)`
FROM 
(
    SELECT 
    *,
    IF(@sameUser = UserId, @a := @a + 1 , @a := 1) row_number,
    @sameUser := UserId
    FROM your_table
    CROSS JOIN (SELECT @a := 1, @sameUser := 0) var
    ORDER BY UserId , `quizendtime(AID)` DESC
) AS t
WHERE t.row_number <= 2

Working Demo

注意:如果您希望每个用户最多有x个条目,请更改where子句中的条件,如下所示:

WHERE t.row_number <= x

<强>解释

SELECT 
 *,
 IF(@sameUser = UserId, @a := @a + 1 , @a := 1) row_number,
 @sameUser := UserId
FROM your_table
CROSS JOIN (SELECT @a := 1, @sameUser := 0) var
ORDER BY UserId , `quizendtime(AID)` DESC;

此查询按userId的升序和quizendtime(AID)的降序对所有数据进行排序。

现在对这个(多个)排序数据进行分析。

每当您看到新的userId分配row_number (1)时。如果您再次看到同一个用户,则只需增加row_number

最后只过滤那些拥有row_number <= 2的记录,确保每个用户最多有两个最新条目。

编辑:正如Gordon指出的那样,mysql中使用用户定义变量的表达式的评估不能保证始终遵循相同的顺序,因此上述查询会稍加修改:

SELECT 
t.UserId,
t.`QuizId(AID)`,
t.`quizendtime(AID)`
FROM 
(
    SELECT 
    *,
    IF (
            @sameUser = UserId,
            @a := @a + 1,
            IF(@sameUser := UserId, @a := 1, @a:= 1)
        )AS row_number
    FROM your_table
    CROSS JOIN (SELECT @a := 1, @sameUser := 0) var
    ORDER BY UserId , `quizendtime(AID)` DESC
) AS t
WHERE t.row_number <= 2;

WORKING DEMO V2

答案 1 :(得分:1)

用户定义的变量是解决方案的关键。但是,将所有变量赋值放在单个表达式中非常重要。 MySQL不保证select中表达式的评估顺序 - 实际上,有时会以不同的顺序处理它们。

select t.*
from (select t.*,
             (@rn := if(@u = UserId, @rn + 1,
                        if(@u := UserId, 1, 1)
                       )
             ) as rn
       from t cross join
            (select @u := -1, @rn := 0) params
       order by UserId, quizendtime desc
      ) t
where rn <= 2;