我如何将工作时间转换为布尔值?
how do i convert the working hours to Boolean?
如何转换工作时间 08:00:00-11:59:00;13:00:00-16:59:00;转换为 48 位布尔格式,如
"000000000000000011111111001111111100000000000000"
其中每个数字是指使用 Oracle SQL 查询的 30 分钟粒度?
假设您从一个字符串开始,该字符串始终以分号分隔 from/to 对,最后一对后有一个尾随分号;那些时间总是 HH24:MI:SS ,秒数总是零,如图所示;然后...您可以将字符串拆分为多个字符串对,代表每个 from/to 对:
select regexp_substr('08:00:00-11:59:00;13:00:00-16:59:00;', '(.*?)(;|-|$)', 1, (2 * level - 1), null, 1),
regexp_substr('08:00:00-11:59:00;13:00:00-16:59:00;', '(.*?)(;|-|$)', 1, 2 * level, null, 1)
from dual
connect by level <= regexp_count('08:00:00-11:59:00;13:00:00-16:59:00;', ';')
REGEXP_S REGEXP_S
-------- --------
08:00:00 11:59:00
13:00:00 16:59:00
并且您可以在标称的一天内生成所有半小时块(选择一个不受 DST 转换影响的块):
select to_char(date '2000-01-01' + ((level - 1) / 48), 'HH24:MI":00"')
from dual
connect by level <= 48
TO_CHAR(
--------
00:00:00
00:30:00
01:00:00
01:30:00
02:00:00
...
23:00:00
23:30:00
然后使用字符串比较(这就是时间格式很重要的原因)将它们连接在一起以查看重叠的地方;为简单起见,使用 CTE 提供初始字符串,然后提供前两个查询的结果:
with t1 (working_hours) as (
select '08:00:00-11:59:00;13:00:00-16:59:00;' from dual
),
t2 (working_from, working_to) as (
select regexp_substr(working_hours, '(.*?)(;|-|$)', 1, (2 * level - 1), null, 1),
regexp_substr(working_hours, '(.*?)(;|-|$)', 1, 2 * level, null, 1)
from t1
connect by level <= regexp_count(working_hours, ';')
),
t3 (block_from) as (
select to_char(date '2000-01-01' + ((level - 1) / 48), 'HH24:MI":00"')
from dual
connect by level <= 48
)
select block_from,
case when t2.working_from is null then 0 else 1 end as flag
from t3
left join t2 on t2.working_from <= t3.block_from and t2.working_to >= t3.block_from
BLOCK_FROM FLAG
---------- ----
00:00:00 0
00:30:00 0
...
07:30:00 0
08:00:00 1
08:30:00 1
...
11:00:00 1
11:30:00 1
12:00:00 0
12:30:00 0
13:00:00 1
13:30:00 1
...
16:00:00 1
16:30:00 1
17:00:00 0
...
23:00:00 0
23:30:00 0
然后最终将它们聚合成一个结果字符串:
with t1 (working_hours) as (
select '08:00:00-11:59:00;13:00:00-16:59:00;' from dual
),
t2 (working_from, working_to) as (
select regexp_substr(working_hours, '(.*?)(;|-|$)', 1, (2 * level - 1), null, 1),
regexp_substr(working_hours, '(.*?)(;|-|$)', 1, 2 * level, null, 1)
from t1
connect by level <= regexp_count(working_hours, ';')
),
t3 (block_from) as (
select to_char(date '2000-01-01' + ((level - 1) / 48), 'HH24:MI":00"')
from dual
connect by level <= 48
)
select listagg(case when t2.working_from is null then 0 else 1 end)
within group (order by t3.block_from) as result
from t3
left join t2 on t2.working_from <= t3.block_from and t2.working_to >= t3.block_from
RESULT
------------------------------------------------
000000000000000011111111001111111100000000000000
如果您的初始字符串实际上来自 table 并且您需要一次对多行进行此转换,那么连接拆分会稍微复杂一些,递归 CTE 可能更合适table 那部分。
纯属娱乐,here's an example。
如何转换工作时间 08:00:00-11:59:00;13:00:00-16:59:00;转换为 48 位布尔格式,如
"000000000000000011111111001111111100000000000000"
其中每个数字是指使用 Oracle SQL 查询的 30 分钟粒度?
假设您从一个字符串开始,该字符串始终以分号分隔 from/to 对,最后一对后有一个尾随分号;那些时间总是 HH24:MI:SS ,秒数总是零,如图所示;然后...您可以将字符串拆分为多个字符串对,代表每个 from/to 对:
select regexp_substr('08:00:00-11:59:00;13:00:00-16:59:00;', '(.*?)(;|-|$)', 1, (2 * level - 1), null, 1),
regexp_substr('08:00:00-11:59:00;13:00:00-16:59:00;', '(.*?)(;|-|$)', 1, 2 * level, null, 1)
from dual
connect by level <= regexp_count('08:00:00-11:59:00;13:00:00-16:59:00;', ';')
REGEXP_S REGEXP_S
-------- --------
08:00:00 11:59:00
13:00:00 16:59:00
并且您可以在标称的一天内生成所有半小时块(选择一个不受 DST 转换影响的块):
select to_char(date '2000-01-01' + ((level - 1) / 48), 'HH24:MI":00"')
from dual
connect by level <= 48
TO_CHAR(
--------
00:00:00
00:30:00
01:00:00
01:30:00
02:00:00
...
23:00:00
23:30:00
然后使用字符串比较(这就是时间格式很重要的原因)将它们连接在一起以查看重叠的地方;为简单起见,使用 CTE 提供初始字符串,然后提供前两个查询的结果:
with t1 (working_hours) as (
select '08:00:00-11:59:00;13:00:00-16:59:00;' from dual
),
t2 (working_from, working_to) as (
select regexp_substr(working_hours, '(.*?)(;|-|$)', 1, (2 * level - 1), null, 1),
regexp_substr(working_hours, '(.*?)(;|-|$)', 1, 2 * level, null, 1)
from t1
connect by level <= regexp_count(working_hours, ';')
),
t3 (block_from) as (
select to_char(date '2000-01-01' + ((level - 1) / 48), 'HH24:MI":00"')
from dual
connect by level <= 48
)
select block_from,
case when t2.working_from is null then 0 else 1 end as flag
from t3
left join t2 on t2.working_from <= t3.block_from and t2.working_to >= t3.block_from
BLOCK_FROM FLAG
---------- ----
00:00:00 0
00:30:00 0
...
07:30:00 0
08:00:00 1
08:30:00 1
...
11:00:00 1
11:30:00 1
12:00:00 0
12:30:00 0
13:00:00 1
13:30:00 1
...
16:00:00 1
16:30:00 1
17:00:00 0
...
23:00:00 0
23:30:00 0
然后最终将它们聚合成一个结果字符串:
with t1 (working_hours) as (
select '08:00:00-11:59:00;13:00:00-16:59:00;' from dual
),
t2 (working_from, working_to) as (
select regexp_substr(working_hours, '(.*?)(;|-|$)', 1, (2 * level - 1), null, 1),
regexp_substr(working_hours, '(.*?)(;|-|$)', 1, 2 * level, null, 1)
from t1
connect by level <= regexp_count(working_hours, ';')
),
t3 (block_from) as (
select to_char(date '2000-01-01' + ((level - 1) / 48), 'HH24:MI":00"')
from dual
connect by level <= 48
)
select listagg(case when t2.working_from is null then 0 else 1 end)
within group (order by t3.block_from) as result
from t3
left join t2 on t2.working_from <= t3.block_from and t2.working_to >= t3.block_from
RESULT
------------------------------------------------
000000000000000011111111001111111100000000000000
如果您的初始字符串实际上来自 table 并且您需要一次对多行进行此转换,那么连接拆分会稍微复杂一些,递归 CTE 可能更合适table 那部分。
纯属娱乐,here's an example。