Получить значение из предыдущей строки/следующей строки SQL

у меня есть таблица с 3 полями. то есть

id, transferdate, placeid
---------------------------
1  | 1-4-2014 | 14 
2  | 4-4-2014 | 14 
5  | 10-4-2014| 14 
6  | 1-5-2013 | 13 
9  | 10-6-2013| 12

Чего я хотел бы достичь... если это возможно... с помощью одного запроса (независимо от того, сколько подзапросов), но простой SQL (без поворота, CTE и т. д.), чтобы получить то же самое: дата переноса места из каждой строки, в предыдущем строку или к следующей строке, чтобы я мог сделать некоторые вычисления с ними. я имею в виду :

 id, transferdate, placeid, nexttransferdate
    --------------------------------------------
    1  | 1-4-2014 | 14        | 4-4-2014        
    2  | 4-4-2014 | 14        | 10-4-2014 
    5  | 10-4-2014| 14        | null (or transferdate)
    6  | 1-5-2013 | 13        | null (or transferdate)
    9  | 10-6-2013| 12        | null (or transferdate)

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

Спасибо за ваш ответ


person ckinfos    schedule 04.09.2014    source источник
comment
Пожалуйста, не используйте теги, которые не относятся к вашему вопросу.   -  person John Conde    schedule 04.09.2014
comment
Значит, не обязательно быть агностиком? Вы пометили это так, но в вашем объяснении говорится, что это на сервере sql. Предполагая, что это сервер sql, какую версию вы используете? И вы можете использовать CTE в отчете.   -  person Sean Lange    schedule 04.09.2014
comment
@SeanLange: я пометил это как database-agnostic, так как ОП упоминал об этом несколько раз. Вы не знаете, какой тип отчета он имеет в виду.   -  person Tim Schmelter    schedule 04.09.2014
comment
Стандарт SQL определяет для этого функции lead() и lag(), так что это можно считать независимым от базы данных. И все современные СУБД поддерживают это и могут считаться современной функцией.   -  person a_horse_with_no_name    schedule 04.09.2014
comment
@TimSchmelter Я знаю. Именно поэтому я попросил разъяснений. В ОП упоминается, что он должен быть агностическим, но также упоминается CTE, что немного сбивает с толку. Я знаю, что они сказали, что хотят избежать этого, но я предполагаю, что они не понимают, что вы можете использовать их в отчете.   -  person Sean Lange    schedule 04.09.2014
comment
Что такое оператор отчета SQL?   -  person Gordon Linoff    schedule 04.09.2014
comment
с оператором отчета SQL я имел в виду использовать его как запрос на получение для некоторого механизма отчетности. Увы, наш механизм отчетов сделан на заказ, поэтому он принимает только избранные запросы, и это моя проблема. База данных, на которую я ссылаюсь, - это oracle, но я поместил любую базу данных sql, чтобы прояснить общее решение, а не для определенной системы. Извините, если перепутал. Спасибо за комментарии в любом случае.   -  person ckinfos    schedule 04.09.2014


Ответы (2)


Стандартная функция SQL для просмотра предыдущих строк — LAG, а для просмотра последующих строк — LEAD. Однако они доступны не во всех dbms. Просто посмотрите, есть ли они в наличии.

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

РЕДАКТИРОВАТЬ: Вот простой запрос без LEAD для вас:

select 
  id,
  transferdate,
  placeid,
  (
    select min(transferdate)
    from transfers latertransfers
    where latertransfers.placeid = transfers.placeid
    and latertransfers.transferdate > transfers.transferdate
  ) as nexttransferdate
from transfers
order by id;

РЕДАКТИРОВАТЬ: Вот версия LEAD. Доступно в Oracle начиная с версии 8.1.6.

select 
  id,
  transferdate,
  placeid,
  lead(transferdate) over (partition by placeid order by transferdate) as nexttransferdate
from transfers
order by id;
person Thorsten Kettner    schedule 04.09.2014
comment
Спасибо за ваш ответ. он работает так же, как [ссылка] (@GordonLinoff), но план запроса показывает, что ваш план работает быстрее. - person ckinfos; 04.09.2014
comment
Я также добавил запрос LEAD. Это прямой способ сделать это, и он должен привести к лучшему плану выполнения. - person Thorsten Kettner; 04.09.2014

Вы можете сделать это с помощью самообъединения и агрегации:

select t.id, t.transferdate, t.placeid, min(t.transferdate)
from table t left join
     table tnext
     on tnext.placeid = t.placeid and tnext.transferdate > t.transferdate
group by t.id, t.transferdate, t.placeid;

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

person Gordon Linoff    schedule 04.09.2014
comment
он хорошо работает для того, что мне нужно, но, как вы упоминаете, он, безусловно, делает странный план запроса. Я должен дать ответ на запрос Кеттнера. Спасибо вам обоим в любом случае. - person ckinfos; 04.09.2014