-- тестовый набор данных - искать в реальном наборе тягостно
drop table if exists siv cascade;
create table siv (
	siv_id int NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,  
	line_key varchar(255) NOT NULL, 
	dt_from date NOT NULL, 
	agreement_version int NOT NULL, 
	line_version int NOT NULL,
	cost int NULL,
	descr text NULL
);
insert into siv (line_key,dt_from,agreement_version,line_version,cost)
values 
('line-01', '2025-03-01', 1, 1, 100),
('line-01', '2025-04-01', 1, 2, 100), -- сдвиг на месяц позже
('line-01', '2025-02-01', 2, 1, 200), -- сдвиг на 2 месяца раньше и увеличение 
('line-01', '2025-05-01', 3, 1, 250), -- сдвиг на 3 месяца позже и увеличение 
('line-01', '2025-05-01', 3, 2, 130), -- уменьшение без сдвига 
('line-01', '2025-06-01', 4, 1, 160) -- сдвиг и увеличение 
;
select s.*, (select ) 
from siv s 

--https://stackoverflow.com/questions/74296984/how-can-i-discard-rows-that-are-out-of-order
SELECT *,
LEAD(dt_from) OVER (PARTITION BY line_key ORDER BY dt_from) dt_next
FROM
(
  SELECT *,
    MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) mn
	
  FROM siv
) t
WHERE t.dt_from=t.mn
order by siv_id
;
-- демонстрирует коллизию совпадающих дат
-- для совпадающих дат нам просто нужно взять старшую

SELECT *,
(select min(dt_from) from siv i where i.dt_from > t.dt_from AND i.line_key=t.line_key) dt_next
FROM
(
  SELECT *,
    MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) mn	
  FROM siv
) t
WHERE t.dt_from=t.mn  -- получаем лесенку, в которой порядок дат соответствует порядку версий
order by siv_id
;

SELECT *,
LEAD(dt_from) OVER (PARTITION BY line_key ORDER BY dt_from, agreement_version,line_version) dt_next
FROM
(
  SELECT *,
    MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) mn
	
  FROM siv
) t
WHERE t.dt_from=t.mn
order by siv_id
;
-- в данном случае siv_id=4 имеет нулевой интервал и не будет учтена в расчетах, хотя и даст лишнее чтение
-- вместо null мы можем взять верхнюю границу диапазона