2011-08-11 4 views
2

직원을 퇴사시키는 데이터베이스가 있습니다. 직원이 퇴근 할 때마다 새 레코드가 데이터베이스에 입력됩니다. 내가 성취하고자하는 것은 누군가가 종업원 ID와 날짜 범위를 입력하는 것이며, 각 휴면 기간에 대해 날짜, 기간, 기간 및 오전 또는 오후 (반나절 동안)를 나타내는 레코드가 반환됩니다.연속 된 일정을 수집하는 중

그것은처럼 보일 (직원 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 

주 : 10과 12 모두 반 일이기 때문에 첫 번째 기간은 위의 2 11 일은 꽉 찼습니다.

어쨌든. 시작 날짜가 직원이 떠날 날짜가 아니라면 예상했던대로 정확하게 쿼리가 작동합니다. 예를 들어 위의 예제에서 날짜를 10 일, 11 일 또는 12 일로 설정하면 해당 행이 제거됩니다. 지정된 날짜 사이의 날짜를 계산해야합니다.

은 현재 (직원 9999과 2011-09-01에 2011-08-11 날짜)하는 방법을 보여줍니다

: 유사

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

날짜에 일어나고했지만, 난 고정 것을 얻었다. 유사한 접근 방식이 시작 날짜에 작동하지 않았습니다. 아래 내 저장 프로 시저입니다. 기본적으로 LEFT JOIN의 각 난에 전달 된 매개 변수에 의해 시작 날짜에서 필터링 기준으로했다

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

가 좋아 나는 그것을 알아 냈 그것은 매우 간단했다.

나는 또한 여부를 기준으로 필터링했다 휴가가 승인되면 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 ; 
관련 문제