Как c помощью аналитических функций получить предыдущее значение прошлой группы в текущей группе?
Предположим есть данные:
create table ttt (id integer, grp varchar(10),amount decimal(16,2))
insert into ttt values (1,'GRP1',500)
insert into ttt values (1,'GRP1',500)
insert into ttt values (2,'GRP1',400)
insert into ttt values (2,'GRP1',400)
insert into ttt values (2,'GRP1',400);
Необходимо получить на выходе такую таблицу:
id grp amount prev_amount
1 GRP1 500 null
1 GRP1 500 null
2 GRP1 400 500
2 GRP1 400 500
2 GRP1 400 500
Обычный LAG or LEAD не подходят, потому что они делают смещение под одинаковый набор данных(последняя строка с GRP1 400 будем иметь прошлое значение null, так как неоткуда было переносить прошлое значение), а тут как мы видим в ID = 1 2 строки, а в ID = 2 уже 3 строки, и их может быть какое угодно кол-во, хоть 1 строка или более 3ех.
Придумал весьма кастыльное решение, через 2 подзапроса.
select
t.*, max(prev_grp_amount) over (partition by id,grp) as final_prev_amount
from (
select
t.id
,t.grp
,t.amount
,lag(AMOUNT,cnt) over (partition by GRP order by id asc) as prev_grp_amount
from (select t.*, count(*) over (partition by GRP,id) as cnt from ttt as t) as t
) as t
order by id;
Для начала я формирую динамический отступ для функции LAG (cnt), затем получаю почти корректный перенос AMOUNT на следущую группу, но ввиду того что полного соответствия для каждой строки не имею, то получаю NULL в одной строчке. Чтобы убрать этот NULL приходится еще в одном подзапросе использовать еще одну аналитическую функцию MAX() по разрезу. Считаю этот вариант слишком кастыльным и неправильным. Кто может придумать более корректное решение?
Ответы (1 шт):
select x.*, max(p_amount) over(partition by id)
from (
select ttt.*,
case when id != lag(id) over(order by id) then lag(amount) over(order by id) end p_amount
from ttt
) x