gpt4 book ai didi

sql - 按小时分组的开始时间和结束时间的差异

转载 作者:行者123 更新时间:2023-12-01 12:48:04 26 4
gpt4 key购买 nike

我的表有类似下面的信息

Emp  Date       START_TIME            END_TIME             Code     Minutes
--- -------- ------------------- ------------------- ---- -------
E1 11/1/2012 11/1/2012 6:55:00 AM 11/1/2012 7:01:00 AM C1 6
E1 11/1/2012 11/1/2012 6:57:00 AM 11/1/2012 8:01:00 AM C2 64
E2 11/1/2012 11/1/2012 6:57:00 AM 11/1/2012 8:00:00 AM C2 63
E1 11/2/2012 11/2/2012 7:35:00 AM 11/2/2012 8:01:00 AM C1 26

预期输出是

Date       Code  Range                        Minutes
--------- ---- ----------------------- -------
11/1/2012 C1 6:30:00 AM-7:00:00 AM 5
11/1/2012 C1 7:00:00 AM-7:30:00 AM 1
11/1/2012 C2 6:30:00 AM-7:00:00 AM 6
11/1/2012 C2 7:00:00 AM-7:30:00 AM 60
11/1/2012 C2 7:30:00 AM-8:00:00 AM 60
11/1/2012 C2 8:00:00 AM-8:30:00 AM 1
11/2/2012 C1 7:30:00 AM-8:00:00 AM 25
11/2/2012 C1 8:00:00 AM-8:30:00 AM 1

不考虑 Emp 字段,我想按日期分组,并根据每次 30 分钟内花费的总时间进行编码。 我的限制是使用 select 语句实现此目的,即只能通过 SQL 查询,因为 PL/SQL 是不允许的。提前致谢!

最佳答案

涉及模型条款的解决方案。

首先让我们计算每个条目所需的 30 分钟 block 的数量。

SQL> select emp, start_time, end_time, code,
2 trunc(start_time, 'mi')
3 - (mod(to_char(trunc(start_time, 'mi'), 'mi'), 30) / 1440) start_block,
4 ceil(2*24*(end_time-(trunc(start_time, 'mi')
5 - (mod(to_char(trunc(start_time, 'mi'), 'mi'), 30) / 1440)))) blocks
6 from tab f
7 /

EM START_TIME END_TIME CO START_BLOCK BLOCKS
-- ---------------------- ---------------------- -- ---------------------- ----------
E1 11/01/2012 06:55:00 am 11/01/2012 07:01:00 am C1 11/01/2012 06:30:00 am 2
E1 11/01/2012 06:57:00 am 11/01/2012 08:01:00 am C2 11/01/2012 06:30:00 am 4
E2 11/01/2012 06:57:00 am 11/01/2012 08:00:00 am C2 11/01/2012 06:30:00 am 3
E1 11/02/2012 07:35:00 am 11/02/2012 08:01:00 am C1 11/02/2012 07:30:00 am 2

现在,我们使用模型子句生成行以将其分成 30 分钟的时间段。

SQL> with foo as (select rownum id, emp, start_time, end_time, code,
2 trunc(start_time, 'mi')
3 - (mod(to_char(trunc(start_time, 'mi'), 'mi'), 30) / 1440) start_block,
4 ceil(2*24*(end_time-(trunc(start_time, 'mi')
5 - (mod(to_char(trunc(start_time, 'mi'), 'mi'), 30) / 1440)))) blocks
6 from tab f)
7 select trunc(start_time) thedate, code, emp, range, minutes
8 from foo
9 model partition by(id)
10 dimension by(0 as f)
11 measures(code, emp, start_time, end_time, start_block, blocks,
12 sysdate as start_range,
13 sysdate as end_range,
14 cast(0 as number) minutes,
15 cast('' as varchar2(50)) range)
16 rules (start_range [for f from 0 to blocks[0]-1 increment 1] = start_block[0] + (30*cv(f)/1440),
17 end_range[any] = start_range[cv()] + (30/1440),
18 code[any] = code[0],
19 emp[any] = emp[0],
20 start_time[any] = start_time[0],
21 end_time[any] = end_time[0],
22 range [any] = to_char(start_range[cv()], 'dd/mm/yyyy hh:mi:ss am') || ' - ' || to_char(end_range[cv()], 'dd/mm/yyyy hh24:mi:ss am'),
23 minutes [any] = case
24 when start_time[0] between start_range[cv()] and end_range[cv()]
25 then 1440 *(end_range[cv()] - start_time[0])
26 when end_time[0] between start_range[cv()] and end_range[cv()]
27 then 1440 *(end_time[0] - start_range[cv()])
28 else 1440 * (end_range[cv()] - start_range[cv()])
29 end );

CO EM RANGE MINUTES
-- -- -------------------------------------------------- ----------
C2 E2 11/01/2012 06:30:00 am - 11/01/2012 07:00:00 am 3
C2 E2 11/01/2012 07:00:00 am - 11/01/2012 07:30:00 am 30
C2 E2 11/01/2012 07:30:00 am - 11/01/2012 08:00:00 am 30
C1 E1 11/01/2012 06:30:00 am - 11/01/2012 07:00:00 am 5
C1 E1 11/01/2012 07:00:00 am - 11/01/2012 07:30:00 am 1
C1 E1 11/02/2012 07:30:00 am - 11/02/2012 08:00:00 am 25
C1 E1 11/02/2012 08:00:00 am - 11/02/2012 08:30:00 am 1
C2 E1 11/01/2012 06:30:00 am - 11/01/2012 07:00:00 am 3
C2 E1 11/01/2012 07:00:00 am - 11/01/2012 07:30:00 am 30
C2 E1 11/01/2012 07:30:00 am - 11/01/2012 08:00:00 am 30
C2 E1 11/01/2012 08:00:00 am - 11/01/2012 08:30:00 am 1

11 rows selected.

所以我们按以下方式划分:

partition by(id)

即通过唯一引用。然后我们将生成具有我们维度的行

dimension by(0 as f)

结合部分规则:

for f from 0 to blocks[0]-1  increment 1

所以 start_range 列是用start_range [for f from 0 to blocks[0]-1 increment 1] = start_block[0] + (30*cv(f)/1440),

start_block[0] 在第一个查询中,例如:

EM START_TIME             END_TIME               CO START_BLOCK                BLOCKS
-- ---------------------- ---------------------- -- ---------------------- ----------
E1 11/01/2012 06:55:00 am 11/01/2012 07:01:00 am C1 11/01/2012 06:30:00 am 2

所以对于这一行,它的计算结果为

start_range[0 to 1] = 11/01/2012 06:30:00 am + (30minutes * the value of f)

start_range[0] = 11/01/2012 06:30:00 am + (30min*0) = 11/01/2012 06:30:00 am
start_range[1] = 11/01/2012 06:30:00 am + (30min*1) = 11/01/2012 07:00:00 am

剩下的就很简单了:

end_range[any]  =  start_range[cv()] + (30/1440),

表示对于当前行的 end-range,我们采用 start_range 并添加 30 分钟。

range 列是 start_range 和 end_range 的串联:

range [any] = to_char(start_range[cv()], 'dd/mm/yyyy hh:mi:ss am') || ' - ' || to_char(end_range[cv()], 'dd/mm/yyyy hh24:mi:ss am'),

最后为了计算该范围内的分钟数:

minutes [any]   = case
when start_time[0] between start_range[cv()] and end_range[cv()]
then 1440 *(end_range[cv()] - start_time[0])
when end_time[0] between start_range[cv()] and end_range[cv()]
then 1440 *(end_time[0] - start_range[cv()])
else 1440 * (end_range[cv()] - start_range[cv()])
end );
  1. 如果 start_time 位于范围内,则取范围的末尾 - 开始时间
  2. 如果 end_time 位于范围内,则取 end_time - 范围的开始
  3. 否则为 end_range - start_range。

1440只是以分钟的形式得到答案。

现在我们可以将它们全部分组:

SQL> with foo as (select rownum id, emp, start_time, end_time, code,
2 trunc(start_time, 'mi')
3 - (mod(to_char(trunc(start_time, 'mi'), 'mi'), 30) / 1440) start_block,
4 ceil(2*24*(end_time-(trunc(start_time, 'mi')
5 - (mod(to_char(trunc(start_time, 'mi'), 'mi'), 30) / 1440)))) blocks
6 from tab f)
7 select thedate, code, range, sum(minutes) minutes
8 from (select trunc(start_time) thedate, code, emp, range, minutes
9 from foo
10 model partition by(id)
11 dimension by(0 as f)
12 measures(code, emp, start_time, end_time, start_block, blocks,
13 sysdate as start_range,
14 sysdate as end_range,
15 cast(0 as number) minutes,
16 cast('' as varchar2(50)) range)
17 rules (start_range [for f from 0 to blocks[0]-1 increment 1] = start_block[0] + (30*cv(f)/1440),
18 code[any] = code[0],
19 emp[any] = emp[0],
20 end_range[any] = start_range[cv()] + (30/1440),
21 start_time[any] = start_time[0],
22 end_time[any] = end_time[0],
23 range [any] = to_char(start_range[cv()], 'dd/mm/yyyy hh:mi:ss am') || ' - ' || to_char(end_range[cv()], 'dd/mm/yyyy hh24:mi:ss am'),
24 minutes [any] = case
25 when start_time[0] between start_range[cv()] and end_range[cv()]
26 then 1440 *(end_range[cv()] - start_time[0])
27 when end_time[0] between start_range[cv()] and end_range[cv()]
28 then 1440 *(end_time[0] - start_range[cv()])
29 else 1440 * (end_range[cv()] - start_range[cv()])
30 end ))
31 group by thedate, code, range
32 order by thedate, code, range;

THEDATE CO RANGE MINUTES
---------- -- -------------------------------------------------- ----------
11/01/2012 C1 11/01/2012 06:30:00 am - 11/01/2012 07:00:00 am 5
11/01/2012 C1 11/01/2012 07:00:00 am - 11/01/2012 07:30:00 am 1
11/01/2012 C2 11/01/2012 06:30:00 am - 11/01/2012 07:00:00 am 6
11/01/2012 C2 11/01/2012 07:00:00 am - 11/01/2012 07:30:00 am 60
11/01/2012 C2 11/01/2012 07:30:00 am - 11/01/2012 08:00:00 am 60
11/01/2012 C2 11/01/2012 08:00:00 am - 11/01/2012 08:30:00 am 1
11/02/2012 C1 11/02/2012 07:30:00 am - 11/02/2012 08:00:00 am 25
11/02/2012 C1 11/02/2012 08:00:00 am - 11/02/2012 08:30:00 am 1

关于sql - 按小时分组的开始时间和结束时间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14196688/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com