假设您有一个工作时间表,以下是 Snowflake SQL 中的解决方案:
select
t.id
, sum(datediff(‘second’,
-- calculate the max of the two start time
(case when t.start <=
w.working_day_start_timestamp
then w.working_day_start_timestamp
else t.start
end),
-- calculate the min of the two end times
(case when t.end >=
w.working_day_end_timestamp
then w.working_day_end_timestamp
else t.end
end)
)) / 3600 -- convert to hourly
as working_hour_diff
from
working_days_times w,
cross join time_intervals t
where -- select all intersecting intervals
(
t.start <= w.working_day_end_timestamp
and
t.end >= w.working_day_start_timestamp
)
and -- select only working days
w.is_working_day
group by
t.id
Run Code Online (Sandbox Code Playgroud)
这是一篇文章,详细介绍了在 SQL 中和作为雪花中的 Javascript UDF 实现这一点的更多细节:
以下示例适用于 BigQuery 标准 SQL
#standardSQL
WITH `project.dataset.working_hours` AS (
SELECT 1 weekday, 'Sun' DAY, NULL start_time, NULL end_time UNION ALL
SELECT 2, 'Mon', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
SELECT 3, 'Tue', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
SELECT 4, 'Wed', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
SELECT 5, 'Thu', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
SELECT 6, 'Fri', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
SELECT 7, 'Sat', TIME(9, 0, 0), TIME(15, 0, 0)
), `project.dataset.availability` AS (
SELECT 'Tom' name, TIMESTAMP '2018-01-10 12:38:04' start_time, TIMESTAMP '2018-02-11 10:38:04' end_time UNION ALL
SELECT 'Mike', TIMESTAMP '2018-01-01 12:35:00', TIMESTAMP '2018-01-01 14:35:00' UNION ALL
SELECT 'Sam', TIMESTAMP '2018-01-06 12:35:00', TIMESTAMP '2018-01-07 14:35:00'
), full_days_minutes AS (
SELECT name,
SUM(TIME_DIFF(h.end_time, h.start_time, MINUTE)) minutes
FROM `project.dataset.availability` a,
UNNEST(GENERATE_DATE_ARRAY(DATE(start_time), DATE(end_time))) DAY
JOIN `project.dataset.working_hours` h
ON h.weekday = EXTRACT(DAYOFWEEK FROM DAY)
GROUP BY name
), corrections AS (
SELECT name,
IFNULL(CASE -- correction for start time
WHEN TIME(a.start_time) > x.end_time THEN TIME_DIFF(x.end_time, x.start_time, MINUTE)
WHEN TIME(a.start_time) < x.start_time THEN 0
ELSE TIME_DIFF(TIME(a.start_time), x.start_time, MINUTE)
END, 0) +
IFNULL(CASE -- correction for end time
WHEN TIME(a.end_time) < y.start_time THEN TIME_DIFF(y.end_time, y.start_time, MINUTE)
WHEN TIME(a.end_time) > y.end_time THEN 0
ELSE TIME_DIFF(y.end_time, TIME(a.end_time), MINUTE)
END, 0)
AS correction
FROM `project.dataset.availability` a
JOIN `project.dataset.working_hours` x ON x.weekday = EXTRACT(DAYOFWEEK FROM a.start_time)
JOIN `project.dataset.working_hours` y ON y.weekday = EXTRACT(DAYOFWEEK FROM a.end_time)
)
SELECT name, minutes - correction AS elapsed_minutes,
ROUND((minutes - correction) / 60, 2) elapsed_hours
FROM full_days_minutes JOIN corrections USING(name)
Run Code Online (Sandbox Code Playgroud)
结果为
Row name elapsed_minutes elapsed_hours
1 Tom 12,622 210.37
2 Mike 120 2
3 Sam 145 2.42
Run Code Online (Sandbox Code Playgroud)
注意:代码假定可用性和工作时间表中的 start_time <= end_time
归档时间: |
|
查看次数: |
757 次 |
最近记录: |