Агрегатные функции в предложении WHERE в SQLite

Проще говоря, у меня есть таблица, в которой, помимо прочего, есть столбец для временных меток. Я хочу получить строку с самой последней меткой времени (т. Е. С наибольшим значением). Сейчас делаю вот что:

SELECT * FROM table ORDER BY timestamp DESC LIMIT 1

Но я бы предпочел сделать что-то вроде этого:

SELECT * FROM table WHERE timestamp=max(timestamp)

Однако SQLite отклоняет этот запрос:

SQL error: misuse of aggregate function max()

документация подтверждает это поведение (внизу страницы):

Aggregate functions may only be used in a SELECT statement.

Мой вопрос: можно ли написать запрос, чтобы получить строку с наибольшей отметкой времени, не упорядочивая выбор и не ограничивая количество возвращаемых строк до 1? Кажется, это должно быть возможно, но я полагаю, что мой SQL-fu не в порядке.

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
11
0
40 899
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий
SELECT * from foo where timestamp = (select max(timestamp) from foo)

или, если SQLite настаивает на обработке подзапросов как наборов,

SELECT * from foo where timestamp in (select max(timestamp) from foo)

Красиво работает, спасибо. Я знал, что это должно быть что-то простое.

Kyle Cronin 24.12.2008 04:06

Просто любопытно, заставляет ли подзапрос sqlite обрабатывать таблицу дважды или это оптимизировано?

Chris Noe 24.12.2008 05:30

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

SquareCog 24.12.2008 23:03

Думаю, я отвечал на этот вопрос 5 раз за последнюю неделю, но я слишком устал, чтобы найти ссылку на один из них прямо сейчас, так что вот он снова ...

SELECT
     *
FROM
     table T1
LEFT OUTER JOIN table T2 ON
     T2.timestamp > T1.timestamp
WHERE
     T2.timestamp IS NULL

Вы в основном ищете строку, в которой не соответствует ни одна другая строка, более поздняя, ​​чем она.

ПРИМЕЧАНИЕ: Как указано в комментариях, этот метод не будет работать так же хорошо в такой ситуации. Обычно это работает лучше (по крайней мере, для SQL Server) в ситуациях, когда вам нужна последняя строка для каждого клиента (в качестве примера).

Это может сработать, но разве выполнение соединения не влечет за собой снижение производительности?

Kyle Cronin 24.12.2008 04:05

Это работает, но поражает своей неэффективностью. Предполагая, что в исходной таблице 10 строк, это дает (и отбрасывает) 55 строк. Для 100 строк размер создаваемого вами набора составляет 5050. Растет очень быстро. Лучше просто сделать два сканирования.

SquareCog 24.12.2008 04:11

Да, и это не работает, когда у вас есть две строки с одинаковой максимальной отметкой времени.

SquareCog 24.12.2008 04:12

@Dmitriy - ваше собственное решение дает тот же точный результат, если две строки имеют одинаковую максимальную временную метку. Что касается эффективности, то в этом упрощенном примере использование подзапроса работает лучше, но не в тех случаях, когда вы хотите, чтобы последняя строка была сгруппирована по другому столбцу.

Tom H 24.12.2008 06:11

Том, ты прав, я снимаю свой комментарий о том, что твое решение не работает. Но я считаю, что это очень неэффективно. Что до группировки по другому столбцу - а? Просто добавьте "группу по x". Может я не понимаю сценарий? Как правило, из соображений философии я стараюсь избегать почти декартовых соединений.

SquareCog 24.12.2008 23:01

ты можешь просто сделать

ВЫБРАТЬ *, макс (отметка времени) ИЗ таблицы

Редактировать: Поскольку агрегатную функцию нельзя использовать таким образом, она выдает ошибку. Думаю, то, что предложил SquareCog, было лучшим решением

SELECT * FROM table WHERE timestamp = (select max(timestamp) from table)

Есть много способов снять шкуру с кошки.

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

SELECT * FROM TABLE ORDER BY ID DESC LIMIT 1

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