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