在GROUP BY中选择MAX但在MYSQL中将LIMIT结果为1

时间:2018-05-29 20:20:12

标签: mysql sql dbeaver

我有以下表格:

  

任务(id,....)

     

TaskPlan(id,task_id,.......,end_at)

请注意,end_at是一个时间戳,一个Task有许多TaskPlans。我需要为每个任务查询MAX end_at

此查询可以正常工作,除非您对不同的TaskPlans具有相同的确切时间戳。在这种情况下,对于同一个任务,我将返回多个具有MAX end_at的TaskPlans。

我知道这种情况不太可能,但无论如何我可以将每个task_id的结果数限制为1吗?

我目前的代码是:

SELECT * FROM Task AS t
INNER JOIN (
SELECT * FROM TaskPlan WHERE end_at in (SELECT MAX(end_at) FROM TaskPlan GROUP BY task_id )
) AS pt 
ON pt.task_id = t.id
WHERE status = 'plan';

这是有效的,除了上述情况,如何实现? 同样在子查询中,SELECT MAX(end_at) FROM TaskPlan GROUP BY task_id的instad,是否可以执行类似的操作,以便我可以将TaskPlan.id用于where in子句?

SELECT id, MAX(end_at) FROM TaskPlan GROUP BY task_id

当我尝试时,它会出现以下错误:

  

SQL错误[1055] [42000]:SELECT列表的表达式#1不在GROUP中   BY子句并包含非聚合列'TaskPlan.id',它不是   功能上依赖于GROUP BY子句中的列;这是   与sql_mode = only_full_group_by

不兼容

任何解释和建议都会受到欢迎!

关于重复标签的说明: (现已重新开启)

我已经研究了this question,但它没有为我的情况提供答案,结果中有多个最大值,需要过滤掉每个组只包含一个结果行。

3 个答案:

答案 0 :(得分:1)

使用id而不是时间戳:

SELECT *
FROM Task AS t INNER JOIN
     (SELECT tp.*
      FROM TaskPlan tp
      WHERE tp.id = (SELECT tp2.id FROM TaskPlan tp2 WHERE tp2.task_id = tp.task_id ORDER BY tp2.end_at DESC LIMIT 1)
     ) tp 
     ON tp.task_id = t.id
WHERE status = 'plan';

或者使用带有元组的in

SELECT *
FROM Task AS t INNER JOIN
     (SELECT tp.*
      FROM TaskPlan tp
      WHERE (tp.task_id, tp.end_at) in (SELECT tp2.task_id, MAX(tp2.end_at)
                                        FROM TaskPlan tp2 
                                        GROUP BY tp2.task_id
                                       )
     ) tp 
     ON tp.task_id = t.id
WHERE status = 'plan';

答案 1 :(得分:1)

如果您想获得每个MAX end_at的任务ID列表,请运行以下查询:

SELECT t.id, MAX(tp.end_at) FROM Task t JOIN TaskPlan tp on t.id = tp.task_id GROUP BY t.id;

编辑:

现在,我知道你到底要做什么。 如果TaskPlan表格如此之大,您可以避免使用' GROUP BY'并运行下面非常有效的查询:

SET @first_row := 0;
SET @task_id := 0;

SELECT * FROM Task t JOIN (
   SELECT tp.*
    , IF(@task_id = tp.`task_id`, @first_row := 0, @first_row := 1) AS temp
    , @first_row AS latest_record
    , @task_id := tp.`task_id`

    FROM TaskPlan tp ORDER BY task_id, end_at DESC) a  ON t.task_id = a.task_id AND a.latest_record = 1;

答案 2 :(得分:0)

尝试此查询:

select t.ID , tp1.end_at
from TASK t
left join TASKPLAN tp1 on t.ID = tp1.id 
left join TASKPLAN tp2 on t.ID = tp2.id and tp1.end_at < tp2.end_at
where tp2.end_at is null;