Выберите последние n строк без использования order by - PullRequest
5 голосов
/ 31 октября 2011

Я хочу получить последние n строк из таблицы в базе данных Postgres. Я не хочу использовать предложение ORDER BY, поскольку хочу иметь общий запрос. У кого-нибудь есть предложения?

Будет оценен один запрос, так как я не хочу использовать FETCH курсор Postgres.

Ответы [ 2 ]

9 голосов
/ 01 ноября 2011

То, что вы получите с помощью решения Лукаса (по состоянию на 1 ноября 2011 г.), вы получите чистая удача .* В СУБД нет «естественного порядка» по определению.Вы зависите от деталей реализации, которые могут измениться в новой версии без предварительного уведомления.Или дамп / восстановление может изменить этот порядок.Он может даже изменить на ровном месте , когда изменяется статистика в БД, и планировщик запросов выбирает другой план, который приводит к другому порядку строк.

Правильный путь чтобы получить «последние n» строк, нужно иметь столбец метки времени или последовательности и ORDER BY этот столбец.Каждая СУБД, о которой вы только можете подумать, имеет ORDER BY, поэтому она настолько «универсальна», насколько это возможно.

I цитируйте руководство здесь :

ЕслиORDER BY не задан, строки возвращаются в любом порядке, который система сочтет наиболее быстрым.

Решение Лукаса прекрасно подходит для избежания LIMIT, которое по-разному реализовано в различных СУБД (например,SQL Server использует TOP n вместо LIMIT), но вам нужно до ORDER BY в любом случае.

Стоит упомянуть, что, хотя оконные функции находятся в SQLстандарт, они все еще не так универсальны, как вы могли бы пожелать.MySQL, например, не поддерживает их.

5 голосов
/ 31 октября 2011

Используйте оконные функции!

select t2.* from (
  select t1.*, row_number() over() as r, count(*) over() as c
  from (
    -- your generic select here
  ) t1
) t2
where t2.r + :n > t2.c

В приведенном выше примере t2.r - это номер строки каждой строки, t2.c - это общее количество записей в вашем общем выборе. И :n будет n последних строк, которые вы хотите получить. Это также работает, когда вы сортируете свой общий выбор.

РЕДАКТИРОВАТЬ : немного менее общий от моего предыдущего примера:

select * from (
  select my_table.*, row_number() over() as r, count(*) over() as c
  from my_table
  -- optionally, you could sort your select here
  -- order by my_table.a, my_table.b
) t
where t.r + :n > t.c
...