Oracle伪列的使用总结

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)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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章