Помогите написать запрос: путаница в порядке операций GROUP BY и ORDER BY

У меня есть таблица с именем Информация об этой схеме:

int objectId;
int time;
int x, y;

В системе много избыточных данных - то есть objectId НЕ УНИКАЛЬНЫЙ. Для каждого objectId может быть несколько записей time, x, y.

Я хочу получить список последней позиции каждого объекта. Я начал с этого запроса:

SELECT * FROM Info GROUP BY objectId

Это дало мне именно тот список, который я искал. Однако я также хочу получить только последнее время для каждого объекта, поэтому я попробовал:

SELECT * FROM Info GROUP BY objectId ORDER BY time DESC

Это дало мне список информации по нисходящей системе time. Однако Я не думаю, что он сделал то, что я хочу - это вернуть мне последний time, x, y для каждого объекта..

Кто-нибудь может представить себе запрос, который сделает то, что я хочу?

Обновлять Я попробовал три лучших решения, чтобы увидеть, как они работают друг с другом на наборе данных, состоящем из примерно 50 000 Infos. Вот результаты:

-- NO INDEX: forever
-- INDEX: 7.67 s

SELECT a.*
FROM Info AS a
  LEFT OUTER JOIN Info AS b ON (a.objectId = b.objectId AND a.time < b.time)
WHERE b.objectId IS NULL;

-- NO INDEX: 8.05 s
-- INDEX: 0.17 s

select a.objectId, a.time, a.x, a.y
  from Info a,
       (select objectId, max(time) time from Info group by objectId) b
  where a.objectId = b.objectId and a.time = b.time;

-- NO INDEX: 8.30 s
-- INDEX: 0.18 s

SELECT A.time, A.objectId, B.x, B.y
FROM
(
   SELECT max(time) as time, objectId 
   FROM Info
   GROUP by objectId
) as A 
INNER JOIN Info B
   ON A.objectId = b.objectId AND A.time = b.time;

С некоторым запасом where превосходит inner join.

Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
2
0
1 004
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

SELECT A.time, A.objectID, B.X, B.Y
FROM
(
   SELECT max(time) as time, objectID 
   FROM table
   GROUP by objectID
) as A 
INNER JOIN table B
   ON A.objectID = b.objectID AND A.Time = b.Time

votenaders, решение не сработает, если x и y уменьшатся в любой точке временной шкалы.

Ответ принят как подходящий

Один из способов - использовать подзапрос.

select distinct a.objectID, a.time, a.x, a.y
  from Info a,
       (select objectID, max(time) time from Info group by objectID) b
  where a.objectID = b.objectID and a.time = b.time

Обновлено: добавлено DISTINCT для предотвращения дублирования строк, если один objectId имеет несколько записей с одинаковым временем. В зависимости от ваших данных, если это необходимо, автор вопроса упомянул, что было много повторяющихся строк. (добавлено Томалак)

Использование предложения DISTINCT предотвращает дублирование строк в выходных данных, если существует более одной записи с одинаковым временем для одного objectId.

Tomalak 25.10.2008 22:26

Мне больше нравится стиль SQL Glomek, чем стиль Кэмпбелла, поэтому я отдаю свой голос именно ему, но в основном они одинаковы. Дело вкуса.

Torbjørn 25.10.2008 22:37

Томалак: Вы можете подробнее остановиться на этом? Можете ли вы взять SQL-код Glomek и добавить предложение DISTINCT? Или, может быть, Гломек не будет возражать?

Frank Krueger 25.10.2008 22:41

Сделанный. Думаю, написание собственного ответа уже не будет иметь большого значения. :-)

Tomalak 25.10.2008 23:49

Как бы то ни было, вот еще один способ получить желаемый результат. Я привык делать подобные трюки еще во времена MySQL 4.0, еще до того, как стали поддерживаться подзапросы.

SELECT a.*
FROM Info AS a
  LEFT OUTER JOIN Info AS b ON (a.objectID = b.objectID AND a.time < b.time)
WHERE b.objectID IS NULL;

Другими словами, покажите мне строку, в которой нет другой строки с тем же objectID и большим временем. Это, естественно, возвращает строку с максимальным временем для каждого идентификатора объекта. GROUP BY не требуется.

Разве тебе там не нужен МАКС?

DOK 25.10.2008 23:06

Нет, вам не нужен MAX (). Когда b.objectID IS NULL, это означает, что условие соединения не было выполнено, что означает, что текущая строка 'a' имеет максимальное значение времени любой строки с тем же objectID.

Bill Karwin 26.10.2008 02:11

Это довольно распространенный способ получить всю информацию в строке для строки, которая является частью группы.

Select Info.*
from Info
inner join
   (select ObjectId, max(time) as Latest
    from Info
    group by ObjectId)  I
on Info.ObjectId = I.ObjectID and Info.time = I.Latest

Один и тот же вопрос задавали в разных формах пару раз за последние пару недель. Я забыл, как были сформулированы вопросы.

Другие вопросы по теме