我意识到这可能是一个多余的问题,但是我一直努力遵循我确实找到的一些示例,我想我会再次询问以提供特定情况的详细信息。
这就是我与之合作的原因:
我能够计算出工作时间,但是我不知道如何进入工作日部分。
答案 0 :(得分:2)
从您的星期五上午8点到星期一上午9点开始:
with dates as (
Select timestamp '2019-05-31 08:00:00' start_date
, timestamp '2019-06-03 09:00:00' end_date
from dual
)
我们需要生成介于两者之间的日期。我们可以通过递归查询来做到这一点:
, recur(start_date, calc_date, end_date) as (
-- Anchor Part
select start_date
, trunc(start_date)
, end_date
from dates
-- Recrusive Part
union all
select start_date
, calc_date+1
, end_date
from recur
where calc_date+1 < end_Date
)
由此,我们需要弄清一些事情,例如,工作日是一个工作日还是一个周末,以及calc_day的开始和结束时间是多少,我们可以采用这些值并使用一点日期算法来查找当天的工作小时数(从我们开始使用时间戳开始,将天数返回到第二个间隔):
, days as (
select calc_date
, case when mod(to_number(to_char(calc_date,'d'))-1,6) != 0 then 1 end isWeekDay
, greatest(start_date, calc_date + interval '8' hour) start_time
, least(end_date, calc_date + interval '16:30' hour to minute) end_time
, least( ( least(end_date, calc_date + interval '16:30' hour to minute)
- greatest(start_date, calc_date + interval '8' hour)
) * case when mod(to_number(to_char(calc_date,'d'))-1,6) != 0 then 1 end
, interval '8' hour
) daily_hrs
from recur
where start_date < (calc_date + interval '16:30' hour to minute)
and (calc_date + interval '8' hour) < end_date
)
请注意,在上述步骤中,我们将每天的工作时间限制为每天8小时,而where子句可防止在工作时间以外的开始或结束日期。最后一步是汇总小时数。不幸的是,Oracle没有任何本机间隔汇总或分析功能,但是我们仍然可以通过将间隔转换为秒,求和然后再将其转换回间隔进行输出来进行管理:
select calc_date
, daily_hrs
, numtodsinterval(sum( extract(hour from daily_hrs)*60*60
+ extract(minute from daily_hrs)*60
+ extract(second from daily_hrs)
) over (order by calc_date)
,'second') run_sum
from days;
我已经完成了上述总和作为分析函数,因此我们可以看到一些中间数据,但是如果您只想要最终输出,则可以将查询的最后一部分更改为此:
select numtodsinterval(sum( extract(hour from daily_hrs)*60*60
+ extract(minute from daily_hrs)*60
+ extract(second from daily_hrs)
)
,'second') run_sum
这是一个 db<>fiddle ,整个查询都在起作用。请注意,在小提琴中,由于一周的第一天是特定于国家/地区的,因此我将数据库会话的NLS_TERRITORY设置更改为AMERICA以使查询正常工作。提琴中的第二个查询替换了特定于地区的功能:
case when mod(to_number(to_char(calc_date,'d'))-1,6) != 0 then 1 end
具有位置和语言不可知的计算:
case when (mod(mod(calc_date - next_day(date '2019-1-1',to_char(date '2019-01-06','day')),7),6)) != 0 then 1 end