在Oracle中按小时分配时间

时间:2013-04-15 10:05:21

标签: sql oracle

我有各种活动的记录,其开始和结束时间可能跨越几小时,如12:00 = 13:30。我需要将时间分配到几小时,以便将时间分配为该活动的12:00 - 1小时,13:00,00:00。实现这一目标的最佳方法是什么?

这是创建表,插入和预期结果。需要帮助请叫我。谢谢!

CREATE TABLE Z_SCHED_ACTIVITY
(
SCHED_ACTIVITY_ID decimal(38),
STARTTIME timestamp,
ENDTIME timestamp,
ACTIVITY_ID decimal(38),
EMPLOYEE_ID decimal(38),
SHIFT_ID decimal(38)
);

插入:

INSERT INTO Z_SCHED_ACTIVITY  VALUES (16452556,{ts '2013-04-11 01:00:00.0'},{ts '2013-04-11 02:00:00.0'},-4107,5217,252849);
INSERT INTO Z_SCHED_ACTIVITY  VALUES (16456677,{ts '2013-04-11 05:30:00.0'},{ts '2013-04-11 05:45:00.0'},-4104,1878,249440);
INSERT INTO Z_SCHED_ACTIVITY  VALUES (16457993,{ts '2013-04-11 03:52:00.0'},{ts '2013-04-11 04:07:00.0'},-4104,5217,252849);
INSERT INTO Z_SCHED_ACTIVITY  VALUES (16613742,{ts '2013-04-11 08:00:00.0'},{ts '2013-04-11 09:00:00.0'},-4107,1878,249440);
INSERT INTO Z_SCHED_ACTIVITY  VALUES (16613744,{ts '2013-04-11 10:30:00.0'},{ts '2013-04-11 10:45:00.0'},-4104,1878,249440);
INSERT INTO Z_SCHED_ACTIVITY  VALUES (16613744,{ts '2013-04-10 23:45.00.0'},{ts '2013-04-11 00:45:00.0'},-4104,1878,249440);

EXPECTED RESULT
Shift ID     EmployeeID            hour start                Sched Time          Activity
249440           1878            04/10/2013 23:00:00           15               -4104
249440           1878            04/11/2013 00:00:00           45               -4104
249440           1878            04/11/2013 05:00:00           15               -4104
249440           1878            04/11/2013 08:00:00           60               -4107
249440           1878            04/11/2013 10:00:00           15               -4104
252849           5217            04/11/2013 01:00:00           60               -4107
252849           5217            04/11/2013 03:00:00            8               -4104
252849           5217            04/11/2013 04:00:00            7               -4104

1 个答案:

答案 0 :(得分:0)

一个有用的技巧是从数据中生成所有可能的每小时时段,然后将其用作连接的一部分,例如:

select min_start + ((level - 1) / 24) as hour_start,
    min_start + (level / 24) as hour_end
from (
    select trunc(min(starttime), 'HH') as min_start,
        trunc(max(endtime), 'HH') as max_end
    from z_sched_activity
)
connect by level <= ((max_end - min_start) * 24) + 1;

HOUR_START          HOUR_END
------------------- -------------------
04/10/2013 23:00:00 04/11/2013 00:00:00
04/11/2013 00:00:00 04/11/2013 01:00:00
04/11/2013 01:00:00 04/11/2013 02:00:00
04/11/2013 02:00:00 04/11/2013 03:00:00
04/11/2013 03:00:00 04/11/2013 04:00:00
04/11/2013 04:00:00 04/11/2013 05:00:00
04/11/2013 05:00:00 04/11/2013 06:00:00
04/11/2013 06:00:00 04/11/2013 07:00:00
04/11/2013 07:00:00 04/11/2013 08:00:00
04/11/2013 08:00:00 04/11/2013 09:00:00
04/11/2013 09:00:00 04/11/2013 10:00:00
04/11/2013 10:00:00 04/11/2013 11:00:00

12 rows selected.

您可以在匹配期间加入基表:

with hours as (
    select min_start + ((level - 1) / 24) as hour_start,
        min_start + (level / 24) as hour_end
    from (
        select trunc(min(starttime), 'HH') as min_start,
            trunc(max(endtime), 'HH') as max_end
        from z_sched_activity
    )
    connect by level <= ((max_end - min_start) * 24) + 1
)
select h.hour_start, h.hour_end, zsa.sched_activity_id, zsa.starttime,
    zsa.endtime, zsa.activity_id, zsa.employee_id, zsa.shift_id
from hours h
join z_sched_activity zsa
on not (zsa.starttime >= h.hour_end or zsa.endtime < h.hour_start)
order by h.hour_start, zsa.sched_activity_id, zsa.starttime;

我不会显示输出,因为它有点乱,但它会显示所有句点,其中一个或多个句点与基础数据starttimeendtime重叠。

然后,您可以计算每个伪记录在匹配期间的时间量:

with hours as (
    select min_start + ((level - 1) / 24) as hour_start,
        min_start + (level / 24) as hour_end
    from (
        select trunc(min(starttime), 'HH') as min_start,
            trunc(max(endtime), 'HH') as max_end
        from z_sched_activity
    )
    connect by level <= ((max_end - min_start) * 24) + 1
)
select zsa.shift_id, zsa.employee_id, h.hour_start,
    (60*24) * (least(h.hour_end, zsa.endtime)
        - greatest(h.hour_start, zsa.starttime)) as sched_time,
    zsa.activity_id
from hours h
join z_sched_activity zsa
on not (zsa.starttime >= h.hour_end or zsa.endtime < h.hour_start)
order by zsa.shift_id, zsa.employee_id, h.hour_start, zsa.sched_activity_id;

  SHIFT_ID EMPLOYEE_ID HOUR_START          SCHED_TIME ACTIVITY_ID
---------- ----------- ------------------- ---------- -----------
    249440        1878 04/10/2013 23:00:00         15       -4104
    249440        1878 04/11/2013 00:00:00         45       -4104
    249440        1878 04/11/2013 05:00:00         15       -4104
    249440        1878 04/11/2013 08:00:00         60       -4107
    249440        1878 04/11/2013 09:00:00          0       -4107
    249440        1878 04/11/2013 10:00:00         15       -4104
    252849        5217 04/11/2013 01:00:00         60       -4107
    252849        5217 04/11/2013 02:00:00          0       -4107
    252849        5217 04/11/2013 03:00:00          8       -4104
    252849        5217 04/11/2013 04:00:00          7       -4104

10 rows selected.

这里有点奇怪的是,对于endtime 2013-04-11 02:00:00.0的记录,该结束时间可以说是在下一个小时的开始,这为您提供sched_time的记录零。您可以通过重复计算将它们排除在where子句中,或者将其包装在外部select中,而不是将其删除,或者您可以添加另一个连接条件,以便根本不考虑它们:

...
from hours h
join z_sched_activity zsa
on not (zsa.starttime >= h.hour_end or zsa.endtime < h.hour_start)
and zsa.endtime != h.hour_start
...

  SHIFT_ID EMPLOYEE_ID HOUR_START          SCHED_TIME ACTIVITY_ID
---------- ----------- ------------------- ---------- -----------
    249440        1878 04/10/2013 23:00:00         15       -4104
    249440        1878 04/11/2013 00:00:00         45       -4104
    249440        1878 04/11/2013 05:00:00         15       -4104
    249440        1878 04/11/2013 08:00:00         60       -4107
    249440        1878 04/11/2013 10:00:00         15       -4104
    252849        5217 04/11/2013 01:00:00         60       -4107
    252849        5217 04/11/2013 03:00:00          8       -4104
    252849        5217 04/11/2013 04:00:00          7       -4104

8 rows selected.