Мне нужно найти два ближайших расстояния каждой строки на основе всех значений столбца.
Я попытался выполнить перекрестное соединение и использовал функцию опережения, чтобы найти расстояние. Я совершенно не уверен, как это написать. Пожалуйста, предложите.
select a.id,lead(a.value,b.value) as distance from cluster a , cluster b
Входная таблица:
ID Values
1 12.1
2 11
3 14
4 10
5 9
6 15
7 16
8 8
ID Values Closest_Value
1 12.1 11,10
2 11 9,10
3 14 15,16
4 10 9,11
5 9 8,10
6 15 14,16
7 16 14,15
8 8 9,10
Один метод использует перекрестное соединение и агрегацию:
select id, value,
listagg(other_value, ',') within group (order by diff) as near_values
from (select c.id, c.value, c2.value as other_value
abs(c2.value = c.value) as diff,
row_number() over (partition by c.id order by abs(c2.value = c.value)) as seqnum
from cluster c join
cluster c2
on c.id <> c2.id
) c
where seqnum <= 2
group by id, value;
Вышеупомянутое не особенно эффективно для больших объемов данных. Альтернативой является использование lead()
и lag()
для получения значений, разворота и агрегирования:
with vals as (
select c.id, c.value,
(case when n.n = 1 then prev_value_2
when n.n = 2 then prev_value
when n.n = 3 then next_value
when n.n = 4 then next_value_2
end) as other_value
from (select c.*,
lag(value, 2) over (order by value) as prev_value_2,
lag(value) over (order by value) as prev_value,
lead(value) over (order by value) as next_value,
lead(value, 2) over (order by value) as next_value_2,
from clusters c
) c cross join
(select rownum as n
from clusters
where rownum <= 4
) n -- just a list of 4 numbers
)
select v.id, v.value,
list_agg(other_value, ',') within group (order by diff)
from (select v.*,
abs(other_value - value) as diff
row_number() over (partition by id order by abs(other_value - value)) as seqnum
from vals v
) v
where seqnum <= 2
group by id, value;
Блестящий. Спасибо