mysql avg длина последовательности дат - PullRequest
1 голос
/ 12 апреля 2019

У меня есть отчет, который я пытаюсь выяснить, но я хотел бы сделать все это с помощью оператора SQL вместо необходимости перебирать кучу данных в сценарии, чтобы сделать это.

У меня есть таблица, которая структурирована как:

CREATE TABLE `batch_item` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `record_id` int(11) DEFAULT NULL,
  `created` DATE NOT NULL,
  PRIMARY KEY (`id`),
  KEY `record_id` (`record_id`)
);

Поле даты всегда ГОД-МЕСЯЦ-01. Данные выглядят примерно так:

+------+-----------+------------+
|  id  | record_id |   created  |
+------+-----------+------------+
|    1 | 1         | 2019-01-01 |
|    2 | 2         | 2019-01-01 |
|    3 | 3         | 2019-01-01 |
|    4 | 1         | 2019-02-01 |
|    5 | 2         | 2019-02-01 |
|    6 | 1         | 2019-03-01 |
|    7 | 3         | 2019-03-01 |
|    8 | 1         | 2019-04-01 |
|    9 | 2         | 2019-04-01 |
+------+-----------+------------+

Итак, что я пытаюсь сделать без необходимости создания циклического сценария, так это найти число AVG последовательных месяцев для каждой записи. Пример с данными выше будет:

Record_id 1 would have a avg of 4 months.
Record_id 2 would be 1.5
Record_id 3 would be 1

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

Ответы [ 2 ]

1 голос
/ 12 апреля 2019

Это проблема пробелов и островков. Вам просто нужно перечисление строк, чтобы это работало. В MySQL 8+ вы бы использовали row_number(), но вы можете использовать глобальное перечисление здесь:

select record_id, min(created) as min_created, max(created) as max_created, count(*) as num_months
from (select bi.*, (created - interval n month) as grp
      from (select bi.*, (@rn := @rn + 1) as n  -- generate some numbers
            from batch_item bi cross join
                 (select @rn := 0) params
            order by bi.record_id, bi.month
           ) bi
      ) bi
group by record_id, grp;

Обратите внимание, что при использовании row_number() вы обычно partition by record_id. Однако в этом нет необходимости, если номера созданы в правильной последовательности.

Приведенный выше запрос возвращает острова. Для получения окончательных результатов вам необходим еще один уровень агрегирования:

select record_id, avg(num_months)
from (select record_id, min(created) as min_created, max(created) as max_created, count(*) as num_months
      from (select bi.*, (created - interval n month) as grp
            from (select bi.*, (@rn := @rn + 1) as n  -- generate some numbers
                  from batch_item bi cross join
                       (select @rn := 0) params
                  order by bi.record_id, bi.month
                 ) bi
            ) bi
      group by record_id, grp
     ) bi
group by record_id;
0 голосов
/ 12 апреля 2019

Это не проверенное решение.Это должно работать в MySQL 8.x с небольшими изменениями, так как я не помню арифметику даты в MySQL:

with
a as ( -- the last row of each island
  select *
  from batch_item
  where lead(created) over(partition by record_id order by created) is null
     or lead(created) over(partition by record_id order by created) 
    > created + 1 month -- Fix the date arithmetic here!
),
e as ( -- each row, now with the last row of its island
  select b.id, b.record_id, min(a.last_created) as end_created
  from batch_item b
  join a on b.record_id = a.record_id and b.created <= a.created
  group by b.id, b.record_id
),
m as ( -- each island with the number of months it has
  select
    record_id, end_created, count(*) as months
  from e
  group by record_id, end_created
)
select -- the average length of islands for each record_id
  record_id, avg(months) as avg_months
from m
group by record_id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...