暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

3692.Oracle伪列的使用总结

张鹏 2024-12-23
83

3692.Oracle伪列的使用总结
伪列是指在创建表时不用我们自己创建,而是由Oracle自动创建的列。Oracle可以使用的伪列分为以下几种:
(1)在普通查询中使用的伪列:ora_rowscn,rowid,rownum;
(2)在Flashback Version Query查询中使用的伪列:versions_starttime,versions_endtime,versions_startscn,versions_endscn,versions_operation,versions_xid;
(3)在递归查询中使用的伪列:connect_by_isleaf,level,connect_by_iscycle。

一、普通查询中使用的伪列
1、ora_rowscn伪列
默认情况下,ora_rowscn的查询结果是从数据文件块头获取的,查询出的是block的最近事务的scn,而不是精确到row的scn。在创建表时,可以指定rowdependencies来使ora_rowscn真正记录行一级的scn。

举例:

(1)创建一张表stu,指定rowdependencies参数

SQL> create table stu(id char(11) primary key,name varchar2(20),age number(2)) rowdependencies;

Table created.

(2)插入三条记录,查询ora_rowscn

SQL> select ora_rowscn,stu.* from stu;

ORA_ROWSCN ID NAME AGE


11285682 20180224001 张云 20
11285682 20180224002 李辉 21
11285682 20180224012 张华 19

(3)对第一条记录进行修改并提交,然后重新查询ora_rowscn

SQL> update stu set age=18 where id=‘20180224001’;

1 row updated.

Elapsed: 00:00:00.00
SQL> commit;

Commit complete.

Elapsed: 00:00:00.02
SQL> select ora_rowscn,stu.* from stu;

ORA_ROWSCN ID NAME AGE


11285703 20180224001 张云 18
11285682 20180224002 李辉 21
11285682 20180224012 张华 19

(4)利用SCN_TO_TIMESTAMP函数可以查询scn号对应的具体时间

SQL> select ora_rowscn,SCN_TO_TIMESTAMP(ora_rowscn),stu.* from stu;

ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN) ID NAME AGE


11285703 26-FEB-20 11.27.19.000000000 AM 20180224001 张云 18
11285682 26-FEB-20 11.26.25.000000000 AM 20180224002 李辉 21
11285682 26-FEB-20 11.26.25.000000000 AM 20180224012 张华 19

Elapsed: 00:00:00.04

2、ROWID伪列
rowid与磁盘驱动器中的特定位置相关,rowid就是表中的行存在于文件系统中的物理位置,oracle数据库每一行都有一个rowid值。一旦一行数据插入数据库,则rowid在该行的生命周期内是唯一的,即即使该行产生行迁移,行的rowid也不会改变。索引结构中也包含rowid,通过索引能快速的定位表中的记录。

Rowid是基于64位编码的18位字符,格式如下:

data_object_id file_id block_number row_number
OOOOOO FFF BBBBBB RRR

查看表中的rowid伪列数据:

SQL> select rowid,e.empno,e.ename,e.sal,e.comm from emp e;

ROWID EMPNO ENAME SAL COMM


AAASE7AAEAAAACWAAA 7698 BLAKE 2850
AAASE7AAEAAAACWAAM 7499 ALLEN 1600 300
AAASE7AAEAAAACWAAN 7788 SCOTT 3000 500
AAASE7AAEAAAACWAAP 7876 ADAMS 1100
AAASE7AAEAAAACWAAQ 7654 MARTIN 1250 1400
AAASE7AAEAAAACWAAR 7900 JAMES 950
AAASE7AAEAAAACWAAV 7566 JONES 2975
AAASE7AAEAAAACWAAW 7902 FORD 3000
AAASE7AAEAAAACWAAX 7369 SMITH 800
AAASE7AAEAAAACWAAY 7521 WARD 1250 500
AAASE7AAEAAAACWAAZ 7844 TURNER 1500 0
AAASE7AAEAAAACWAAa 8002 TOM 4000 500
AAASE7AAEAAAACWAAb 7934 MILLER 1300 2
AAASE7AAEAAAACWAAc 7782 CLARK 2450 2
AAASE7AAEAAAACWAAd 7839 KING 5000 2

15 rows selected.

3、ROWNUM伪列
在查询结果中,每返回一条记录,rownum伪列就返回一个数字,代表查询返回的行的编号。rownum返回的是查询过程中返回记录的顺序,并不是查询结果的序列号,因此对于某一条记录来说rownum的值是不确定的,每次查询都有可能对应不同的取值。

如果使用rownum伪列构造查询条件,只能使用(<、<=、!=),不能使用(>,>=,=,between…and),因为rownum是针对查询的结果集加的一个伪列,即先查到结果集之后再加上去的一个列,rownum 是对符合条件结果的序列号,如果使用(>,>=,=,between…and)构造查询条件,从缓冲区或数据文件中得到的第一条记录的rownum为1,则被删除,接着取下条,可是它的rownum还是1,又被删除,依次类推,便查询不到任何数据。如果想使用(>,>=,=,between…and)构造查询条件,可以使用子查询解决。

举例:

SQL> select * from (select rownum rn,emp.* from emp) e where e.rn between 3 and 7;

RN	EMPNO ENAME	 JOB		  MGR HIREDATE			 SAL	   COMM     DEPTNO

 3	 7788 SCOTT	 ANALYST	 7566 1987-04-19 00:00:00	3000	   500 	20
 4	 7876 ADAMS	 CLERK		 7788 1987-05-23 00:00:00	1100			20
 5	 7654 MARTIN SALESMAN	 7698 1981-09-28 00:00:00	1250	  1400 	30
 6	 7900 JAMES	 CLERK		 7698 1981-12-03 00:00:00	 950			30
 7	 7566 JONES	 MANAGER	 7839 1981-04-02 00:00:00	2975			20

Elapsed: 00:00:00.00

二、Flashback Version Query查询中的伪列
Flashback Version Query查询称为Oracle的闪回版本查询,闪回版本查询用来获取在给定的时间区间中,指定行的不同版本。当COMMIT语句被执行时,一个新的行版本被创建。闪回版本查询使用VERSIONS BETWEEN子句,闪回版本查询中可以使用versions_starttime,versions_endtime,versions_startscn,versions_endscn,versions_operation,versions_xid伪列来获取相关信息。格式如下:

VERSIONS {BETWEEN {SCN | TIMESTAMP} start AND end}
1
AI助手
说明:
(1)start和end是代表开始和结束的表达式,代表被查询的时间区间。
(2)闪回版本查询返回一个表,包含行在指定的时间区间中的所有版本。在表中的每行都包含关于行版本的元数据伪列。

例如:对emp表的7788号员工的comm字段进行多次修改并且提交。

SQL> select systimestamp from dual;

SYSTIMESTAMP

25-FEB-20 08.52.50.309623 PM +08:00

Elapsed: 00:00:00.01
SQL> update emp set comm=100 where empno=7788;

1 row updated.

Elapsed: 00:00:00.01
SQL> commit;

Commit complete.

Elapsed: 00:00:00.01
SQL> update emp set comm=300 where empno=7788;

1 row updated.

Elapsed: 00:00:00.00
SQL> commit;

Commit complete.

Elapsed: 00:00:00.01
SQL> update emp set comm=500 where empno=7788;
1 row updated.
Elapsed: 00:00:00.01
SQL> commit;
Commit complete.

查询emp表的修改信息(显示修改时间):

SQL>
SELECT versions_starttime, versions_endtime, versions_xid, versions_operation,
emp.empno,emp.ename,emp.comm
FROM emp
versions between timestamp
to_timestamp(‘2020-2-25 20.52.50’,‘yyyy-mm-dd hh24:mi:ss’)
AND systimestamp
WHERE empno=7788;

VERSIONS_STARTTIME VERSIONS_ENDTIME VERSIONS_XID V EMPNO ENAME COMM


25-FEB-20 08.53.26 PM 040021005E0A0000 U 7788 SCOTT 500
25-FEB-20 08.53.17 PM 25-FEB-20 08.53.26 PM 08001B00890F0000 U 7788 SCOTT 300
25-FEB-20 08.53.11 PM 25-FEB-20 08.53.17 PM 070015004C0A0000 U 7788 SCOTT 100
25-FEB-20 08.53.11 PM 7788 SCOTT

查询emp表的修改信息(显示修改的SCN号):

SQL>
SELECT versions_startscn, versions_endscn, versions_xid, versions_operation, emp.empno,emp.ename,emp.comm
FROM emp
versions between timestamp to_timestamp(‘2020-2-25 20.52.50’,‘yyyy-mm-dd hh24:mi:ss’)
AND systimestamp
5 WHERE empno=7788;

VERSIONS_STARTSCN VERSIONS_ENDSCN VERSIONS_XID V EMPNO ENAME COMM


 11242056		      040021005E0A0000 U	   7788 SCOTT		  500
 11242052	 11242056 08001B00890F0000 U	   7788 SCOTT		  300
 11242049	 11242052 070015004C0A0000 U	   7788 SCOTT		  100
		     11242049			               7788 SCOTT

查询各个时间点的数据:

SQL> select * from emp as of scn 11242049 where empno=7788;

 EMPNO ENAME      JOB	       MGR HIREDATE		      SAL	COMM	 DEPTNO

  7788 SCOTT      ANALYST	      7566 1987-04-19 00:00:00	     3000	 100	     20

Elapsed: 00:00:00.01
SQL> select * from emp as of scn 11242052 where empno=7788;

 EMPNO ENAME      JOB	       MGR HIREDATE		      SAL	COMM	 DEPTNO

  7788 SCOTT      ANALYST	      7566 1987-04-19 00:00:00	     3000	 300	     20

Elapsed: 00:00:00.00
SQL> select * from emp as of scn 11242056 where empno=7788;

 EMPNO ENAME      JOB	       MGR HIREDATE		      SAL	COMM	 DEPTNO

  7788 SCOTT      ANALYST	      7566 1987-04-19 00:00:00	     3000	 500	     20

三、递归查询中使用的伪列
在select语句中可以使用start with…connect by prior子句实现递归查询,其基本语法如下:

SELECT …
FROM …
START WITH cond1
CONNECT BY cond2
WHERE cond3;

说明:
(1)START WITH:表示从哪个节点开始查找,也就是通过cond1查询到的数据,作为后续查询的起始节点(参数),可以是一个或多个根节点;如果省略Start With,就把整个表中的数据从头到尾遍历一次,每一个数据做一次根,然后遍历树中的其他节点信息;
(2)CONNECT BY子句说明每行数据将是按照层次顺序检索,cond2是连接条件,一般包含PRIOR,如果PRIOR在子节点(ID)之前,表示向下查找,如果PRIOR在父节点(PID)之前,表示向上查找;如果不带PRIOR,则只显示当前记录;
(3)WHERE:这里的条件判断用于在最后查询出结果列表之后再进行条件筛选;
(4)可以使用伪列connect_by_isleaf判断一个节点是否是叶子节点;
(5)可以使用伪列level查询当前节点所处层级,这里的层级指的是从start with查询到的节点开始往下算起。

举例:
1、数据准备
创建一张表area,表结构如下:

10:59:43 SQL> desc area;
Name Null? Type

ID NOT NULL NUMBER(38)
DSC VARCHAR2(20)
PID NUMBER(38)

该表以树状结构保存地区,表中的PID(parent ID)字段存储的某个地区的上级ID,如果是树的根节点,则PID为0。

插入记录,结果如下:

11:05:34 SQL> select * from area;

ID DSC			       PID

     1 中国                          0
   101 河南省                        1
   102 湖北省                        1
   103 河北省                        1
 10101 郑州市                      101
 10102 新乡市                      101
 10103 开封市                      101
 10104 驻马店市                    101
 10105 南阳市                      101
 10106 信阳市                      101
 10107 濮阳市                      101
 10108 安阳市                      101

1010201 红旗市 10102
1010202 卫滨区 10102
1010203 牧野市 10102
1010204 原阳县 10102
1010205 获嘉县 10102
1010206 卫辉市 10102
1010401 驿城区 10104
1010402 上蔡县 10104
1010403 新蔡县 10104
1010404 正阳县 10104
1010405 西平县 10104
1010406 汝南县 10104
10201 武汉市 102
10202 黄冈市 102
10203 黄石市 102
10204 孝感市 102
1020101 武昌区 10201
1020102 汉口区 10201
1020103 汉阳区 10201

31 rows selected.

2、查找一个节点所有的下层节点
SQL>
SELECT area.*
FROM area
START WITH id=101
3 4 CONNECT BY prior id=pid;

ID DSC			       PID

   101 河南省                        1
 10101 郑州市                      101
 10102 新乡市                      101

1010201 红旗市 10102
1010202 卫滨区 10102
1010203 牧野市 10102
1010204 原阳县 10102
1010205 获嘉县 10102
1010206 卫辉市 10102
10103 开封市 101
10104 驻马店市 101
1010401 驿城区 10104
1010402 上蔡县 10104
1010403 新蔡县 10104
1010404 正阳县 10104
1010405 西平县 10104
1010406 汝南县 10104
10105 南阳市 101
10106 信阳市 101
10107 濮阳市 101
10108 安阳市 101

21 rows selected.
Elapsed: 00:00:00.03
3、查找一个节点所有的上层节点
SQL>
SELECT area.*
FROM area
START WITH id=10102
4 CONNECT BY id=prior pid;

ID DSC			       PID

 10102 新乡市                      101
   101 河南省                        1
     1 中国                          0

Elapsed: 00:00:00.00

4、判断节点是否是叶子节点
SQL>
SELECT area.*,
decode(connect_by_isleaf,0,‘非叶子节点’,1,‘叶子节点’)
as isleaf_node
FROM area
START WITH id=101
6 CONNECT BY prior id=pid;

ID DSC			       PID ISLEAF_NODE

   101 河南省                        1 非叶子节点
 10101 郑州市                      101 叶子节点
 10102 新乡市                      101 非叶子节点

1010201 红旗市 10102 叶子节点
1010202 卫滨区 10102 叶子节点
1010203 牧野市 10102 叶子节点
1010204 原阳县 10102 叶子节点
1010205 获嘉县 10102 叶子节点
1010206 卫辉市 10102 叶子节点
10103 开封市 101 叶子节点
10104 驻马店市 101 非叶子节点
1010401 驿城区 10104 叶子节点
1010402 上蔡县 10104 叶子节点
1010403 新蔡县 10104 叶子节点
1010404 正阳县 10104 叶子节点
1010405 西平县 10104 叶子节点
1010406 汝南县 10104 叶子节点
10105 南阳市 101 叶子节点
10106 信阳市 101 叶子节点
10107 濮阳市 101 叶子节点
10108 安阳市 101 叶子节点

21 rows selected.

5、查询叶子节点
SQL>
SELECT area.*
FROM area
WHERE connect_by_isleaf=1
START WITH id=101
5 CONNECT BY prior id=pid;

ID DSC			       PID

 10101 郑州市                      101

1010201 红旗市 10102
1010202 卫滨区 10102
1010203 牧野市 10102
1010204 原阳县 10102
1010205 获嘉县 10102
1010206 卫辉市 10102
10103 开封市 101
1010401 驿城区 10104
1010402 上蔡县 10104
1010403 新蔡县 10104
1010404 正阳县 10104
1010405 西平县 10104
1010406 汝南县 10104
10105 南阳市 101
10106 信阳市 101
10107 濮阳市 101
10108 安阳市 101

18 rows selected.

6、查询非叶子节点
SQL>
SELECT area.*
FROM area
WHERE connect_by_isleaf=0
START WITH id=101
5 CONNECT BY prior id=pid;

ID DSC			       PID

   101 河南省                        1
 10102 新乡市                      101
 10104 驻马店市                    101

Elapsed: 00:00:00.00

7、判断每个节点的层级
SQL>
SELECT area.*,level as level_n
FROM area
START WITH id=101
4 CONNECT BY prior id=pid;

ID DSC			       PID    LEVEL_N

   101 河南省                        1          1
 10101 郑州市                      101          2
 10102 新乡市                      101          2

1010201 红旗市 10102 3
1010202 卫滨区 10102 3
1010203 牧野市 10102 3
1010204 原阳县 10102 3
1010205 获嘉县 10102 3
1010206 卫辉市 10102 3
10103 开封市 101 2
10104 驻马店市 101 2
1010401 驿城区 10104 3
1010402 上蔡县 10104 3
1010403 新蔡县 10104 3
1010404 正阳县 10104 3
1010405 西平县 10104 3
1010406 汝南县 10104 3
10105 南阳市 101 2
10106 信阳市 101 2
10107 濮阳市 101 2
10108 安阳市 101 2

21 rows selected.

从下向上查询的结果:

SQL>
SELECT area.*,level as level_n
FROM area
START WITH id=101
4 CONNECT BY id=prior pid;

ID DSC			       PID    LEVEL_N

   101 河南省                        1          1
     1 中国                          0          2

8、统计节点的层数
SQL>
SELECT count(distinct level)
FROM area
START WITH id=1
4 CONNECT BY prior id=pid;

COUNT(DISTINCTLEVEL)

	   4

Elapsed: 00:00:00.01

9、查询每一层节点的个数
SQL>
WITH tmp AS
(SELECT area.*,level as lev
FROM area
START WITH id=1
CONNECT BY prior id=pid)
SELECT ‘Level-’||lev as level_count,
count(1) as node_count
FROM tmp
9 GROUP BY lev;

LEVEL_COUNT NODE_COUNT


Level-1 1
Level-2 3
Level-4 15
Level-3 12

10、查询某一个节点的子节点
SQL>
SELECT area.*,level as level_n
FROM area
WHERE level=2
START WITH id=101
5 CONNECT BY prior id=pid;

ID DSC			       PID    LEVEL_N

 10101 郑州市                      101          2
 10102 新乡市                      101          2
 10103 开封市                      101          2
 10104 驻马店市                    101          2
 10105 南阳市                      101          2
 10106 信阳市                      101          2
 10107 濮阳市                      101          2
 10108 安阳市                      101          2

8 rows selected.
Elapsed: 00:00:00.00

11、查询某一个节点的父节点
SQL>

SELECT area.*,level as level_n
FROM area
WHERE level=2
START WITH id=101
5 CONNECT BY id=prior pid;

ID DSC			       PID    LEVEL_N

     1 中国                          0          2

Elapsed: 00:00:00.00

12、格式化节点的显示
SQL>
SELECT LPAD(’ ',(level-1)*4)||dsc as area
FROM area
START WITH id=1
4 CONNECT BY prior id=pid;

AREA

中国
河南省
郑州市
新乡市
红旗市
卫滨区
牧野市
原阳县
获嘉县
卫辉市
开封市
驻马店市
驿城区
上蔡县
新蔡县
正阳县
西平县
汝南县
南阳市
信阳市
濮阳市
安阳市
湖北省
武汉市
武昌区
汉口区
汉阳区
黄冈市
黄石市
孝感市
河北省

31 rows selected.

Elapsed: 00:00:00.00

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论