Nếu tôi hiểu đúng, bạn muốn tính toán sự khác biệt giữa ngày bắt đầu và ngày kết thúc không bao gồm thời gian trước 10 giờ sáng và sau 7 giờ tối.
Đây là truy vấn mẫu và sql fiddle.
SELECT start_time,
finish_time,
interval_time,
EXTRACT (HOUR FROM interval_time), --extract the hours,mins and seconds from the interval
EXTRACT (MINUTE FROM interval_time),
EXTRACT (SECOND FROM interval_time)
FROM (SELECT start_time,
finish_time,
NUMTODSINTERVAL (
CASE
WHEN finish_time - TRUNC (finish_time) > (19 / 24) --if finish time is after 7pm
THEN
TRUNC (finish_time) + (19 / 24) --set it to 7pm
ELSE
finish_time --else set it to actual finish time
END
- CASE
WHEN start_time - TRUNC (start_time) < (10 / 24) --if start time is before 10 am
THEN
TRUNC (start_time) + (10 / 24) --set it to 10 am.
ELSE
start_time --else set it to the actual start time
END,
'day') --subtract the both and convert the resulting day to interval
interval_time
FROM timings);
Những gì tôi đã làm là,
- Kiểm tra xem thời gian bắt đầu là trước 10 giờ sáng và thời gian kết thúc là sau 7 giờ tối. Nếu vậy, hãy đặt thời gian là 10 giờ sáng và 7 giờ tối.
- Sau đó, trừ các ngày và chuyển đổi các ngày kết quả thành Loại Khoảng thời gian.
- Sau đó trích xuất giờ, phút và giây từ Khoảng thời gian.
Lưu ý: Truy vấn này giả định rằng cả hai ngày đều rơi vào cùng một ngày và cả hai đều không trước 10 giờ sáng hoặc sau 7 giờ tối.
CẬP NHẬT: Để loại trừ ngày lễ, truy vấn sẽ trở nên phức tạp. Tôi khuyên bạn nên viết ba hàm và sử dụng các hàm này trong truy vấn.
Chức năng thứ nhất:
FUNCTION modify_start_time (p_in_dte DATE) RETURN DATE
----------------------------------
IF p_in_dte - TRUNC (p_in_dte) < (10 / 24)
THEN
RETURN TRUNC (p_in_dte) + (10 / 24);
ELSIF p_in_dte - TRUNC (p_in_dte) > (19 / 24)
THEN
RETURN TRUNC (p_in_dte) + 1 + (10 / 24);
ELSE
RETURN p_in_dte;
END IF;
Nếu thời gian bắt đầu nằm ngoài giờ làm việc, hãy sửa đổi thời gian bắt đầu thành thời gian bắt đầu gần nhất tiếp theo.
Chức năng thứ 2:
FUNCTION modify_finish_time (p_in_dte DATE) RETURN DATE
----------------------------------
IF p_in_dte - TRUNC (p_in_dte) > (19 / 24)
THEN
RETURN TRUNC (p_in_dte) + (19 / 24);
ELSIF p_in_dte - TRUNC (p_in_dte) < (10 / 24)
THEN
RETURN TRUNC (p_in_dte) - 1 + (19 / 24);
ELSE
RETURN p_in_dte;
END IF;
Nếu thời gian kết thúc nằm ngoài giờ làm việc, hãy sửa đổi nó thành thời gian kết thúc gần nhất trước đó.
Chức năng thứ 3:
FUNCTION get_days_to_exclude (p_in_start_date DATE,
p_in_finish_date DATE) RETURN NUMBER
--------------------------------------------------------
WITH cte --get all days between start and finish date
AS ( SELECT p_in_start_date + LEVEL - 1 dte
FROM DUAL
CONNECT BY LEVEL <= p_in_finish_date + 1 - p_in_starT_date)
SELECT COUNT (1) * 9 / 24 --mutiply the days with work hours in a day
INTO l_num_holidays
FROM cte
WHERE TO_CHAR (dte, 'dy') = 'sun' --find the count of sundays
OR dte IN --fins the count of holidays, assuming leaves are stored in separate table
(SELECT leave_date
FROM leaves
WHERE leave_date BETWEEN p_in_start_date
AND p_in_finish_date);
l_num_holidays :=
l_num_holidays + ( (p_in_finish_date - p_in_start_date) * (15 / 24)); --also, if the dates span more than a day find the non working hours.
RETURN l_num_holidays;
Hàm này tìm ngày không bị loại trừ trong khi tính toán thời lượng.
Vì vậy, truy vấn cuối cùng phải là một cái gì đó như thế này,
SELECT start_time,
finish_time,
CASE
WHEN work_duration < 0 THEN NUMTODSINTERVAL (0, 'day')
ELSE NUMTODSINTERVAL (work_duration, 'day')
END
FROM (SELECT start_time, finish_time,
--modify_start_time (start_time), modify_finish_time (finish_time),
modify_finish_time (finish_time)
- modify_start_time (start_time)
- get_days_to_exclude (
TRUNC (modify_start_time (start_time)),
TRUNC (modify_finish_time (finish_time)))
work_duration
FROM timings);
Nếu thời lượng nhỏ hơn 0, hãy bỏ qua nó bằng cách đặt nó thành 0.