[Sql] получить предыдущую, следующую запись в групповом запросе?

Dasar

Как в sql эффективно получать предыдущую, следующую запись в групповом запросе?
при одиночном запросе все понятно - делаем отсечку по rownum/top.

select top 1 * from data where time > @prevTime

а как быть в групповом запросе? например, когда надо получить следующие записи для целого набора.
зы
конкретная постановка
таблица
objid, value, time
необходимо эффективно выполнить следующий запрос:
по каждому Objid получить последнюю запись, которая шла перед заданным временем
ззы
задача модельная: т.е. в первую очередь хочется научиться решать задачи схожего класса.

sinet

http://www.oracle-base.com/articles/misc/LagLeadAnalyticFunc...
В MS SQL`е правда это ещё не реализовали вроде, хотя в стандарте есть...

6yrop

select top 1 * from data where time > @prevTime
если не указана сортировка, то этот запрос вернет "случайную" запись

asel75

а в PL вообще вернёт ошибку

Dasar

>если не указана сортировка, то этот запрос вернет "случайную" запись
согласен. должно быть так
select top 1 * from data where time > @prevTime order by time

lebed853

Если оракловая база, то ссылку на LAG и LEAD тебе дали, если MS SQL и др., то эффективно в самом запросе не вернуть, однако можно быстро получить нужную строку на клиенте, например.

6yrop

Но order by тяжелая операция, вот такой запрос будет выполняться быстрее
 

SELECT T1.*
FROM T1
WHERE
[Time] =
(
SELECT MAX([Time])
FROM T1
WHERE [Time] < '10-01-2001'
)

6yrop

По аналогии групповой запрос будет выглядеть так

SELECT T1.*
FROM T1
INNER JOIN
(
SELECT ObjectId, MAX([Time]) AS MaxTime
FROM T1
WHERE [Time] < '10-01-2001'
GROUP BY ObjectId
) T2
ON T1.ObjectId = T2.ObjectId
AND T1.[Time] = T2.MaxTime

6yrop

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

Dasar

> Но order by тяжелая операция, вот такой запрос будет выполняться быстрее
даже при наличии подходящего индекса?

Dasar

> вот такой запрос будет выполняться быстрее
имхо, такой запрос обычно раскрывается в два пробега по индексу, в отличии от order by
или я ошибаюсь?

Dasar

> По аналогии групповой запрос будет выглядеть так
запрос неправильный (так же как и предыдущий одинночный) так как для каждого объекта может вернуть несколько записей, хотя требовалась только по одной

6yrop

имхо, такой запрос обычно раскрывается в два пробега по индексу, в отличии от order by
или я ошибаюсь?
при наличии индекса по Time, планы запросов совпадают.

6yrop

запрос неправильный (так же как и предыдущий одинночный) так как для каждого объекта может вернуть несколько записей, хотя требовалась только по одной
имхо, странное бизнес-требование — выбор произвольной ("случайной") записи из множества.

6yrop

ну если очень надо, то можно так

SELECT T1.*
FROM T1
INNER JOIN
(
SELECT ObjectId, MAX([Time]) AS MaxTime, MAX([Value]) AS MaxValue
FROM T1
WHERE [Time] < '10-01-2001'
GROUP BY ObjectId
) T2
ON T1.ObjectId = T2.ObjectId
AND T1.[Time] = T2.MaxTime
AND T1.[Value] = T2.MaxValue

anton7805

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

Dasar

> имхо, странное бизнес-требование — выбор произвольной ("случайной") записи из множества.
нормальное бизнес-требование - выбрать максимальную запись.
и опять же нормальное требование - что нет уникальности по тому полю, по которому берется максимум.

6yrop

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

Dasar

> если требуется выбрать одну запись и нет уникальности, то придется выбирать "случайную" запись
согласен, надо брать случайную
но неправильно брать несколько

T1.ObjectId = T2.ObjectId
AND T1.[Time] = T2.MaxTime
AND T1.[Value] = T2.MaxValue

и неправильно требовать наличие индекса по objectId, time и value.
неправильно - в том смысле, что в общем случае хотелось бы обойтись без поиска мифического доп. поля на который повешен такой подходящий для нас индекс.
Оставить комментарий
Имя или ник:
Комментарий: