Совокупный счет в таблице истории с удаленными атрибутами - PullRequest
0 голосов
/ 04 мая 2018

У меня есть таблица истории обновлений записей, и я хочу рассчитать совокупные итоги, где значения могут быть добавлены или удалены в набор. (т. е. совокупный итог за один месяц может быть меньше предыдущего).

Например, вот таблица с историей обновлений тегов для записи о человеке. (id - это идентификатор записи человека).

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

+----+------------------------+---------------------+
| id |          tags          |     created_at      |
+----+------------------------+---------------------+
|  1 | ["vip", "established"] | 2017-01-01 00:00:00 |
|  2 | ["established"]        | 2017-01-01 00:00:00 |
|  3 | ["established"]        | 2017-02-01 00:00:00 |
|  1 | ["vip"]                | 2017-03-01 00:00:00 |
|  4 | ["established"]        | 2017-05-01 00:00:00 |
+----+------------------------+---------------------+

С некоторой помощью этих сообщений , я дошел до этого:

SELECT 
  item_month,
  sum(count(distinct(id))) OVER (ORDER BY item_month)
FROM (
  SELECT 
    to_char("created_at", 'yyyy-mm') as item_month,
    id
  FROM person_history 
  WHERE tags ? 'established'
) t1
GROUP BY item_month;

Что дает мне:

month   count
2017-01 2
2017-02 3
2017-05 4 <--- should be 3

А также отсутствует запись на 2017-03-03, которая должна быть 2.

(Запись на 2017-04 также была бы хороша, но пользовательский интерфейс всегда мог бы вывести ее из предыдущего месяца, если это необходимо)

1 Ответ

0 голосов
/ 04 мая 2018

Вот пошаговое руководство, вы можете попытаться свернуть все эти CTE:

with 
  -- Example data
  person_history(id, tags, created_at) as (values
    (1, '["vip", "est"]'::jsonb, '2017-01-01'::timestamp),
    (2, '["est"]', '2017-01-01'), -- Note that Person 2 changed its tags several times per month 
    (2, '["vip"]', '2017-01-02'),
    (2, '["vip", "est"]', '2017-01-03'),
    (3, '["est"]', '2017-02-01'),
    (1, '["vip"]', '2017-03-01'),
    (4, '["est"]', '2017-05-01')),
  -- Get the last tags for each person per month
  monthly as (
    select distinct on (id, date_trunc('month', created_at))
      id,
      date_trunc('month', created_at) as month,
      tags,
      created_at
    from person_history
    order by 1, 2, created_at desc),
  -- Retrieve tags from previous month
  monthly_prev as (
    select
      *,
      coalesce((lag(tags) over (partition by id order by month)), '[]') as prev_tags
    from monthly),
  -- Calculate delta: if "est" was added then 1, removed then -1, nothing heppens then 0
  monthly_delta as (
    select
      *,
      case
        when tags ? 'est' and not prev_tags ? 'est' then 1
        when not tags ? 'est' and prev_tags ? 'est' then -1
        else 0
      end as delta
    from monthly_prev),
  -- Sum all deltas for each month
  monthly_total as (
    select month, sum(delta) as total
    from monthly_delta
    group by month)
-- Finally calculate cumulative sum
select *, sum(total) over (order by month) from monthly_total
order by month;

Результат:

┌─────────────────────┬───────┬─────┐
│        month        │ total │ sum │
├─────────────────────┼───────┼─────┤
│ 2017-01-01 00:00:00 │     2 │   2 │
│ 2017-02-01 00:00:00 │     1 │   3 │
│ 2017-03-01 00:00:00 │    -1 │   2 │
│ 2017-05-01 00:00:00 │     1 │   3 │
└─────────────────────┴───────┴─────┘
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...