伪列

伪列是指那些可以像表中的列一样用在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;

注解

  1. 当创建列名时不能与ROWNUM关键字冲突的,如果冲突就报错。如果表或者视图这样的对象名与ROWNUM相同将不会报错,因为这是允许的。
  2. Returning目标列中不能有ROWNUM列,这样的查询没有意义,兼容了 Oracle 表现。
  3. 当视图(VIEW)中包含ROWNUM列时,此视图为不可更新视图,兼容了 Oracle 表现。
  4. 不能使用“表名.ROWNUM”的形式,如tab1.rownum,因为ROWNUM不属于某个表。
  5. ROWNUM不能用作连接条件的判断中,也就是不能用在关键字ON后。
  6. 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;