获取连续日期的集合

时间:2011-08-11 13:53:24

标签: mysql

我有一个存储员工休假的数据库。员工休假的每一天都会将新记录输入数据库。我想要达到的目的是让某人输入员工ID和日期范围,并且每个缺席期间都会返回一份记录,说明日期,日期,持续时间以及是上午还是上午(半天)。 / p>

它应该类似于(对于员工9999和日期2011-08-08到2011-09-01):

employee_id | Start      | start_am_pm | End        | end_am_pm | Duration
9999        | 2011-08-10 | PM          | 2011-08-12 | AM        | 2
9999        | 2011-09-01 |             | 2011-09-01 |           | 1

注意:上面的第一个持续时间是2,因为第10和第12个是半天,第11个是满的。

反正。如果From日期不是员工离开的日期,那么我的查询完全符合我的预期。例如,在上面的示例中,如果我将起始日期设置为10日,11日或12日,则会删除该行。它应该计算指定日期之间的天数。

目前如何显示(员工9999和日期2011-08-11至2011-09-01):

employee_id | Start      | start_am_pm | End        | end_am_pm | Duration
9999        | 2011-09-01 |             | 2011-09-01 |           | 1

类似的事情发生在To Date,但我已经解决了这个问题。类似的方法对于From日期不起作用。以下是我的存储过程。

DELIMITER $$

USE `test`$$

DROP PROCEDURE IF EXISTS `GetLeaveDates`$$

CREATE DEFINER=`root`@`%` PROCEDURE `GetLeaveDates`(pEmpID INT, pDateFrom DATETIME, pDateTo DATETIME)
BEGIN

SELECT 
    a.start_date,
CASE WHEN a.am_pm = 1 THEN "AM"
     WHEN a.am_pm = 2 THEN "PM"
     ELSE "" END AS start_am_pm,
    CASE WHEN pDateTo > MIN(c.start_date) THEN
        MIN(c.start_date)
    ELSE
        pDateTo
    END AS End,
CASE WHEN c.am_pm = 1 THEN "AM"
     WHEN c.am_pm = 2 THEN "PM"
     ELSE "" END AS start_am_pm,
    CASE WHEN a.am_pm = 0 AND c.am_pm = 0 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)+1
         WHEN (a.am_pm = 0 AND c.am_pm <> 0) OR (c.am_pm = 0 AND a.am_pm <> 0) THEN
        DATEDIFF(MIN(c.start_date),a.start_date)+0.5
         WHEN a.am_pm <> 0 AND c.am_pm <> 0 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)
    END
     AS Duration
FROM t AS a
LEFT JOIN t AS b ON a.employee_id=b.employee_id AND a.start_date = ADDDATE(b.start_date,1)
LEFT JOIN t AS c ON a.employee_id=c.employee_id AND a.start_date <= c.start_date
LEFT JOIN t AS d ON c.employee_id=d.employee_id AND c.start_date = ADDDATE(d.start_date,-1)
WHERE b.start_date IS NULL AND c.start_date IS NOT NULL AND d.start_date IS NULL
AND a.EMPLOYEE_ID = pEmpID
AND a.START_DATE BETWEEN pDateFrom AND pDateTo
GROUP BY a.employee_id, a.start_date   
; END$$

DELIMITER ;

1 个答案:

答案 0 :(得分:0)

好的我想通了,这很简单,基本上每个LEFT JOIN我必须通过传入的参数过滤开始日期。

我还必须根据请假是否已批准进行过滤,Approved_DateTimeApproved_By字段如果已获批准则填写。在某些情况下,持续时间的计算还有点过时。所以我的存储过程现在看起来像:

DELIMITER $$

USE `test`$$

DROP PROCEDURE IF EXISTS `GetLeaveDates`$$

CREATE DEFINER=`root`@`%` PROCEDURE `GetLeaveDates`(pEmpID INT, pDateFrom DATETIME, pDateTo DATETIME, pApproved BOOLEAN)
BEGIN

SELECT 
    DATE_FORMAT(a.start_date,'%d/%m/%y') AS start,
CASE WHEN a.am_pm = 1 THEN "AM"
     WHEN a.am_pm = 2 THEN "PM"
     ELSE "" END AS start_am_pm,
    DATE_FORMAT(CASE WHEN pDateTo > MIN(c.start_date) THEN
        MIN(c.start_date)
    ELSE
        pDateTo
    END, '%d/%m/%y') AS end,
CASE WHEN c.am_pm = 1 THEN "AM"
     WHEN c.am_pm = 2 THEN "PM"
     ELSE "" END AS end_am_pm,
  CASE WHEN a.am_pm = 0 THEN
    CASE WHEN c.am_pm = 0 OR c.am_pm = 2 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)+1
    WHEN c.am_pm = 1 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)+0.5
    END
WHEN a.am_pm = 1 THEN
    CASE WHEN c.am_pm = 0 OR c.am_pm = 2 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)+1
    WHEN c.am_pm = 1 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)+0.5
    END
WHEN a.am_pm = 2 THEN
    CASE WHEN c.am_pm = 0 OR c.am_pm = 2 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)+0.5
    WHEN c.am_pm = 1 THEN
        DATEDIFF(MIN(c.start_date),a.start_date)
    END 
END AS Duration

FROM t AS a
LEFT JOIN t AS b ON a.employee_id=b.employee_id AND a.start_date = ADDDATE(b.start_date,1) AND ISNULL(b.approved_datetime) <> pApproved AND b.start_date BETWEEN pDateFrom AND pDateTo
LEFT JOIN t AS c ON a.employee_id=c.employee_id AND a.start_date <= c.start_date AND ISNULL(c.approved_datetime) <> pApproved AND c.start_date BETWEEN pDateFrom AND pDateTo
LEFT JOIN t AS d ON c.employee_id=d.employee_id AND c.start_date = ADDDATE(d.start_date,-1) AND ISNULL(d.approved_datetime) <> pApproved AND d.start_date BETWEEN pDateFrom AND pDateTo
WHERE b.start_date IS NULL AND c.start_date IS NOT NULL AND d.start_date IS NULL
AND a.EMPLOYEE_ID = pEmpID
AND a.START_DATE BETWEEN pDateFrom AND pDateTo
AND ISNULL(a.approved_datetime) <> pApproved
AND a.start_date BETWEEN pDateFrom AND pDateTo
GROUP BY a.employee_id, a.start_date
; END$$

DELIMITER ;