伪列¶
伪列是指那些可以像表中的列一样用在SELECT中但不作为用户数据在表中存储的特殊标识, 它们可以被选择(使用SELECT),但不能被删除(DELETE)和更新(UPDATE)。神通数据库提供如下几种伪列:
- ROWID
ROWID在整个数据库中唯一标识了一行数据,通过它可以直接定位数据的物理存储位置。
- SYSATTR_ROWVERSION
SYSATTR_ROWVERSION标识表中一行的版本,如果行被更新了,该SYSATTR_ROWVERSION就会发生变化,但SYSATTR_ROWVERSION变化不代表该列也一定发生变化。
- ROWNUM
ROWNUM的本质是一个伪列,它的作用就是根据从查询中获取记录的顺序,为每一条记录分配一个递增唯一的整数值。 因此ROWNUM的分配是按照第一条取出记录的ROWNUM是1,第二条取出记录的ROWNUM是2,... 这样的顺序进行的。
示例1: 使用 ROWNUM 限制查询一次所获取的记录总数
-- 清理环境
DROP VIEW view1 CASCADE;
DROP TABLE tab1 CASCADE;
CREATE TABLE tab1 (a CHAR(6), b INT);
CREATE VIEW view1 AS SELECT * FROM tab1 ORDER BY a;
INSERT INTO tab1 VALUES('200001', 1000);
INSERT INTO tab1 VALUES('200002', 1100);
INSERT INTO tab1 VALUES('200003', 1200);
INSERT INTO tab1 VALUES('200004', 1300);
INSERT INTO tab1 VALUES('200005', 1400);
INSERT INTO tab1 VALUES('200006', 1500);
INSERT INTO tab1 VALUES('200007', 1600);
SELECT * FROM view1;
A(char) |B(int) |
-------------------------
200001 |1000 |
-------------------------
200002 |1100 |
-------------------------
200003 |1200 |
-------------------------
200004 |1300 |
-------------------------
200005 |1400 |
-------------------------
200006 |1500 |
-------------------------
200007 |1600 |
总数目:7
-- 使用 ROWNUM 限制结果集行数
SELECT ROWNUM, * FROM view1 WHERE ROWNUM < 5 ORDER BY ROWNUM;
ROWNUM(bigint) |A(char) |B(int) |
---------------------------------------------
1 |200001 |1000 |
---------------------------------------------
2 |200002 |1100 |
---------------------------------------------
3 |200003 |1200 |
---------------------------------------------
4 |200004 |1300 |
总数目:4
SELECT ROWNUM, * FROM view1 WHERE ROWNUM = 1;
ROWNUM(bigint) |A(char) |B(int) |
---------------------------------------------
1 |200001 |1000 |
总数目:1
-- 删除视图、表
DROP VIEW view1;
DROP TABLE tab1;
如果判断条件是 ROWNUM > n 或者 ROWNUM = n 或者 ROWNUM >= n (n>1)时,此查询条件是恒假的,查询是不会有结果的, 因为根据 ROWNUM 伪列的定义,每当产生一条结果记录时 ROWNUM 加1,所以当用户用 ROWNUM 和某个大于1的数作比较时, 判断结果为假,未产生结果记录,所以 ROWNUM 不累加,再次选出记录与 ROWNUM 作比较就会重复上述过程,直到没有结果记录被选出。
示例2: 使用 ROWNUM 未筛选出结果
-- 清理环境
DROP VIEW view2 CASCADE;
DROP TABLE tab2 CASCADE;
CREATE TABLE tab2 (a CHAR(6), b INT);
CREATE VIEW view2 AS SELECT * FROM tab2 ORDER BY a;
INSERT INTO tab2 VALUES('200001', 1000);
INSERT INTO tab2 VALUES('200002', 1100);
INSERT INTO tab2 VALUES('200003', 1200);
INSERT INTO tab2 VALUES('200004', 1300);
INSERT INTO tab2 VALUES('200005', 1400);
INSERT INTO tab2 VALUES('200006', 1500);
INSERT INTO tab2 VALUES('200007', 1600);
SELECT * FROM view2;
A(char) |B(int) |
-------------------------
200001 |1000 |
-------------------------
200002 |1100 |
-------------------------
200003 |1200 |
-------------------------
200004 |1300 |
-------------------------
200005 |1400 |
-------------------------
200006 |1500 |
-------------------------
200007 |1600 |
总数目:7
-- 使用 ROWNUM 未筛选出结果
SELECT ROWNUM, * FROM view2 WHERE ROWNUM = 3;
ROWNUM(bigint) |A(char) |B(int) |
总数目:0
SELECT ROWNUM, * FROM view2 WHERE ROWNUM > 2;
ROWNUM(bigint) |A(char) |B(int) |
总数目:0
-- 删除视图、表
DROP VIEW view2;
DROP TABLE tab2;
使用 ROWNUM 还可以实现结果集分页显示。
示例3: 伪列 ROWNUM 实现分页显示
-- 清理环境
DROP TABLE tab3 CASCADE;
CREATE TABLE tab3 (a CHAR(6), b INT);
INSERT INTO tab3 VALUES('200001', 1000);
INSERT INTO tab3 VALUES('200002', 1100);
INSERT INTO tab3 VALUES('200003', 1200);
INSERT INTO tab3 VALUES('200004', 1300);
INSERT INTO tab3 VALUES('200005', 1400);
INSERT INTO tab3 VALUES('200006', 1500);
INSERT INTO tab3 VALUES('200007', 1600);
SELECT * FROM tab3 ORDER BY a DESC;
A(char) |B(int) |
-------------------------
200007 |1600 |
-------------------------
200006 |1500 |
-------------------------
200005 |1400 |
-------------------------
200004 |1300 |
-------------------------
200003 |1200 |
-------------------------
200002 |1100 |
-------------------------
200001 |1000 |
总数目:7
-- 使用 ROWNUM 实现分页显示
SELECT * FROM
(SELECT ROWNUM AS ROW_NUM, A.* FROM
(SELECT * FROM tab3 T ORDER BY a DESC) A
) B WHERE B.ROW_NUM BETWEEN 1 AND 3;
ROW_NUM(bigint) |A(char) |B(int) |
----------------------------------------------
1 |200007 |1600 |
----------------------------------------------
2 |200006 |1500 |
----------------------------------------------
3 |200005 |1400 |
总数目:3
SELECT * FROM
(SELECT ROWNUM AS ROW_NUM, A.* FROM
(SELECT * FROM tab3 T ORDER BY a DESC) A
) B WHERE B.ROW_NUM BETWEEN 4 AND 5;
ROW_NUM(bigint) |A(char) |B(int) |
----------------------------------------------
4 |200004 |1300 |
----------------------------------------------
5 |200003 |1200 |
总数目:2
SELECT * FROM
(SELECT ROWNUM AS ROW_NUM, A.* FROM
(SELECT * FROM tab3 T ORDER BY a DESC) A
) B WHERE B.ROW_NUM BETWEEN 6 AND 10;
ROW_NUM(bigint) |A(char) |B(int) |
----------------------------------------------
6 |200002 |1100 |
----------------------------------------------
7 |200001 |1000 |
总数目:2
-- 删除表
DROP TABLE tab3;
注解
- 当创建列名时不能与ROWNUM关键字冲突的,如果冲突就报错。如果表或者视图这样的对象名与ROWNUM相同将不会报错,因为这是允许的。
- Returning目标列中不能有ROWNUM列,这样的查询没有意义,兼容了 Oracle 表现。
- 当视图(VIEW)中包含ROWNUM列时,此视图为不可更新视图,兼容了 Oracle 表现。
- 不能使用“表名.ROWNUM”的形式,如tab1.rownum,因为ROWNUM不属于某个表。
- ROWNUM不能用作连接条件的判断中,也就是不能用在关键字ON后。
- ORDER BY 和 GROUP BY 动作是在 ROWNUM 伪列追加完之后进行的(参见示例4)。
示例4: 同时使用 GROUP BY、ROWNUM
-- 清理环境
DROP TABLE tab4 CASCADE;
CREATE TABLE tab4 (a CHAR(6), b INT);
INSERT INTO tab4 VALUES('200001', 1000);
INSERT INTO tab4 VALUES('200001', 1100);
INSERT INTO tab4 VALUES('200001', 1200);
INSERT INTO tab4 VALUES('200004', 1300);
INSERT INTO tab4 VALUES('200002', 1400);
INSERT INTO tab4 VALUES('200007', 1500);
INSERT INTO tab4 VALUES('200007', 1600);
SELECT * FROM tab4 ORDER BY a,b DESC;
A(char) |B(int) |
-------------------------
200001 |1200 |
-------------------------
200001 |1100 |
-------------------------
200001 |1000 |
-------------------------
200002 |1400 |
-------------------------
200004 |1300 |
-------------------------
200007 |1600 |
-------------------------
200007 |1500 |
总数目:7
-- 只使用 GROUP BY
SELECT COUNT(*) FROM (SELECT a FROM tab4 GROUP BY a);
COUNT(int) |
----------------
4 |
总数目:1
-- 同时使用 GROUP BY、ROWNUM
SELECT COUNT(*) FROM (SELECT a FROM tab4 GROUP BY a, ROWNUM);
COUNT(int) |
----------------
7 |
总数目:1
-- 删除表
DROP TABLE tab4;