生成具有一系列时间戳的表 - Oracle SQL
Posted
技术标签:
【中文标题】生成具有一系列时间戳的表 - Oracle SQL【英文标题】:Generate a table with a range of timestamps - Oracle SQL 【发布时间】:2020-04-23 04:53:58 【问题描述】:我正在尝试使用以下格式创建一个包含 2 列的表格,其中包含 2019 年的所有日期:-
START_TIME END_TIME
2010-01-01 17:00:00|2019-01-02 17:00:00
2019-01-02 17:00:00|2019-01-03 17:00:00
2019-01-03 17:00:00|2019-01-04 17:00:00
...
...
2019-12-31 17:00:00|2020-01-01 17:00:00
您能帮忙解决其中的错误吗? 请提出任何优化的方法来实现这一点。
CREATE TABLE s.dates_2019
(
ts_range_begin timestamp(6),
ts_range_end timestamp(6),
);
insert into s.dates_2019 (ts_range_begin)
select
to_timestamp('12/31/2018 05:00 PM', 'YYYY-MM-DD HH24:MI:SS') + n.n
from
(select rownum n
from ( select 1 just_a_column
from dual
connect by level <=
to_timestamp('12/31/2019 05:00 PM', 'YYYY-MM-DD HH24:MI:SS')
- to_timestamp('12/31/2018 05:00 PM', 'YYYY-MM-DD HH24:MI:SS')
+ 1
) t
) n
where
to_timestamp('12/31/2018 05:00 PM','YYYY-MM-DD HH24:MI:SS') + n.n <= to_timestamp('12/31/2019 05:00 PM','YYYY-MM-DD HH24:MI:SS')
insert into s.dates_2019 (ts_range_end)
select
to_timestamp('2019-01-01 05:00 PM', 'YYYY-MM-DD HH24:MI:SS') + n.n
from
(select rownum n
from ( select 1 just_a_column
from dual
connect by level <=
to_timestamp('2020-01-01 05:00 PM', 'YYYY-MM-DD HH24:MI:SS')
- to_timestamp('2019-01-01 05:00 PM', 'YYYY-MM-DD HH24:MI:SS')
+ 1
) t
) n
where
to_timestamp('2019-01-01 05:00 PM','YYYY-MM-DD HH24:MI:SS') + n.n <= to_timestamp('2020-01-01 05:00 PM','YYYY-MM-DD HH24:MI:SS')
错误是:-
[Error Code: 30081, SQL State: 99999] ORA-30081: invalid data type for datetime/interval arithmetic
【问题讨论】:
to_timestamp('12/31/2018 05:00 PM', 'YYYY-MM-DD HH24:MI:SS')
格式错误。字符串12/31/2018 05:00 PM
不是YYYY-MM-DD HH24:MI:SS
,它们必须匹配。
【参考方案1】:
这个怎么样?
SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi';
Session altered.
SQL> with dates as
2 (select date '2019-01-01' + 17/24 + level - 1 datum
3 from dual
4 connect by level <= date '2020-01-01' - date '2019-01-01' + 1
5 ),
6 staend as
7 (select datum as start_time,
8 lead(datum) over (order by datum) as end_time
9 from dates
10 )
11 select start_time,
12 end_time
13 from staend
14 where end_time is not null
15 order by start_time;
START_TIME END_TIME
---------------- ----------------
2019-01-01 17:00 2019-01-02 17:00
2019-01-02 17:00 2019-01-03 17:00
2019-01-03 17:00 2019-01-04 17:00
2019-01-04 17:00 2019-01-05 17:00
<snip>
2019-12-30 17:00 2019-12-31 17:00
2019-12-31 17:00 2020-01-01 17:00
365 rows selected.
SQL>
如果你想在表格中插入日期,你真的不需要timestamp
- date
就可以了。
SQL> create table dates_2019
2 (ts_range_begin date,
3 ts_range_end date
4 );
Table created.
SQL> insert into dates_2019 (ts_range_begin, ts_range_end)
2 with dates as
3 (select date '2019-01-01' + 17/24 + level - 1 datum
4 from dual
5 connect by level <= date '2020-01-01' - date '2019-01-01' + 1
6 ),
7 staend as
8 (select datum as start_time,
9 lead(datum) over (order by datum) as end_time
10 from dates
11 )
12 select start_time,
13 end_time
14 from staend
15 where end_time is not null
16 order by start_time;
365 rows created.
SQL>
如果您想汇总周末,请考虑在 lead
分析函数中使用 offset。该偏移量取决于日期名称(星期五)。此外,从结果集中删除周末(第 21 行,where day not in ('sat', 'sun')
)。
SQL> insert into dates_2019 (ts_range_begin, ts_range_end)
2 with dates as
3 (select date '2019-01-01' + 17/24 + level - 1 datum,
4 --
5 to_char(date '2019-01-01' + 17/24 + level - 1,
6 'fmdy', 'nls_date_language = english') day
7 from dual
8 connect by level <= date '2020-01-01' - date '2019-01-01' + 1
9 ),
10 staend as
11 (select datum as start_time,
12 day,
13 lead(datum, case when day = 'fri' then 3
14 else 1
15 end) over (order by datum) as end_time
16 from dates
17 )
18 select start_time,
19 end_time
20 from staend
21 where day not in ('sat', 'sun')
22 and end_time is not null;
261 rows created.
SQL> select * from dates_2019 order by ts_range_begin;
TS_RANGE_BEGIN TS_RANGE_END
---------------- ----------------
2019-01-01 17:00 2019-01-02 17:00
2019-01-02 17:00 2019-01-03 17:00
2019-01-03 17:00 2019-01-04 17:00
2019-01-04 17:00 2019-01-07 17:00 --> aggregated
2019-01-07 17:00 2019-01-08 17:00
2019-01-08 17:00 2019-01-09 17:00
2019-01-09 17:00 2019-01-10 17:00
2019-01-10 17:00 2019-01-11 17:00
2019-01-11 17:00 2019-01-14 17:00 --> aggregated
2019-01-14 17:00 2019-01-15 17:00
2019-01-15 17:00 2019-01-16 17:00
<snip>
【讨论】:
谢谢..有没有一个函数可以用来聚合周末日期(周五到周一),如下所示:- `START_TIME END_TIME -------------- ------------------ 2019-01-01 17:00 2019-01-02 17:00 2019-01-02 17:00 2019-01-03 17:00 2019-01-03 17:00 2019-01-04 17:00 2019-01-04 17:00 2019-01-07 17:00 ` 不客气。我添加了一些聚合周末的代码。请看一下。 非常感谢..这完全解决了我的用例。 没问题,如果有帮助我很高兴。【参考方案2】:我认为您的实际错误是因为减去时间戳会返回一个间隔,而您将结果用作CONNECT BY LEVEL
中的数字。您可以将时间戳转换为日期(您可能会发现 the answers here 很有用)或使用 interval expression 来获取时间戳之间的日期部分。
但如果这是您的实际 SQL 而不是简化,我建议只使用 CONNECT BY
中的日期(如果这是您想要的,您仍然可以在表中保留时间戳)并执行类似...
CREATE TABLE dates_2019
(
ts_range_begin timestamp(6),
ts_range_end timestamp(6)
);
insert into dates_2019 (ts_range_begin)
select
to_timestamp('2018-12-31 17', 'YYYY-MM-DD HH24') + rownum
from
dual
connect by level <= to_date('2019-12-31 17', 'YYYY-MM-DD HH24') - to_date('2018-12-31 17', 'YYYY-MM-DD HH24')
;
update dates_2019 SET ts_range_end = ts_range_begin + 1;
...我在 Oracle 18c 中测试过,但可能适用于 10g。
【讨论】:
以上是关于生成具有一系列时间戳的表 - Oracle SQL的主要内容,如果未能解决你的问题,请参考以下文章