我有以下表格:
任务(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,但它没有为我的情况提供答案,结果中有多个最大值,需要过滤掉每个组只包含一个结果行。
答案 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;