Oracle生成连续的数字/字符/时间序列的常用语法

 更新时间:2024年04月15日 10:40:31   作者:不剪发的Tony老师  
这篇文章主要介绍了Oracle生成连续的数字/字符/时间序列的常用语法,在 Oracle 中实现数据行生成的方法有很多,本文只介绍几种常用的语法,文中有相关的代码示例供大家参考,需要的朋友可以参考下

在 Oracle 中实现数据行生成的方法有很多,本文只介绍几种常用的语法。

使用层次查询生成序列

Oracle 提供了 CONNECT BY 层次查询,可以用于生成数字序列。

生成一个连接的数字序列

以下语句使用 CONNECT BY 和 LEVEL 伪列生成了一个连续的数字序列:

SELECT LEVEL AS n
FROM dual
WHERE LEVEL >= 11
CONNECT BY LEVEL <= 15;
N |
--|
11|
12|
13|
14|
15|

通过修改查询条件中的 LEVEL 范围,可以返回不同的数字序列。

除了使用 LEVEL 伪列之外,也可以使用 ROWNUM 伪列实现相同的功能:

SELECT rownum AS n
FROM dual
CONNECT BY LEVEL <= 5;
N|
-|
1|
2|
3|
4|
5|

生成一个间隔的数字序列

以下查询利用 mod 函数返回了一个从 2 到 15 之间、增量为 3 的数字序列:

SELECT LEVEL AS n
FROM dual
WHERE LEVEL >= 2 AND MOD(LEVEL-2, 3)=0
CONNECT BY LEVEL <= 15;
N |
--|
 2|
 5|
 8|
11|
14|

以下查询返回了一个增量为 -2.5、范围从 15 到 1.4 之间的降序数字序列:

SELECT (LEVEL-1) * -2.5 + 15 AS n
FROM dual
WHERE LEVEL >= 1
CONNECT BY (LEVEL-1) * -2.5 + 15 >= 1.4;
N   |
----|
  15|
12.5|
  10|
 7.5|
   5|
 2.5|

生成一个连续的字符序列

基于上面的层次查询和 chr(n) 函数可以生成连续的字符序列。例如:

SELECT CHR(LEVEL-1+65) AS letter
FROM dual 
CONNECT BY LEVEL-1 <= 70-65;
LETTER|
------|
A     |
B     |
C     |
D     |
E     |
F     |

该查询返回了字符 A 到 F 的序列,chr(n) 函数用于将 ASCII 编码转化为相应的字符。

生成一个间隔的时间序列

同样基于以上层次查询和时间加减法可以生成间隔的时间序列。例如:

SELECT TIMESTAMP '2020-01-01 00:00:00' + (LEVEL-1)/24 AS ts
FROM dual 
CONNECT BY LEVEL <= 12;
TS                 |
-------------------|
2020-01-01 00:00:00|
2020-01-01 01:00:00|
2020-01-01 02:00:00|
2020-01-01 03:00:00|
2020-01-01 04:00:00|
2020-01-01 05:00:00|
2020-01-01 06:00:00|
2020-01-01 07:00:00|
2020-01-01 08:00:00|
2020-01-01 09:00:00|
2020-01-01 10:00:00|
2020-01-01 11:00:00|

该查询返回了 2020-01-01 00:00:00 到 2020-01-01 12:00:00、间隔为 1 小时的所有时间点。

使用表函数生成序列

Oracle 支持表函数(table function),也就是返回结果为集合(表)的函数,可以用于模拟 PostgreSQL 中的 generate_series 函数。

创建模拟的 generate_series 函数

我们创建一个 PL/SQL 函数 generate_series:

CREATE OR REPLACE FUNCTION generate_series (pstart IN NUMBER, pstop IN NUMBER, pstep IN NUMBER DEFAULT 1)
RETURN sys.odcinumberlist DETERMINISTIC PIPELINED
AS
BEGIN
  IF (pstep = 0) THEN
    raise_application_error(-20001, 'step size cannot equal zero!');
  END IF;
  
  IF (pstart > pstop AND pstep > 0) OR (pstart < pstop AND pstep < 0) THEN
    RETURN;
  END IF;
  
  FOR i IN 0 .. floor(abs((pstop-pstart)/pstep)) LOOP
    PIPE ROW (pstart + i * pstep);
  END LOOP;
    
  RETURN;
END generate_series;

其中,sys.odcinumberlist 是 Oracle 预定义的变长数组类型;PIPELINED 表示定义管道表函数;pstart 表示数据序列的起点,pstop 表示数据序列的终点,pstep 表示每次的增量,不允许为 0,默认为 1。

使用 generate_series 函数生成序列

创建了 generate_series 函数之后,我们就可以用它来生成各种序列值。例如:

SELECT * FROM TABLE(generate_series(11, 15));
COLUMN_VALUE|
------------|
          11|
          12|
          13|
          14|
          15|

SELECT * FROM TABLE(generate_series(15, 1.4, -2.5));
COLUMN_VALUE|
------------|
          15|
        12.5|
          10|
         7.5|
           5|
         2.5|

其中,TABLE 函数用于将数组转换为表;第一个函数返回了 11 到 15 的连续整数;第二个函数返回了 15 到 1.4 之间增量为 -2.5 的降序序列。

我们同样可以使用 generate_series 函数生成字符序列和时间序列:

SELECT chr(column_value) FROM TABLE(generate_series(65, 70));
CHR(COLUMN_VALUE)|
-----------------|
A                |
B                |
C                |
D                |
E                |
F                |

SELECT TIMESTAMP '2020-01-01 00:00:00' + (column_value-1)/24 AS ts
FROM TABLE(generate_series(1, 12));
TS                 |
-------------------|
2020-01-01 00:00:00|
2020-01-01 01:00:00|
2020-01-01 02:00:00|
2020-01-01 03:00:00|
2020-01-01 04:00:00|
2020-01-01 05:00:00|
2020-01-01 06:00:00|
2020-01-01 07:00:00|
2020-01-01 08:00:00|
2020-01-01 09:00:00|
2020-01-01 10:00:00|
2020-01-01 11:00:00|

使用通用表表达式生成序列

生成一个等差数字序列

通用表表达式(Common Table Expression)的递归调用可以用于生成各种数列。例如:

WITH t(n) AS (
  SELECT 1 FROM dual
  UNION ALL
  SELECT n+2 FROM t WHERE n < 9
)
SELECT n FROM t;
N|
-|
1|
3|
5|
7|
9|

以上语句生成了一个从 1 递增到 9、增量为 2 的数列,执行过程如下:

  • 首先,执行 CTE 中的初始化查询,生成一行数据(1);
  • 然后,第一次执行递归查询,判断 n < 9,生成一行数据 3(n+2);
  • 接着,重复执行递归查询,生成更多的数据;直到 n = 9 时不满足条件终止递归;此时临时表 t 中包含 5 条数据;
  • 最后,执行主查询,返回所有的数据。

生成一个等比数字序列

上文模拟的 generate_series 函数只能生成等差数列,通用表表达式则可以生成更复杂的数列,例如等比数列:

WITH t(n) AS (
  SELECT 1 FROM dual
  UNION ALL
  SELECT n*3 FROM t WHERE n < 100
)
SELECT n FROM t;
N  |
---|
  1|
  3|
  9|
 27|
 81|
243|

从第二行开始,每个数字都是上一行的 3 倍。

生成斐波那契数列

斐波那契数列(Fibonacci series)是指从数字 0 和 1(或者从 1 和 1)开始,后面的每个数字等于它前面两个数字之和(0、1、1、2、3、5、8、13、21、…)。使用通用表表达式可以很容易地生成斐波那契数列:

WITH fibonacci (n, fib_n, next_fib_n) AS (
  SELECT 1, 0, 1 FROM dual
  UNION ALL
  SELECT n + 1, next_fib_n, fib_n + next_fib_n
  FROM fibonacci
  WHERE n < 10 )
SELECT * FROM fibonacci;
N |FIB_N|NEXT_FIB_N|
--|-----|----------|
 1|    0|         1|
 2|    1|         1|
 3|    1|         2|
 4|    2|         3|
 5|    3|         5|
 6|    5|         8|
 7|    8|        13|
 8|   13|        21|
 9|   21|        34|
10|   34|        55|

其中,字段 n 表示该行包含了第 n 个斐波那契数列值;字段 fib_n 表示斐波那契数列值;字段 next_fib_n 表示下一个斐波那契数列值。

生成一个连续的字符序列

基于通用表表达式和 CHR(n) 函数同样可以生成连续的字符序列,例如:

WITH t(n) AS (
  SELECT 65 FROM dual
  UNION ALL
  SELECT n+1 FROM t WHERE n <= 70
)
SELECT chr(n) FROM t;
CHR(N)|
------|
A     |
B     |
C     |
D     |
E     |
F     |
G     |

生成一个间隔的时间序列

以下语句使用递归通用表表达式生成一个时间序列:

WITH ts(v) AS (
  SELECT TIMESTAMP '2020-01-01 00:00:00' FROM dual
  UNION ALL
  SELECT v + 1/24 FROM ts WHERE v < TIMESTAMP '2020-01-01 12:00:00'
)
SELECT v FROM ts;
V                  |
-------------------|
2020-01-01 00:00:00|
2020-01-01 01:00:00|
2020-01-01 02:00:00|
2020-01-01 03:00:00|
2020-01-01 04:00:00|
2020-01-01 05:00:00|
2020-01-01 06:00:00|
2020-01-01 07:00:00|
2020-01-01 08:00:00|
2020-01-01 09:00:00|
2020-01-01 10:00:00|
2020-01-01 11:00:00|
2020-01-01 12:00:00|

以上查询返回了一个表,数据为 2020-01-01 00:00:00 到 2020-01-01 12:00:00,间隔为 1 小时的时间点。

到此这篇关于Oracle生成连续的数字/字符/时间序列的常用语法的文章就介绍到这了,更多相关Oracle连续数字/字符/时间序列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Oracle(90)数据库如何创建用户(User)

    Oracle(90)数据库如何创建用户(User)

    这篇文章主要介绍了在Oracle数据库中创建用户的过程,包括连接到数据库、创建用户、分配权限、分配表空间和设置账户状态,提供了详细的步骤和代码示例,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-12-12
  • 登录oracle数据库时密码忘记的解决方法

    登录oracle数据库时密码忘记的解决方法

    登录本地oracle数据库时,忘记密码了,这种情况时有发生,下面有个不错的解决方法,希望对大家有所帮助
    2014-01-01
  • PL/SQL登录Oracle数据库报错ORA-12154:TNS:无法解析指定的连接标识符已解决(本地未安装Oracle需要连接服务器上的)

    PL/SQL登录Oracle数据库报错ORA-12154:TNS:无法解析指定的连接标识符已解决(本地未安装Oracle

    这篇文章主要介绍了PL/SQL登录Oracle数据库报错ORA-12154:TNS:无法解析指定的连接标识符已解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Oracle表空间与权限的深入讲解

    Oracle表空间与权限的深入讲解

    Oracle表空间(tablespaces)是一个逻辑的概念,真正存放数据的是数据文件(data files),下面这篇文章主要给大家介绍了关于Oracle表空间与权限的相关资料,需要的朋友可以参考下
    2021-11-11
  • oracle 监听 lsnrctl 命令 (推荐)

    oracle 监听 lsnrctl 命令 (推荐)

    这篇文章主要介绍了oracle 监听 lsnrctl 命令 ,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-03-03
  • ORACLE隐藏参数查看及修改的方法

    ORACLE隐藏参数查看及修改的方法

    这篇文章主要介绍了ORACLE隐藏参数查看及修改的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • Oracle数据完整性和锁机制简析

    Oracle数据完整性和锁机制简析

    事务不是程序,事务和程序分属两个概念,事务控制语句称为TCL,一般包括Commit和Rollback,需要了解的朋友可以参考下
    2012-11-11
  • oracle中左填充(lpad)和右填充(rpad)的介绍与用法

    oracle中左填充(lpad)和右填充(rpad)的介绍与用法

    这篇文章主要跟大家介绍了关于oracle中左填充(lpad)和右填充(rpad)的相关资料,通过填充我们可以固定字段的长度,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-08-08
  • Oracle归档日志写满(ora-00257)了怎么办

    Oracle归档日志写满(ora-00257)了怎么办

    今天在使用oracle数据库做项目时,突然报错:ORA-00257: archiver error. Connect internal only, until freed,该问题如何解决呢?经过本人一番折腾此问题还要归档于日志满了,下面小编把Oracle归档日志写满(ora-00257)的解决办法在此分享给大家供大家参考
    2015-10-10
  • Oracle Index Partition索引分区的注意事项

    Oracle Index Partition索引分区的注意事项

    Oracle索引分区的管理是一个复杂而重要的过程,需要数据库管理员具备丰富的经验和专业知识,通过合理的索引分区策略、定期的维护和优化以及注意事项的遵循,可以确保数据库的性能和稳定性,这篇文章主要介绍了Oracle Index Partition索引分区的管理,需要的朋友可以参考下
    2024-08-08

最新评论