SELECT GROUP BY 中的 MAX 但 LIMIT 结果在 MYSQL 中为 1
SELECT MAX in GROUP BY but LIMIT results to 1 in MYSQL
我有以下表格:
Task (id,....)
TaskPlan (id, task_id,.......,end_at)
注意end_at是一个时间戳,一个Task有很多TaskPlans。我需要为每个任务查询 MAX end_at
。
此查询工作正常,除非您对不同的 TaskPlans 具有完全相同的时间戳。在那种情况下,我将返回多个 TaskPlans,其中 MAX end_at
用于同一 Task.
我知道这种情况不太可能发生,但无论如何我可以将每个 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
的子查询中,是否可以做这样的事情,这样我就可以将 TaskPlan.id 用于 where in
子句?
SELECT id, MAX(end_at) FROM TaskPlan GROUP BY task_id
当我尝试时,出现以下错误:
SQL Error [1055] [42000]: Expression #1 of SELECT list is not in GROUP
BY clause and contains nonaggregated column 'TaskPlan.id' which is not
functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
非常欢迎任何解释和建议!
重复标签注意事项: (现已重新开放)
我已经研究过 this question,但它没有为我的情况提供答案,即结果中有多个最大值,需要过滤掉以每组只包含一个结果行。
试试这个查询:
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;
使用 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';
如果您想获取每个任务 ID 最大 end_at 的列表,运行 下面的查询:
SELECT t.id, MAX(tp.end_at) FROM Task t JOIN TaskPlan tp on t.id = tp.task_id GROUP BY t.id;
编辑:
现在,我知道你到底要做什么了。
如果 TaskPlan table 太大,可以避免 '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;
我有以下表格:
Task (id,....)
TaskPlan (id, task_id,.......,end_at)
注意end_at是一个时间戳,一个Task有很多TaskPlans。我需要为每个任务查询 MAX end_at
。
此查询工作正常,除非您对不同的 TaskPlans 具有完全相同的时间戳。在那种情况下,我将返回多个 TaskPlans,其中 MAX end_at
用于同一 Task.
我知道这种情况不太可能发生,但无论如何我可以将每个 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
的子查询中,是否可以做这样的事情,这样我就可以将 TaskPlan.id 用于 where in
子句?
SELECT id, MAX(end_at) FROM TaskPlan GROUP BY task_id
当我尝试时,出现以下错误:
SQL Error [1055] [42000]: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'TaskPlan.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
非常欢迎任何解释和建议!
重复标签注意事项: (现已重新开放)
我已经研究过 this question,但它没有为我的情况提供答案,即结果中有多个最大值,需要过滤掉以每组只包含一个结果行。
试试这个查询:
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;
使用 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';
如果您想获取每个任务 ID 最大 end_at 的列表,运行 下面的查询:
SELECT t.id, MAX(tp.end_at) FROM Task t JOIN TaskPlan tp on t.id = tp.task_id GROUP BY t.id;
编辑:
现在,我知道你到底要做什么了。 如果 TaskPlan table 太大,可以避免 '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;