云数据库OceanBase入门教程 OceanBase 伪类

2024-02-26 开发教程 云数据库OceanBase入门教程 匿名 5

伪列(Pseudocolumn)的行为与表中的列相同,但并未存储具体数值。因此,伪列只具备读属性,您不可以对伪列进行插入、更新、删除的等行为。

层次查询伪列

层次查询伪列仅在层次查询中有效,要在查询中定义层次结构关系,必须使用 CONNECT BY 子句。

CONNECT_BY_ISCYCLE 伪列

CONNECT_BY_ISCYCLE​ 伪列用来协助标记循环是从哪一行开始的。如当前行的子节点同时也是其祖先节点之一,则​CONNECT_BY_ISCYCLE​ 返回 1,否则返回 0。

CONNECT_BY_ISCYCLE​ 需要配合 ​CONNECT BY​ 子句的 ​NOCYCLE​ 使用,否则查询结果会因树状结果存在循环而报错。

CONNECT_BY_ISLEAF 伪列

CONNECT_BY_ISLEAF​ 伪列用来协助标记层次结构的叶子节点。如当前行无子节点即为树的叶子节点时,返回 1,否则返回 0。

LEVEL 伪列

LEVEL​ 伪列用来协助标记节点的层次。层次结构中,根为第 1 层,根的子结点为第 2 层,之后以此类推。例如,根节点的 LEVEL 值会返回 1,根节点的子节点的 ​LEVEL​ 值会返回 2,之后以此类推。

序列伪列

序列(Sequence)伪列是数据库按照一定规则生成的自增数字序列。因其自增的特性,通常被用作主键和唯一键。序列伪列有两种取值方法:

  • CURRVAL​:返回序列的当前值。
  • NEXTVAL​:返回序列的下一个自增值。

使用序列伪列时,必须在 ​CURRVAL​、​NEXTVAL​ 前带上序列的名称,并用句点(.)引用。例如,序列的名称为 SEQ_FOO,则可以通过 ​SEQ_FOO.CURRVAL​ 获取 SEQ_FOO 序列的当前值。同样,可以通过​SEQ_FOO.NEXTVAL ​获取 SEQ_FOO 序列的下一个自增值。

序列伪列的应用场景

序列伪列 ​CURRVAL​ 和 ​NEXTVAL​ 的值可以用于以下位置:

  • 非子查询、物化视图或者视图中的 ​SELECT​ 语句的选择列表中。
  • INSERT​ 语句中子查询的选择列表中。
  • INSERT​ 语句中的 ​VALUE​ 子句中。
  • UPDATE​ 语句中的​SET子句中。

序列伪列 ​CURRVAL​ 和 ​NEXTVAL​ 的值不能用于以下位置:

  • DELETE​、​SELECT​ 或者 ​UPDATE​ 语句的子查询中。
  • 视图或者物化视图的查询中。
  • 带 ​DISTINCT​ 运算符的 ​SELECT​ 语句中。
  • 带 ​GROUP BY ​子句或者 ​ORDER BY​ 子句的 ​SELECT​ 语句中。
  • 与另一个 ​SELECT​ 语句通过 ​UNION​、​INTERSECT或者 ​MINUS​ 集合运算符进行联合的 ​SELECT​ 语句中。
  • SELECT​ 语句的 ​WHERE​ 子句中。
  • CREATE TABLE ​或者 ​ALTER TABLE​ 语句中列的 ​DEFAULT​ 值。
  • CHECK​ 约束的条件中。

如何使用序列伪列

创建序列时,需要明确其初始值和步长。第一次引用 ​NEXTVAL​ 将返回序列的初始值,后续对 ​NEXTVAL​ 的引用将按照上一次序列的返回值加上序列定义的步长后返回一个新值。任何时候对 ​CURRVAL​ 的引用,都将返回当前序列的值,即最后一次对 ​NEXTVAL​ 引用时返回的值。

在会话中引用序列的 ​CURRVAL​ 伪列前,都应首先应用序列的 ​NEXTVAL​ 伪列来初始化本次会话的序列值。

创建序列时,可以定义其初始值以及其值之间的增量。对 ​NEXTVAL​ 的第一次引用将返回序列的初始值。对 ​NEXTVAL​ 的后续引用将会使序列值按照定义的增量递增,并返回新值。任何对 ​CURRVAL ​的引用总是返回该序列的当前值,即最后一次对 ​NEXTVAL​ 引用时返回的值。对序列的创建的相关内容,请参考文档 CREATE SEQUENCE 章节。

在单条 SQL 语句中引用 ​NEXTVAL​ 时,OceanBase 数据库按照以下方式递增序列:

  • SELECT​ 语句的外部查询块每返回一行递增一次。这类查询块可以出现在以下地方:
    • 顶层 ​SELECT​ 语句。
    • INSERT... SELECT​ 语句。对于多表插入,​NEXTVAL​ 必须位于 ​VALUES​ 子句中,子查询每返回一行序列就递增一次,即使多个分支引用了 ​NEXTVAL​。
    • CREATE TABLE ... AS SELECT​ 语句。
    • CREATE MATERIALIZED VIEW ... AS SELECT​语句。
  • UPDATE​ 语句每更新一行序列就递增一次。
  • 每有一条包含 ​VALUES​ 子句的 INSERT 语句就递增一次。
  • MERGE​ 语句每合并一行序列递增一次。​NEXTVAL​ 可以出现在​merge_insert_clause​ 或者​merge_update_clause​ 子句中,也可两者同时出现。​NEXTVAL​ 会随着每一行的更新和插入而递增,即使序列数值没有用于更新或者插入操作。如果 ​NEXTVAL​ 在这些位置中被指定了多次,那么对应每一行都递增一次序列,而且该行中出现的所有 ​NEXTVAL​ 都返回相同的值。

当这些位置多次引用一个序列的 ​NEXTVAL​ 伪列时,该序列都只递增一次,即为所有被引用的 ​NEXTVAL​ 伪列返回当前序列的下一个序列值。

当这些位置同时引用一个序列的 ​CURRVAL​和 ​NEXTVAL​ 伪列时,OceanBase 将递增该序列,即为被引用的 ​CURRVAL​ 和 ​NEXTVAL​ 伪列都返回当前序列的下一个序列值。

序列可以同时被许多用户访问,不存在等待和锁定。

ROWSCN 伪列

ORA_ROWSCN​ 伪列将最新更改的系统更改号(SCN:System Change Number)反映到一行,该更改号表示这一行数据修改所在事务的提交时间。

ROWNUM 伪列

ROWNUM​ 伪列会对查询结果中的每一行进行编号,其值为该行在查询结果集中的具体位置。第一行返回值 1,第二行返回值 2,之后以此类推。

ROWNUM 的用法说明

ROWNUM​ 可以限制返回的行数,例如以下示例,将返回 employees 表中的 5 条数据:

SELECT * FROM employees WHERE rownum <=5;

如果在 ​ROWNUM​ 后有 ​ORDER BY​ 子句,则将对满足 ​WHERE​ 条件句的结果进行重排序。如果将 ​ORDER BY​ 子句嵌入子查询中,并将 ​ROWNUM​ 伪列作为条件放置在顶级查询中,则可以强制 ​ROWNUM​条件在行排序之后执行。例如,使用以下语句查询年龄最大的 5 名员工信息是得不到预期结果的,该语句只是将查询结果中的前 5 条员工信息进行年龄排序:

SELECT * FROM employees WHERE rownum <=5 ORDER BY age DESC;

正确的用法应该如下:

SELECT * FROM (SELECT * FROM employees ORDER BY age DESC) WHERE rownum <= 5;

在 ​WHERE​ 子句中,指定 ​ROWNUM​ 大于任何一个正整数时总是返回 FALSE,例如以下 SQL 语句将不返回任何信息:

SELECT * FROM employees WHERE rownum > 1;

因为在获得表的第一行结果时,改行的 ​ROWNUM​ 伪列值将被赋值为 1,此时在 ​WHERE​ 条件判断时结果为 FALSE,则此行被舍去。在获得第二行结果时,该行的 ​ROWNUM​ 伪列值任然被赋值为 1,​WHERE​ 条件判断的结果依旧为 FALSE,此行再次被舍去。以此类推,所以所有行都不满足条件,因此不返回任何数据。

也可以通过 ​UPDATE​ 语句将​ ROWNUM​ 数值赋值给表中的某一列,例如:

UPDATE employees SET id = rownum;

此语句将对表 employees 的 id 列进行​ROWNUM​ 赋值,即依次对 id 列赋值 1、2、... 直至该表总行数。

注意
在查询中使用​ROWNUM ​可能会影响视图优化。

ROWID 伪列

ROWID 伪列提供了快速定位表中某一行的能力,ROWID 值由主键编码得到,不会进行实际的存储,类型是 UROWID。使用方法如下:

  1. 从 employees 表中查询到 ROWID 值

    obclient> SELECT ROWID, last_name FROM employees WHERE department_id = 20;
    +-------------------+-----------+
    | ROWID | LAST_NAME |
    +-------------------+-----------+
    | *AAIKAQAAAAAAAAA= | xxx |
    +-------------------+-----------+
    1 row in set (0.01 sec)
  2. 使用 ROWID 值进行 update 操作

    obclient> UPDATE employees SET last_name = 'yyy' WHERE ROWID = '*AAIKAQAAAAAAAAA=';
    Query OK, 1 row affected (0.01 sec)
    Rows matched: 1 Changed: 1 Warnings: 0
    obclient> select last_name, department_id from employees;
    +-----------+---------------+
    | LAST_NAME | DEPARTMENT_ID |
    +-----------+---------------+
    | yyy | 20 |
    +-----------+---------------+
    1 row in set (0.01 sec)