给定表start_time, end_time
中的两个时间戳计算它们之间发生的总工作时间。
工作时间在您选择的单独表格中定义。
答案 0 :(得分:6)
假设您有一个工作时间表,这里是 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
这里有一篇文章,详细介绍了在 SQL 中以及作为 Snowflake 中的 Javascript UDF 实现此功能的更多细节:
答案 1 :(得分:3)
下面的示例适用于BigQuery Standard 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)
结果为
Row name elapsed_minutes elapsed_hours
1 Tom 12,622 210.37
2 Mike 120 2
3 Sam 145 2.42
注意:代码假定在availability和working_hours表中的start_time&lt; = end_time