我有一个包含合约表的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的记录将返回两行,因为记录ID 5和6之间存在差距。
有什么想法吗?
答案 0 :(得分: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