ВЫБЕРИТЕ МАКС. В GROUP BY, но ОГРАНИЧИВАЙТЕ результаты до 1 в MYSQL - PullRequest
0 голосов
/ 29 мая 2018

У меня есть следующие таблицы:

Task (id, ....)

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

Обратите внимание, что end_at - это отметка времени и что у одной Задачи есть много TaskPlans.Мне нужно запросить MAX end_at для каждой задачи.

Этот запрос работает нормально, за исключением случаев, когда у вас есть одинаковая точная временная метка для разных TaskPlan.В этом случае мне будет возвращено несколько TaskPlan с 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

Любые объяснения и предложения приветствуются!

Примечание на дублирующем ярлыке: (Теперь вновь открыто)

Я уже изучил этот вопрос , но он не дает ответа для моей ситуации, когда в результате есть несколько максимальных значений, и это необходимобыть отфильтрован, чтобы включить только одну строку результатов на группу

Ответы [ 3 ]

0 голосов
/ 29 мая 2018

Используйте 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';
0 голосов
/ 29 мая 2018

Если вы хотите получить список идентификаторов задач с 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;
0 голосов
/ 29 мая 2018

Попробуйте этот запрос:

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;
...