時間の差を直接計算できます:
SELECT task,
start_time,
end_time,
ROUND(
(
-- Calculate the full weeks difference from the start of ISO weeks.
( TRUNC( end_time, 'IW' ) - TRUNC( start_time, 'IW' ) ) * (10/24) * (6/7)
-- Add the full days for the final week.
+ LEAST( TRUNC( end_time ) - TRUNC( end_time, 'IW' ), 6 ) * (10/24)
-- Subtract the full days from the days of the week before the start date.
- LEAST( TRUNC( start_time ) - TRUNC( start_time, 'IW' ), 6 ) * (10/24)
-- Add the hours of the final day
+ LEAST( GREATEST( end_time - TRUNC( end_time ) - 8/24, 0 ), 10/24 )
-- Subtract the hours of the day before the range starts.
- LEAST( GREATEST( start_time - TRUNC( start_time ) - 8/24, 0 ), 10/24 )
)
-- Multiply to give minutes rather than fractions of full days.
* 24,
15 -- Number of decimal places
) AS work_day_hours_diff
FROM your_table;
サンプルデータの場合:
CREATE TABLE your_table ( TASK, START_TIME, END_TIME ) AS
SELECT 'A', DATE '2017-01-16' + INTERVAL '10:00' HOUR TO MINUTE, DATE '2017-01-23' + INTERVAL '11:35' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'B', DATE '2017-01-18' + INTERVAL '17:53' HOUR TO MINUTE, DATE '2017-01-19' + INTERVAL '08:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'C', DATE '2017-01-13' + INTERVAL '13:00' HOUR TO MINUTE, DATE '2017-01-17' + INTERVAL '14:52' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'D', DATE '2017-01-21' + INTERVAL '10:00' HOUR TO MINUTE, DATE '2017-01-30' + INTERVAL '08:52' HOUR TO MINUTE FROM DUAL;
出力(日付形式YYYY-MM-DD HH24:MI:SS (DY)
):
TASK | START_TIME | END_TIME | WORK_DAY_HOURS_DIFF :--- | :------------------------ | :------------------------ | ------------------: A | 2017-01-16 10:00:00 (MON) | 2017-01-23 11:35:00 (MON) | 61.583333333333333 B | 2017-01-18 17:53:00 (WED) | 2017-01-19 08:00:00 (THU) | .116666666666667 C | 2017-01-13 13:00:00 (FRI) | 2017-01-17 14:52:00 (TUE) | 31.866666666666667 D | 2017-01-21 10:00:00 (SAT) | 2017-01-30 08:52:00 (MON) | 68.866666666666667
db<>ここでフィドル
以前の解決策:
相関階層クエリを使用して、就業日ごとに1つの行を生成し、各日の時間を合計することができます。
SELECT task,
COALESCE( SUM( end_time - start_time ), 0 ) * 24 AS total_hours
FROM (
SELECT task,
GREATEST( t.start_time, d.column_value + INTERVAL '8' HOUR ) AS start_time,
LEAST( t.end_time, d.column_value + INTERVAL '18' HOUR ) AS end_time
FROM your_table t
LEFT OUTER JOIN
TABLE(
CAST(
MULTISET(
SELECT TRUNC( t.start_time + LEVEL - 1 )
FROM DUAL
WHERE TRUNC( t.start_time + LEVEL - 1 ) - TRUNC( t.start_time + LEVEL - 1, 'iw' ) < 6
CONNECT BY TRUNC( t.start_time + LEVEL - 1 ) < t.end_time
) AS SYS.ODCIDATELIST
)
) d
ON ( t.end_time > d.column_value + INTERVAL '8' HOUR
AND t.start_time < d.column_value + INTERVAL '18' HOUR )
)
GROUP BY task;