[英]How to remove specific time ranges, from a set of time ranges in SQL?
With this example set of timestamp ranges:使用此示例时间戳范围集:
WITH sessions AS (
(
SELECT
TIMESTAMP('2022-09-24 13:49:32+0100') AS start,
TIMESTAMP('2022-09-26 02:06:17+0100') AS end
UNION ALL
SELECT
TIMESTAMP('2022-09-26 08:42:19+0100'),
TIMESTAMP('2022-09-26 09:41:40+0100'),
UNION ALL
SELECT
TIMESTAMP('2022-09-26 09:53:06+0100'),
TIMESTAMP('2022-09-26 11:20:34+0100'))
)
SELECT * FROM sessions WHERE....
How would I go about removing all time between Fridays 17:00, America/New_York and Monday 09:00 Asia/Shanghai?我 go 如何删除美国/纽约周五 17:00 和亚洲/上海周一 09:00 之间的所有时间?
I really can't seem to figure this out.我似乎真的想不通。
"Best" thing I can think of is generating a table with all Friday/Monday ranges, and joining against that table, using the standard Gaps and Islands solution, is that really the best way?我能想到的“最好”的事情是生成一个包含所有周五/周一范围的表格,并使用标准的 Gaps and Islands 解决方案加入该表格,这真的是最好的方法吗?
Thanks!谢谢!
Edit:编辑:
The context is wait and resolution times for a ticketing system, where only time within the open operating hours should count.上下文是票务系统的等待和解决时间,其中只计算开放营业时间内的时间。 The service is staffed by various international teams, so the services operating hours become more complicated.
该服务由各种国际团队组成,因此服务的运营时间变得更加复杂。
I would expect the results to look like this:我希望结果看起来像这样:
Start End Status
2022-09-24 13:49:32+0100 2022-09-26 02:00:00+0100 Closed
2022-09-26 02:00:00+0100 2022-09-26 02:06:17+0100 Open
2022-09-26 08:42:19+0100 2022-09-26 09:41:40+0100 Open
2022-09-26 09:53:06+0100 2022-09-26 11:20:34+0100 Open
Because the part of the 26th is within the working hours of Shanghai.因为26号这部分是在上海的工作时间内。
Assuming Monday 09:00 Asia/Shanghai corresponds to Sunday 21:00 America/New_York I came up with the following (I only filtered by the column start
, if necessary you can apply the same to end
):假设周一 09:00 Asia/Shanghai 对应于周日 21:00 America/New_York 我想出了以下内容(我只按
start
列过滤,如有必要,您可以将其应用于end
):
WITH sessions AS (
(
SELECT TIMESTAMP('2022-09-24T13:49:32+0100') AS `start`, TIMESTAMP('2022-09-26T02:06:17+0100') AS `end` UNION ALL
SELECT TIMESTAMP('2022-09-26T08:42:19+0100'), TIMESTAMP('2022-09-26T09:41:40+0100'), UNION ALL
SELECT TIMESTAMP('2022-09-26T09:53:06+0100'), TIMESTAMP('2022-09-26T11:20:34+0100'))
)
SELECT *
FROM sessions
WHERE
NOT (
(EXTRACT(DAYOFWEEK FROM start AT TIME ZONE 'America/New_York') = 6 AND EXTRACT(TIME FROM start AT TIME ZONE 'America/New_York') > TIME(17, 0, 0))
OR
(EXTRACT(DAYOFWEEK FROM start AT TIME ZONE 'America/New_York') = 7)
OR
(EXTRACT(DAYOFWEEK FROM start AT TIME ZONE 'America/New_York') = 1 AND EXTRACT(TIME FROM start AT TIME ZONE 'America/New_York') < TIME(21, 0, 0))
)
Short explanation:简短说明:
DAYOFWEEK
gives you the weekday, Sundays being 1
( see docs ). DAYOFWEEK
为您提供工作日,星期日为1
( 请参阅文档)。 For Friday and Sunday I also compare the times with the thresholds and exclude them from the results, Saturday I exclude completely.对于周五和周日,我还将时间与阈值进行比较并将它们从结果中排除,周六我完全排除。
Edit after comments:
评论后编辑:
The following will exclude all periods that fall in the closed time.以下将排除所有属于关闭时间的时段。 Periods that overlap with the closed time are truncated.
与关闭时间重叠的时段将被截断。 Only periods in open time are returned.
仅返回开放时间段。 Added a few comments for explaining the query:
添加了一些注释来解释查询:
-- Assuming closed period in UTC is from Friday 22:00 to Monday 01:00
-- Assuming start and end do not span over the closed period
WITH sessions AS (
(
SELECT TIMESTAMP('2022-09-24T13:49:32+0100') AS `start`, TIMESTAMP('2022-09-26T02:06:17+0100') AS `end` UNION ALL
SELECT TIMESTAMP('2022-09-26T08:42:19+0100'), TIMESTAMP('2022-09-26T09:41:40+0100'), UNION ALL
SELECT TIMESTAMP('2022-09-23T08:42:19+0100'), TIMESTAMP('2022-09-25T09:41:40+0100'), UNION ALL
SELECT TIMESTAMP('2022-09-26T09:53:06+0100'), TIMESTAMP('2022-09-26T11:20:34+0100'))
)
SELECT
CASE
WHEN start_offset IS NOT NULL THEN TIMESTAMP_ADD(TIMESTAMP(DATETIME(EXTRACT(YEAR FROM start), EXTRACT(MONTH FROM start), EXTRACT(DAY FROM start), 1, 0, 0)), INTERVAL start_offset DAY)
ELSE start
END as new_start, -- using the determined offset, time is fixed
CASE
WHEN end_offset IS NOT NULL THEN TIMESTAMP_SUB(TIMESTAMP(DATETIME(EXTRACT(YEAR FROM `end`), EXTRACT(MONTH FROM `end`), EXTRACT(DAY FROM `end`), 22, 0, 0)), INTERVAL end_offset DAY)
ELSE `end`
END as new_end, -- using the determined offset, time is fixed
FROM
(
SELECT
*,
CASE
WHEN (EXTRACT(DAYOFWEEK FROM start) = 6 AND EXTRACT(TIME FROM start) > TIME(22, 0, 0)) THEN 3
WHEN (EXTRACT(DAYOFWEEK FROM start) = 7) THEN 2
WHEN (EXTRACT(DAYOFWEEK FROM start) = 1) THEN 1
WHEN (EXTRACT(DAYOFWEEK FROM start) = 2 AND EXTRACT(TIME FROM start) < TIME(1, 0, 0)) THEN 0
ELSE NULL
END AS start_offset, -- determine how many days to offset the start (adding to start date)
CASE
WHEN (EXTRACT(DAYOFWEEK FROM `end`) = 6 AND EXTRACT(TIME FROM `end`) > TIME(22, 0, 0)) THEN 0
WHEN (EXTRACT(DAYOFWEEK FROM `end`) = 7) THEN 1
WHEN (EXTRACT(DAYOFWEEK FROM `end`) = 1) THEN 2
WHEN (EXTRACT(DAYOFWEEK FROM `end`) = 2 AND EXTRACT(TIME FROM `end`) < TIME(1, 0, 0)) THEN 3
ELSE NULL
END AS end_offset, -- determine how many days to offset the end (subtracting from end date)
FROM sessions
)
WHERE NOT (start_offset IS NOT NULL AND end_offset IS NOT NULL)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.