SQL-запрос для интерполяции между значениями - PullRequest
0 голосов
/ 08 мая 2019

Я намерен интерполировать ( линейная интерполяция ) между значениями в столбце и вставить его в новый столбец с помощью SQL-запроса.Основываясь на результатах поиска в Интернете, я подозреваю, что аналитическая функция LEAD может оказаться полезной.Я новичок в написании запросов SQL.Таким образом, любое понимание того, как этого можно достичь, будет весьма полезным.

Пример набора данных такой, как описано:

Emp  Test_date  Value
---  ---------  -----
A    1/1/2001   null
A    1/2/2001   100
A    1/3/2001   null
A    1/4/2001   80
A    1/5/2001   null
A    1/6/2001   null
A    1/7/2001   75

Идея состоит в том, чтобы получить четвертый столбец, который имеет значения как:

null
100
interpolatedValue1
80
interpolatedValue2
interpolatedValue3
75

Интерполированное значение1 будет интерполированным значением между 100 и 80 ,

Интерполированное значение2 будет линейно интерполированным значением между 80 и 75 .

InterpolatedValue3 будет линейно интерполированным значением между Interpolatedvalue2 и 75

Вот как работает простая линейная интерполяция:

С учетом двух точек ( V1 при D1 ), ( V3 при D3 ).Какое будет значение V2 при D2 ?

(V3-V1) / (D3-D1) * (D2-D1) + V1

Ответы [ 2 ]

2 голосов
/ 08 мая 2019

Это, вероятно, можно немного упростить, но я получаю ответ, который вы хотели, я полагаю.Немного хитрый бит получает как количество дней между ненулевыми значениями (т. Е. Размер пробела, который вы заполняете), так и позицию в этом промежутке:

-- CTE for sample data
with your_table (emp, test_date, value) as (
            select 'A', date '2001-01-01', null from dual
  union all select 'A', date '2001-01-02', 100 from dual
  union all select 'A', date '2001-01-03', null from dual
  union all select 'A', date '2001-01-04', 80 from dual
  union all select 'A', date '2001-01-05', null from dual
  union all select 'A', date '2001-01-06', null from dual
  union all select 'A', date '2001-01-07', 75 from dual
)
-- actual query
select emp, test_date, value,
  coalesce(value,
    (next_value - prev_value) -- v3-v1
    / (count(*) over (partition by grp) + 1) -- d3-d1
    * row_number() over (partition by grp order by test_date desc) -- d2-d1, indirectly
    + prev_value -- v1
  ) as interpolated
from (
  select emp, test_date, value,
    last_value(value ignore nulls)
      over (partition by emp order by test_date) as prev_value,
    first_value(value ignore nulls)
      over (partition by emp order by test_date range between current row and unbounded following) as next_value,
    row_number() over (partition by emp order by test_date) -
      row_number() over (partition by emp order by case when value is null then 1 else 0 end, test_date) as grp
  from your_table
)
order by test_date;
E TEST_DATE       VALUE INTERPOLATED
- ---------- ---------- ------------
A 2001-01-01                        
A 2001-01-02        100          100
A 2001-01-03                      90
A 2001-01-04         80           80
A 2001-01-05              76.6666667
A 2001-01-06              78.3333333
A 2001-01-07         75           75

I 'мы использовали last_value и first_value вместо lead и lag, но оба работают.(Задержка / отставание может быть быстрее на большом наборе данных, я полагаю).grp расчет Табибитозан .

2 голосов
/ 08 мая 2019

Вы можете использовать lag(ignore nulls). Вы не указываете, как сделать интерполяцию, но линейная интерполяция будет:

select emp, test_date,
       coalesce(test_value,
                ( next_tv * (next_td - test_date) +
                  prev_tv * (test_date - prev_td)
                ) / (next_td - prev_td)
               ) as imputed_value
from (select t.*,
             lag(test_value ignore nulls) over (partition by emp order by test_date) as prev_tv,
             lag(test_date ignore nulls) over (partition by emp order by test_date) as prev_td,
             lead(test_value ignore nulls) over (partition by emp order by test_date) as next_tv,
             lead(test_date ignore nulls) over (partition by emp order by test_date) as next_td
      from t
     ) t
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...