У меня есть следующие таблицы:
Задача (id,....)
TaskPlan (id, task_id,......., end_at)
Обратите внимание, что end_at - это метка времени, и у одной задачи есть много TaskPlans. Мне нужно запросить MAX end_at
для каждой задачи.
Этот запрос работает отлично, за исключением случаев, когда у вас одинаковая метка времени для разных TaskPlans. В этом случае мне будет возвращено несколько TaskPlans с MAX end_at
для той же Задачи.
Я знаю, что это маловероятная ситуация, но все равно я могу ограничить количество результатов для каждого 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';
Это работает, за исключением описанной выше ситуации, как это можно достичь? Также в подзапросе, instad из 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 [1055] [42000]: выражение №1 в списке SELECT не находится в предложении GROUP BY и содержит неагрегированный столбец "TaskPlan.id", который функционально не зависит от столбцов в предложении GROUP BY; это несовместимо с sql_mode = only_full_group_by
Любые объяснения и предложения были бы очень желанными!
Примечание по дубликатному ярлыку: (теперь снова открыта)
Я уже изучил этот вопрос, но он не дает ответа на мою ситуацию, когда в результате есть несколько максимальных значений, и его нужно отфильтровать, чтобы включить только одну строку результата для каждой группы.
Используйте 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';
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery
. Я понимаю, что это может быть связано с моей версией, но вторая также будет иметь мою предыдущую проблему в случае нескольких планов задач с одинаковыми значениями task_id
и end_at
. :)
=
, а не in
.
Если вы хотите получить список идентификаторов задач с MAX 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 настолько велика, вы можете избежать "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;
Попробуйте этот запрос:
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;
SELECT taskid, MAX(end_at) FROM TaskPlan GROUP BY task_id
илиSELECT id, MAX(end_at) FROM TaskPlan GROUP BY id
вместоSELECT id, MAX(end_at) FROM TaskPlan GROUP BY task_id