2015-07-14 2 views
0

У меня есть MySQL базы данных, содержащие контракты таблица:MySQL Реализации Порядкового Дата Диапазоны

CREATE TABLE IF NOT EXISTS `contracts` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT, 
    `employee_id` BIGINT(20) DEFAULT NULL, 
    `start_date` DATE DEFAULT NULL, 
    `end_date` DATE DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

INSERT INTO `contracts` (`id`,`employee_id`,`start_date`,`end_date`) 
VALUES 
(1, 555, '2010-01-01', '2012-12-31'), 
(2, 666, '2013-01-01', '2013-05-01'), 
(3, 666, '2013-05-02', '2013-10-11'), 
(4, 777, '2012-01-10', '2013-03-01'), 
(5, 777, '2013-03-02', '2014-07-15'), 
(6, 777, '2015-01-16', '2015-05-20'); 

запрашивая у него я получаю один или несколько контракты линий на одного работника

SELECT * FROM contracts 


id employee_id  start_date end_date 
1 555    2010-01-01 2012-12-31 
2 666    2013-01-01 2013-05-01 
3 666    2013-05-02 2013-10-11 
4 777    2012-01-10 2013-03-01 
5 777    2013-03-02 2014-07-15 
6 777    2015-01-16 2015-05-20 

Как запросить таблицу контрактов на группа последовательных диапазонов на одного сотрудника? Я ищу этот выход:

employee_id  start_date end_date 
555    2010-01-01 2012-12-31 
666    2013-01-01 2013-10-11 
777    2012-01-10 2014-07-15 
777    2015-01-16 2015-05-20 

Запись для работника 666 возвратит наименьшую начальную и самую высокую конечную дату, принимая во внимание не существует разрыва между датами контракта.

Запись для работника 777 будет возвращать две строки, поскольку существует разрыв между Индентификационным 5 и 6.

Любых идеями?

ответ

1

Логика не такая сложная, но реализация в MySQL есть. Идея состоит в том, чтобы добавить флаг, который указывает начало начала контракта. Затем для каждой строки сделайте кумулятивную сумму этого. Суммарная сумма может использоваться для целей группировки.

Первым шагом может использовать коррелированный подзапрос:

SELECT c1.*, 
     (NOT EXISTS (SELECT 1 
        FROM contracts c2 
        WHERE c1.employee_id = c2.employee_id AND 
          c1.start_date = c2.end_date + INTERVAL 1 DAY 
        ) 
     ) AS startflag 
FROM contracts c1; 

Второй использует это в качестве подзапроса и делает накопленную сумму:

SELECT 
c0.* 
,(@rn := @rn + COALESCE(startflag, 0)) AS cumestarts 
FROM 
(SELECT c1.*, 
      (NOT EXISTS (SELECT 1 
          FROM contracts c2 
          WHERE c1.employee_id = c2.employee_id AND 
           c1.start_date = c2.end_date + INTERVAL 1 DAY 
         ) 
      ) AS startflag 
     FROM contracts c1 
     ORDER BY employee_id, start_date 

) c0 CROSS JOIN (SELECT @rn := 0) params; 

Заключительный шаг должен агрегировать на эту величину:

SELECT 
c.employee_id 
,MIN(c.start_date) AS start_date 
,MAX(c.end_date) AS end_date 
,COUNT(*) AS numcontracts 
FROM 
(
     SELECT 
     c0.* 
     ,(@rn := @rn + COALESCE(startflag, 0)) AS cumestarts 
     FROM 
     (SELECT c1.*, 
       (NOT EXISTS (SELECT 1 
         FROM contracts c2 
         WHERE c1.employee_id = c2.employee_id AND 
         c1.start_date = c2.end_date + INTERVAL 1 DAY 
        ) 
       ) AS startflag 
       FROM contracts c1 
       ORDER BY employee_id, start_date 

     ) c0 CROSS JOIN (SELECT @rn := 0) params 

) c 
GROUP BY c.employee_id, c.cumestarts 
+0

Это замечательно. Благодарю. Исправлен ваш ответ, чтобы сделать sql без ошибок. –