【问题标题】:MySQL: Group by select first 2 rows in each group [duplicate]MySQL:通过选择每个组中的前 2 行进行分组 [重复]
【发布时间】:2017-10-10 05:25:55
【问题描述】:

有没有办法从答案表中为每个 Q 选择前 2 个答案:

user_answers 表结构:

id    question_id    user_id    answer_id    create_date
1         1             9           5            null
2         2             8           7            null
3         1             1           3            null
4         3             4           20           null
5         1             4           5            null
6         4             3           25           null
7         2             7           5            null
8         4             9           26           null
9         2             5           8            null
10        1             1           5            null

我需要返回这样的结果:

id    question_id    user_id    answer_id    create_date
1         1             9           5            null
3         1             1           3            null
2         2             8           7            null
7         2             7           5            null
4         3             4           20           null
6         4             3           25           null
8         4             9           26           null

这就像 Group by "question_id" 但从每个组中选择前 2 行,

谢谢,

【问题讨论】:

  • first 2 rows ...您如何定义“第一”?
  • 表“id”列(ASC)
  • "这就像 Group by "question_id""" -- 不,它不像 GROUP BYGROUP BY 从表中返回行;它使用来自每个组的数据计算它返回的行的内容。这个问题属于标签greatest-n-per-group
  • 谢谢你告诉我,那么有没有办法在 MySQL 中处理它?

标签: mysql sql


【解决方案1】:

有一个简单但相当缓慢的解决方案:计算记录数。

select *
from answers
where
(
  select count(*)
  from mytable other
  where other.questionid = answers.questionid
  and other.id <= answers.id
) <= 2
order by questionid, id;

【讨论】:

    【解决方案2】:

    这是一个典型问题,ROW_NUMBER 分析函数将非常有用。 MySQL 不支持任何开箱即用的行号功能,但我们可以使用会话变量来模拟它:

    SET @row_num = 0;
    SET @q_id = 0;
    
    SELECT
        t.id,
        t.question_id,
        t.user_id,
        t.answer_id,
        t.create_date
    FROM
    (
        SELECT 
            @row_num:=CASE WHEN @q_id = question_id THEN @row_num + 1 ELSE 1 END AS rn,
            @q_id:=question_id as question_id,
            id,
            user_id,
            answer_id,
            create_date
        FROM
            user_answers
        ORDER BY question_id, id
    ) t
    WHERE t.rn <= 2
    ORDER BY t.question_id, t.id;
    

    输出:

    演示在这里:

    Rextester

    【讨论】:

    • 在 MySQL (phpMyadmin) "@row_num" 变量上运行这个查询总是有:1
    • @mwafi 嗯...它在演示中运行。尝试使用 SET @q_id = 0; 进行初始化,看看是否有任何改变。您可能需要稍微调整此查询以使其在您的环境中运行。
    【解决方案3】:

    一种方法:(如果您需要每组超过 2 行,那么这不是解决方案)

    select your_table.* from your_table
    inner join(
        select min(id) as id from your_table group by question_id
        union all
        select min(id) as id from your_table
        where id not in (select min(id) from your_table group by question_id)
        group by question_id
    ) t
    on your_table.id = t.id
    order by your_table.question_id , your_table.id 
    

    【讨论】:

    • 工作正常,请问如何显示前 3 个?而不是 2
    • 只是不是这个 )),对于每组超过 2 行,这个查询变得非常丑陋和效率低下,所以如果你需要每组超过 2 行,那么这不是解决方案。跨度>
    • @mwafi:要获得最小值加上除那些最小值之外的所有值的最小值以获得前两个最小值已经感觉有点笨拙。正如 Oto 自己所说:两行以上会变得更加笨拙。您将改用行编号技术,如蒂姆和我的回答中所示。
    • @ThorstenKettner - 如果只需要 2 个第一行/最后一行,这可能是 mysql 中最有效的方法之一。大约超过 2 行,这是个坏主意,我毫无疑问地同意。
    • @Oto Shavadze:我同意这个想法适用于两排 :-) 它看起来有点笨拙,但可以有效地完成任务。
    猜你喜欢
    • 2020-05-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 2022-01-05
    • 2013-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多