Интерполировать отсутствующие значения при объединении двух таблиц - PullRequest
1 голос
/ 07 мая 2020

У меня есть две таблицы с разными данными плотности, и я хотел бы иметь возможность объединить их, но интерполировать эти значения в таблице более низких частот, чтобы заполнить пробелы.

Я понятия не имею, как подойти к этому, кроме того, что это проблема отставания / опережения, но различия нерегулярны.

Вот моя настройка ниже:

CREATE TABLE #HighFreq
    (MD INT NOT NULL,
    LOSS float)

INSERT INTO #HighFreq
VALUES
    (6710,0.5)
    ,(6711,0.6)
    ,(6712,0.6)
    ,(6713,0.5)
    ,(6714,0.5)
    ,(6715,0.4)
    ,(6716,0.9)
    ,(6717,0.9)
    ,(6718,0.9)
    ,(6719,1)
    ,(6720,0.8)
    ,(6721,0.9)
    ,(6722,0.7)
    ,(6723,0.7)
    ,(6724,0.7)
    ,(6725,0.7)

CREATE TABLE #LowFreq
    (MD INT NOT NULL
    ,X FLOAT
    ,Y FLOAT)

INSERT INTO #LowFreq
VALUES
    (6710,12,1000)
    ,(6711,8,1001)
    ,(6718,10,1007)
    ,(6724,8,1013)
    ,(6730,11,1028)

И я хочу, чтобы мой результат выглядел так:

Sample Output

1 Ответ

3 голосов
/ 07 мая 2020

Вот подход с использованием рекурсивных функций cte и окна. Возвращающий cte генерирует список md s из значений, доступных в обеих таблицах. Затем идея состоит в том, чтобы объединить соседние «отсутствующие» #LowFreq записи в группы, используя технику промежутков и островков. Затем вы можете выполнить интерполяцию во внешнем запросе, проецируя значения между первым (и единственным) ненулевым значением в группе и следующим.

with cte as (
    select min(coalesce(h.md, l.md)) md, max(coalesce(h.md, l.md)) md_max
    from #HighFreq h
    full join #LowFreq l on l.md = h.md
    union all
    select md + 1, md_max from cte where md < md_max
)
select
    md,
    loss,
    coalesce(x, min(x) over(partition by grp)
        + (min(lead_x) over(partition by grp) - min(x) over(partition by grp))
        * (row_number() over(partition by grp order by md) - 1) 
        / count(*) over(partition by grp)
    ) x,
    coalesce(y, min(y) over(partition by grp)
        + (min(lead_y) over(partition by grp) - min(y) over(partition by grp))
        * (row_number() over(partition by grp order by md) - 1) 
        / count(*) over(partition by grp)
    ) y
from (
    select 
        c.md,
        h.loss,
        l.x,
        l.y,
        sum(case when l.md is null then 0 else 1 end) over(order by c.md) grp,
        lead(l.x) over(order by c.md) lead_x,
        lead(l.y) over(order by c.md) lead_y
    from cte c
    left join #HighFreq h on h.md = c.md
    left join #LowFreq l  on l.md = c.md
) t

Демо на DB Fiddle :

  md | loss |                x |                y
---: | ---: | ---------------: | ---------------:
6710 |  0.5 |               12 |             1000
6711 |  0.6 |                8 |             1001
6712 |  0.6 | 8.28571428571429 | 1001.85714285714
6713 |  0.5 | 8.57142857142857 | 1002.71428571429
6714 |  0.5 | 8.85714285714286 | 1003.57142857143
6715 |  0.4 | 9.14285714285714 | 1004.42857142857
6716 |  0.9 | 9.42857142857143 | 1005.28571428571
6717 |  0.9 | 9.71428571428571 | 1006.14285714286
6718 |  0.9 |               10 |             1007
6719 |    1 | 9.66666666666667 |             1008
6720 |  0.8 | 9.33333333333333 |             1009
6721 |  0.9 |                9 |             1010
6722 |  0.7 | 8.66666666666667 |             1011
6723 |  0.7 | 8.33333333333333 |             1012
6724 |  0.7 |                8 |             1013
6725 |  0.7 |              8.5 |           1015.5
6726 | <em>null</em> |                9 |             1018
6727 | <em>null</em> |              9.5 |           1020.5
6728 | <em>null</em> |               10 |             1023
6729 | <em>null</em> |             10.5 |           1025.5
6730 | <em>null</em> |               11 |             1028
...