Oracle,SQL,如何获取日期之间的间隔

时间:2017-11-27 09:39:43

标签: sql oracle timestamp intervals

我需要帮助解决问题。实际上,我不知道是否可以直接在SQL中解决它。

我有一份作品清单。每件作品都有一个开始日期和结束日期,格式为

YYYY/MM/DD  HH24:MI:SS

我需要计算这些工作的成本,小时价格取决于工作完成的时间间隔:

Nigth time: 22:00 to 6:00, for example: 20 €/h
Normal time: the rest 17 €/h

所以,如果我有这样的样本:

wo     start                 end
21    2017/11/16 21:25:00    2017/11/16 22:55:00
22    2017/11/17 05:45:00    2017/11/17 07:05:00
23    2017/11/18 23:00:00    2017/11/19 1:10:00
24    2017/11/17 18:00:00    2017/11/17 19:00:00

我需要计算22h和6h之间的日期间隔,其余的乘以相应的价格

wo     rest(minutes)   night(minutes)
21      35              55
22      15              65
23       0              130
24       1               0

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

嘿。如果你真的希望它:)

第五条记录(从2016-10-30开始)已被添加用于测试目的。

SQL> with
  2    src as (select timestamp '2017-11-16 21:25:00' b, timestamp '2017-11-16 22:55:00' f from dual union all
  3            select timestamp '2017-11-17 05:45:00' b, timestamp '2017-11-17 07:05:00' f from dual union all
  4            select timestamp '2017-11-18 23:00:00' b, timestamp '2017-11-19 1:10:00' f from dual union all
  5            select timestamp '2017-11-17 18:00:00' b, timestamp '2017-11-17 19:00:00' f from dual union all
  6            select timestamp '2016-10-30 00:00:00' b, timestamp '2016-11-03 23:00:00' f from dual),
  7    srd as (select b, f, f - b t from src),
  8    mmm as (select min(trunc(b)) b, max(trunc(f)) f from src),
  9    rws as (select b + 6/24 + rownum - 1 b, b + 22/24 + rownum - 1 f from mmm connect by level <= f - b + 1),
 10    mix as (select s.b, s.f, s.t, r.b rb, r.f rf from srd s, rws r where s.f >= r.b (+) and r.f (+) >= s.b),
 11    clc as (select b, f, t, nvl(numtodsinterval(sum((least(f, rf) + 0) - (greatest(b, rb) + 0)), 'DAY'), interval '0' second) d from mix group by b, f, t)
 12  select
 13    to_char(b, 'dd.mm.yyyy hh24:mi') as "datetime begin",
 14    to_char(f, 'dd.mm.yyyy hh24:mi') as "datetime finish",
 15    cast(t as interval day to second(0)) as "total time",
 16    cast(d as interval day to second(0)) as "daytime",
 17    cast(t - d as interval day to second(0)) as "nighttime"
 18  from
 19    clc
 20  order by
 21    1, 2;

datetime begin     datetime finish    total time     daytime        nighttime
------------------ ------------------ -------------- -------------- --------------
16.11.2017 21:25   16.11.2017 22:55   +00 01:30:00   +00 00:35:00   +00 00:55:00
17.11.2017 05:45   17.11.2017 07:05   +00 01:20:00   +00 01:05:00   +00 00:15:00
17.11.2017 18:00   17.11.2017 19:00   +00 01:00:00   +00 01:00:00   +00 00:00:00
18.11.2017 23:00   19.11.2017 01:10   +00 02:10:00   +00 00:00:00   +00 02:10:00
30.10.2016 00:00   03.11.2016 23:00   +04 23:00:00   +03 08:00:00   +01 15:00:00

答案 1 :(得分:0)

另一种方法是更多强力,但它允许将间隔配置与报告区分开来。 它进入了三个方面:

1)定义当天aech分钟的费率类型(如果需要,更改粒度)

create table day_config as
with helper as (
select 
rownum -1 minute_id 
from dual connect by level <= 24*60),
helper2 as (
select 
minute_id,
trunc(minute_id/60) hour_no,
mod(minute_id,60) minute_no
from helper) 
select
minute_id,hour_no, minute_no,
case when hour_no >= 22 or hour_no <= 5 then 0 else 1 end rate_id
from helper2;

select * from day_config order by minute_id;

 MINUTE_ID    HOUR_NO  MINUTE_NO    RATE_ID
---------- ---------- ---------- ----------
         0          0          0          0 
         1          0          1          0 
         2          0          2          0 
         3          0          3          0 
         4          0          4          0 
         5          0          5          0 
         6          0          6          0 
         7          0          7          0 
         8          0          8          0 
         9          0          9          0 

此处rate_id表示nigth,rate_id表示一天。 优点是,您可以根据需要引入尽可能多的费率类型。

2)扩展所需时间间隔的配置,例如到了整整一年。 所以现在我们在一年中的每一分钟都有配置,即适用的费率。

create or replace view year_config as
select my_date + MINUTE_ID / (24*60) minute_ts , MINUTE_ID, HOUR_NO, MINUTE_NO, RATE_ID from day_config 
cross join 
(select DATE '2017-01-01' + rownum -1 as my_date from dual connect by level <= 365)
order by 1,2;

select * from (
select * from year_config
order by 1)
where rownum <= 5;

MINUTE_TS            MINUTE_ID    HOUR_NO  MINUTE_NO    RATE_ID
------------------- ---------- ---------- ---------- ----------
01-01-2017 00:00:00          0          0          0          0 
01-01-2017 00:01:00          1          0          1          0 
01-01-2017 00:02:00          2          0          2          0 
01-01-2017 00:03:00          3          0          3          0 
01-01-2017 00:04:00          4          0          4          0

3)报告就像加入我们的配置表一样简单,限制了RATE中的间隔(半开)和分组。

select b, f,RATE_ID, count(*) minute_cnt 
from tst join year_config c on c.MINUTE_TS >= tst.b and c.MINUTE_TS < tst.f 
group by b, f,RATE_ID
order by b, f,RATE_ID;

B                   F                      RATE_ID MINUTE_CNT
------------------- ------------------- ---------- ----------
16-11-2017 21:25:00 16-11-2017 22:55:00          0         55 
16-11-2017 21:25:00 16-11-2017 22:55:00          1         35 
17-11-2017 05:45:00 17-11-2017 07:05:00          0         15 
17-11-2017 05:45:00 17-11-2017 07:05:00          1         65 
17-11-2017 18:00:00 17-11-2017 19:00:00          1         60 
18-11-2017 23:00:00 19-11-2017 01:10:00          0        130