Вы можете использовать first_value и last_value . Это аналитические функции, которые можно использовать, как в демонстрации ниже.
with demo_data ( primary_id, secondary_id, timestamp)as
( select 1, 10, date '2020-01-01' from dual
union all
select 2 ,10, date '2020-01-28' from dual
union all
select 3, 10, date '2020-02-03' from dual
union all
select 4, 20, date '2020-03-02' from dual
union all
select 5, 20, date '2020-03-15' from dual
)
, grouped_data as
( select primary_id,
secondary_id,
timestamp,
decode(first_value(primary_id) over(partition by secondary_id order by timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ), primary_id, 'Y', 'N') first_row_in_group,
decode(last_value(primary_id) over(partition by secondary_id order by timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING), primary_id, 'Y', 'N') last_row_in_group
from demo_data
)
select primary_id, secondary_id, timestamp
from grouped_data s
where first_row_in_group = 'Y' or last_row_in_group = 'Y'
/