У меня есть база данных, в которой хранятся сотрудники. Каждый день, когда сотрудник находится в отпуске, в базу данных заносится новая запись. Я хочу, чтобы кто-то ввел идентификатор сотрудника и диапазон дат, и для каждого периода отсутствия возвращается запись с указанием даты, даты, продолжительности, а также того, был ли это AM или PM (для половины дней).
Это должно выглядеть примерно так (для сотрудника 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
Подобное происходило с датой До, но я исправил это. Подобный подход не работал для даты С. Ниже моя хранимая процедура.
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 ;