-- тестовый набор данных - искать в реальном наборе тягостно 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 мы можем взять верхнюю границу диапазона