Повторное использование значения для нескольких дат в SQL - PullRequest
0 голосов
/ 15 октября 2018

У меня есть таблица, которая выглядит следующим образом

ID            Type               Change_Date               
1              t1                2015-10-08
1              t2                2016-01-03
1              t3                2016-03-07
2              t1                2017-12-13
2              t2                2018-02-01

Показывает, изменил ли клиент тип учетной записи и когда.Тем не менее, я хотел бы запрос, который может дать мне следующий вывод

ID            Type               Change_Date               
1              t1                2015-10
1              t1                2015-11
1              t1                2015-12
1              t2                2016-01
1              t2                2016-02
1              t3                2016-03
1              t3                2016-04
...            ...               ...
1              t3                2018-10

для каждого ID.Выходные данные показывают, какой тип счета был у клиента для каждого месяца до текущего месяцаМоя проблема заключается в заполнении «пустых» месяцев.В некоторых случаях интервал между изменениями аккаунта может превышать год.

Надеюсь, это имеет смысл.

Заранее спасибо.

1 Ответ

0 голосов
/ 16 октября 2018

Основывается на Presto SQL (поскольку ваш исходный вопрос касается Presto / SQL)


Обновление в 2018-11-01: используйте lead() для упрощенияSQL


Подготовка данных

Таблица mytable такая же, как у вас

id  type  update_date
1   t1    2015-10-08
1   t2    2016-01-03
1   t3    2016-03-07
2   t1    2017-12-13
2   t2    2018-02-01

Таблица t_month - это словарная таблица, которая содержит все данные за месяцот 2015-01 до 2019-12.Этот вид словарных таблиц полезен.

ym
2015-01
2015-02
2015-03
2015-04
2015-05
2015-06
2015-07
2015-08
2015-09
...
2019-12

Добавление продолжительности жизни для mytable

Обычно вам следует «управлять» вашими данными так же, как и срок их службы.Так что mytable должно понравиться

id  type   start_date      end_date
1   t1     2015-10-08      2016-01-03
1   t2     2016-01-03      2016-03-07
1   t3     2016-03-07      null
2   t1     2017-12-13      2018-02-01
2   t2     2018-02-01      null

Но в этом случае вы этого не сделаете.Итак, следующий шаг - «создать».Используйте lead() оконную функцию.

select 
    id,
    type, 
    date_format(update_date, '%Y-%m') as start_month,
    lead(
        date_format(update_date, '%Y-%m'), 
        1, -- next one
        date_format(current_date+interval '1' month, '%Y-%m') -- if null return next month
    ) over(partition by id order by update_date) as end_month
from mytable

Выход

id  type  start_month  end_month
1   t1    2015-10     2016-01
1   t2    2016-01     2016-03
1   t3    2016-03     2018-11
2   t1    2017-12     2018-02
2   t2    2018-02     2018-11

Перекрестное соединение id и month

Это просто

with id_month as (
    select * from t_month 
    cross join (select distinct id from mytable)
)
select * from id_month

Вывод

ym      id
2015-01 1
2015-02 1
2015-03 1
...
2019-12 1
2015-01 2
2015-02 2
2015-03 2
...
2019-12 2

Наконец

Теперь вы можете использовать subquery в select предложении

select 
    id,
    type,
    ym
from (
    select
        t1.id,
        t1.ym,
        (select type from mytable2 where t1.id = id and t1.ym >= start_month and t1.ym < end_month) as type
    from id_month t1
)
where type is not null
-- order by id, ym

Полный sql

with mytable2 as (
    select 
        id,
        type, 
        date_format(update_date, '%Y-%m') as start_month,
        lead(
            date_format(update_date, '%Y-%m'), 
            1, -- next one
            date_format(current_date+interval '1' month, '%Y-%m') -- if null return next month
        ) over(partition by id order by update_date) as end_month
    from mytable
)
, id_month as (
    select * from t_month 
    cross join (select distinct id from mytable)
)
select 
    id,
    type,
    ym
from (
    select
        t1.id,
        t1.ym,
        (select type from mytable2 where t1.id = id and t1.ym >= start_month and t1.ym < end_month) as type
    from id_month t1
)
where type is not null
--order by id, ym

Выход

id  type  ym
1   t1    2015-10
1   t1    2015-11
1   t1    2015-12
1   t2    2016-01
1   t2    2016-02
1   t3    2016-03
1   t3    2016-04
...
1   t3    2018-10
2   t1    2017-12
2   t1    2018-01
2   t2    2018-02
...
2   t2    2018-10
...