2011-08-11 140 views
2

我有一個存儲員工離開的數據庫。對於每一天員工休假,新的記錄被輸入到數據庫中。我想要達到的目的是讓某人輸入員工編號和日期範圍,並且在每個缺勤期間記錄都會返回,記錄日期,日期和持續時間,以及是否爲上午或下午(半天)。獲取連續日期的收集

它應該是這個樣子(員工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日已滿。

無論如何。如果發件日期不是員工留下的日期,則我的查詢完全按照我的預期工作。例如,在上面的例子中,如果我將起始日期設置爲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 

類似的是與發生在日期,但我得到了修復。類似的方法不適用於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 ; 
+0

坦率地說,您的存儲過程是非常高的標準。不過,我想建議更改'Start,start_am_pm,End,end_am_pm'的數據類型,您應該將其存儲爲unix_timestamp,其中'2011-08-10 | PM' = unix_timestamp('2011-08-10 12 :00:00')',帶時間戳,您可以輕鬆地進行範圍選擇等 – ajreal

回答

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 ;