Страницы

Поиск по вопросам

суббота, 8 июня 2019 г.

MySQL Подсчёт уникального количества дней в таблице с диапазонами дат

Пытаюсь найти решение для одной задачки: есть таблица, содержащая Имя, дату начала интервала и дату конца интервала. Суть в том, что у человека с одним и тем же именем - может быть несколько записей, в которых даты могут пересекаться (собственно фото)
Нужно найти для каждого человека (в данном случае для одного Петрова) количество уникальных дней за все даты. То есть не учитывать наложение дат...
Если суммарное количество дней найти по всем записям элементарно - например
SELECT `people_id`, SUM(DATEDIFF(end_date, `start_date`)) AS wd FROM test_days GROUP BY people_id
Или
SELECT SUM(days) total FROM ( SELECT datediff(`end_date`, `start_date`) days FROM test_days ) AS get_days
то как исключить наложения я не додумался.
Если есть добрые люди - поделитесь идеей, пожалуйста.
Сам код таблицы
CREATE TABLE `test_days` ( `people_id` varchar(100) DEFAULT NULL, `start_date` date DEFAULT NULL, `end_date` date DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test_days` (`people_id`, `start_date`, `end_date`) VALUES ('Петров', '2018-06-05', '2018-06-09'), ('Петров', '2018-05-01', '2018-05-19'), ('Петров', '2018-05-06', '2018-05-19'), ('Петров', '2018-05-03', '2018-05-23');


Ответ

Думаю сначала придется размножить записи, что бы каждая дата из интервала стала отдельной строкой. После чего посчитать уникальные записи.
Для размножения записей удобно пользоваться опорной таблицей с порядковыми номерами от 0 до максимальной длины интервалов, которые могут встретиться. Например создадим такую таблицу:
create table seqnum(X int not null); -- Первые 8 записей insert into seqnum values(0),(1),(2),(3),(4),(5),(6),(7); -- И еще 512 insert into seqnum select s1.x*64+s2.x*8+s3.x+8 from seqnum s1, seqnum s2, seqnum s3;
А теперь можем размножать и считать уникальные:
select d.people_id, count(distinct d.start_date + interval s.x day) days from test_days d, seqnum s where s.x<=DATEDIFF(end_date, start_date) group by d.people_id
Пример на sqlfiddle.com

Комментариев нет:

Отправить комментарий