PostgresSQL - Расчет годового роста с данными, в которых отсутствуют записи - PullRequest
0 голосов
/ 10 июля 2020

У меня есть таблица с ежемесячными данными с отсутствующими записями за несколько месяцев в виде:

data_table

entity_id | Date(data_type: date) | Value
1         | 2018-06-01            | 100
1         | 2018-07-01            | 105
1         | 2017-06-01            | 90
1         | 2016-07-01            | 92

Запись для 2017-07 не существует в таблице.

Как лучше всего взять эти данные и рассчитать годовой доход для каждого месяца? Я бы хотел, чтобы он выглядел так:

entity_id | Date       | Value
1         | 2018-06-01 | 0.11111
1         | 2018-07-01 | null

ie. если значение предыдущего года отсутствует, отображается значение null

Примечание. Я не могу редактировать таблицу. Кроме того, исходная таблица содержит множество сущностей, каждая из которых имеет значения, указанные выше. Исходный размер таблицы также большой.

Я пробовал несколько подходов, подобных упомянутому здесь , который предлагает использовать функцию задержки, например

select date, value, prev_value,
       (value - prev_value) / prev_value as YOY_growth
from (select t.*,
             lag(value) over (partition by right(date, 2)
                              order by left(date, 4)
                             ) as prev_value
      from t
     ) t
where prev_value is not null

Но это не так. решить случай отсутствия записей. В комментариях люди предлагали задать новый вопрос.

Кроме того, один из подходов - использовать запрос соединения,

select t1.*, t1.value as prev_value
from data_table as t1 left join data_table on t1.date = t2.date - INTERVAL '1 year'

Но я не хочу его использовать, так как это результат стол. Следовательно, это замедлит вычисление одной и той же таблицы два раза.

Есть ли лучшие варианты?

1 Ответ

0 голосов
/ 10 июля 2020

Вы можете сгенерировать даты с помощью generate_series(), а затем использовать оконные функции:

select date, (value - lag_value) / lag_value as yoy
from (
    select
        d.date,
        t.value,
        lag(t.value) over (partition by right(d.date, 2) order by left(d.date, 4)) as lag_value
    from (
        select to_char(
            generate_series((min(date) || '-01')::date, (max(date) || '-01')::date, interval '1 month'),
            'yyyy-mm'
        ) as date
        from mytable
    ) d
    left join mytable t on t.date = d.date
) t
...