SQL (Redshift) получить начальные и конечные значения для последовательных данных в данном столбце - PullRequest
0 голосов
/ 30 мая 2020

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

+------------+------------+--------------+
| account_id |    date    | current_plan |
+------------+------------+--------------+
| 1          | 2019-08-01 | free         |
| 1          | 2019-08-02 | free         |
| 1          | 2019-08-03 | yearly       |
| 1          | 2019-08-04 | yearly       |
| 1          | 2019-08-05 | yearly       |
| ...        |            |              |
| 1          | 2020-08-02 | yearly       |
| 1          | 2020-08-03 | free         |
| 2          | 2019-08-01 | monthly      |
| 2          | 2019-08-02 | monthly      |
| ...        |            |              |
| 2          | 2019-08-31 | monthly      |
| 2          | 2019-09-01 | free         |
| ...        |            |              |
| 2          | 2019-11-26 | free         |
| 2          | 2019-11-27 | monthly      |
| ...        |            |              |
| 2          | 2019-12-27 | monthly      |
| 2          | 2019-12-28 | free         |
+------------+------------+--------------+

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

+------------+------------+------------+-------------------+
| account_id | start_date |  end_date  | subscription_type |
+------------+------------+------------+-------------------+
|          1 | 2019-08-03 | 2020-08-02 | yearly            |
|          2 | 2019-08-01 | 2019-08-31 | monthly           |
|          2 | 2019-11-27 | 2019-12-27 | monthly           |
+------------+------------+------------+-------------------+

Я начал с выполнения функции LAG windown с кучей операторов WHERE для захвата «изменений состояния», но из-за этого трудно увидеть, когда клиенты постоянно приходят и уходят из подписок, и я не уверен, что это лучший метод.

lag as (
    select *, LAG(tier) OVER (PARTITION BY account_id ORDER BY date ASC) AS previous_plan
            , LAG(date) OVER (PARTITION BY account_id ORDER BY date ASC) AS previous_plan_date
    from data
)
SELECT *
FROM lag
where (current_plan = 'free' and previous_plan in ('monthly', 'yearly'))

1 Ответ

1 голос
/ 30 мая 2020

Это проблема промежутков и островов. Я думаю, что работает разница номеров строк:

select account_id, current_plan, min(date), max(date)
from (select d.*,
             row_number() over (partition by account_id order by date) as seqnum,
             row_number() over (partition by account_id, current_plan order by date) as seqnum_2
      from data
     ) d
where current_plan <> free
group by account_id, current_plan, (seqnum - seqnum_2);
...