金仓数据库 KingbaseES SQL 语言参考手册 (20. SQL语句: MERGE 到 VALUES)

20. SQL语句: MERGE 到 VALUES

本章包含以下SQL语句:

20.1. MERGE

用途

MERGE  --  根据连接条件对目标表执行插入或修改操作

MERGE在一次扫描过程中根据连接条件对目标表执行插入或修改操作。

使用 MERGE 语法可合并 UPDATE 和 INSERT 语句。通过 MERGE语句,根据一张表(或视图)的连接条件对另外一张表(或视图)进行查询,连接条件匹配上的执行 UPDATE(可能含有 DELETE),无法匹配的执行 INSERT。其中数据表包括:普通表、分区表。

MERGE语法仅需要一次全表扫描就完成了全部工作,执行效率要高于INSERT+UPDATE。

MERGE也是一个DML语句,和其它的DML语句一样需要通过ROLLBACK和COMMIT语句结束事务。

前置条件

如果 MERGE action 中指定了 UPDATE/INSERT 子句,则要求用户拥有该表的 UPDATE/INSERT 权限, 如果在 UPDATE 子句中指定了 DELETE action ,则还需要具有该表的 DELETE 权限。

语法

MERGE INTO [ schema. ] { target_table } [ [ AS ] target_table_alias ]
    USING { [ schema. ] { source_table } [ [ AS ] source_table_alias ]
    ON ( condition_expression )
[ merge_update_clause ]
[ merge_insert_clause ];

merge_update_clause:
WHEN MATCHED THEN
UPDATE SET column = { expr | DEFAULT }[, column = { expr | DEFAULT } ]...
[ where_clause ]
[ delete_clause ]

delete_clause:
[DELETE where_clause]

merge_insert_clause:
WHEN NOT MATCHED THEN
INSERT [ ( column [, column ]...) ]
VALUES ({ expr | DEFAULT }[, { expr | DEFAULT } ]...)
[ where_clause ]

where_clause:
WHERE condition

语义

target_table

MERGE目标,它可以是表、水平分区表或可更新视图。不可以是继承的表和垂直分区表。

target_table_alias

MERGE目标的别名。

source_table

MERGE源,可以是表、视图、SQL/MED、子查询、join table以及函数等等。

source_table_alias

MERGE源的别名。

condition_expression

指定目标表与源表之间进行联接的联接条件。如果该条件为真,且指定了 WHEN MATCHED THEN UPDATE 子句,则对匹配到的目标表的该元组执行更新操作;否则,如果该条件为假且指定了 WHEN NOT MATCHED THEN INSERT 子句,则对目标表执行插入操作。

merge_update_clause

当目标表和源表的ON条件为真时,执行该子句,即更新目标表数据。该更新操作会触发目标表上面的触发器。更新的列不能是ON条件中被引用的列,更新时可以通过WHERE条件指明要更新的行,条件中既可以包含源表的列,也可以包含目标表的列,当指明WHERE条件且条件为假时,则不更新。

delete_clause

DELETE子句只删除目标表和源表的ON条件为真、并且是更新后的符合删除条件的记录,DELETE子句不影响INSERT项插入的行。删除条件作用在更新后的记录上,既可以和源表相关,也可以和目标表相关,或者都相关。如果ON条件为真,但是不符合更新条件,并没有更新数据,那么DELETE将不会删除任何数据。

merge_insert_clause

当目标表和源表的ON条件为假时,执行该语句。可指定插入条件,插入时的WHERE条件只能引用源表中的列。VALUES后面也只能引用源表中的列,不能包含目标表的列。

      可选的参数可以被写成任何顺序,不用按照上面说明的顺序。

示例

例1

create table test1(a int, b int);
insert into test1 values(1, 1);
insert into test1 values(2, 2);
insert into test1 values(3, 3);

create table test2(x int, y int);
insert into test2 values(1, 1);
insert into test2 values(3, 3);
insert into test2 values(5, 5);

merge into test2 using test1
on (test1.a = test2.x)
when matched then update set y = y * -1 where test1.a > 1
when not matched then insert values(test1.a, test1.b);
执行结果:
x | y
---+----
 1 |  1
 5 |  5
 2 |  2
 3 | -3
(4 rows)

例2:MERGE中使用DELETE语句:

create table t1(id int, a int, b int, c varchar(100));
create table t2(id int, a int, b int, c varchar(100));
insert into t1 values(1, 1, 1, '1');
insert into t1 values(2, 2, 2, '2');
insert into t1 values(3, 3, 3, '3');
insert into t1 values(4, 4, 4, '4');
insert into t2 values(2, 22, 22, '2');
insert into t2 values(4, 44, 44, '4');

merge into t2 using t1 on (t1.id = t2.id)
when matched then update set t2.a = t2.a * -1, t2.b = t2.b * -1 delete where
t1.id = t2.id
when not matched then insert values(t1.id, t1.a, t1.b, t1.c);

执行结果:
 id | a | b | c
----+---+---+---
  1 | 1 | 1 | 1
  3 | 3 | 3 | 3
(2 行记录)

兼容性

MERGE语句不兼容SQL标准。

其他

  1. 如果源表中有多行与目标表中的一行匹配,并且同时指定了 WHEN MATCHED THEN UPDATE 子句,则报错,因为同一元组不能被重复更新。

  2. 对于 set_list 来说,不能指定 ON 条件子句中用于联接条件的目标表中的列。

  3. 在 value_list 的值表达式中不能引用目标表中的列。

  4. 如果目标表上有约束或目标视图的定义中有 WITH CHECK OPTION,则对目标表所做的更新要满足基表上的约束条件或视图定义的校验条件。

  5. 需要有对源表的 SELECT 权限,对目标表的 UPDATE/INSERT 权限,如果 UPDATE子句有 DELETE,还需要有 DELETE 权限。

20.2. MOVE

用途

MOVE — 定位一个游标

MOVE的工作完全像``FETCH``命令,但是它只定位游标并且不返回行。用于MOVE命令的参数和 FETCH命令的一样,可参考 FETCH 。

成功完成时,MOVE命令返回的命令标签形式是

MOVE count

``count``是一个 具有同样参数的FETCH命令会返回的行数(可能为零)。

前置条件

语法

MOVE [ direction [ FROM | IN ] ] cursor_name

其中direction可以为空或者以下之一:

    NEXT
    PRIOR
    FIRST
    LAST
    ABSOLUTE count
    RELATIVE count
    count
    ALL
    FORWARD
    FORWARD count
    FORWARD ALL
    BACKWARD
    BACKWARD count
    BACKWARD ALL

语义

用于MOVE命令的参数和 FETCH命令的一样,可参考 FETCH 。

示例

BEGIN WORK;
DECLARE liahona CURSOR FOR SELECT * FROM films;

-- 跳过前 5 行:
MOVE FORWARD 5 IN liahona;
MOVE 5

-- 从游标 liahona 中取第 6 行:
FETCH 1 FROM liahona;
 code  | title  | did | date_prod  |  kind  |  len
-------+--------+-----+------------+--------+-------
 P_303 | 48 Hrs | 103 | 1982-10-22 | Action | 01:37
(1 row)

-- 关闭游标 liahona 并且结束事务:
CLOSE liahona;
COMMIT WORK;

兼容性

在 SQL 标准中没有MOVE语句。

20.3. NOTIFY

用途

NOTIFY — 生成一个通知

NOTIFY命令发送一个通知事件以及一个可选的“载荷”字符串给每个正在监听的客户端应用,这些应用之前都在当前数据库中为指定的频道名执行过LISTEN channel。通知对所有用户都可见。

NOTIFY为访问同一个KingbaseES数据库的进程集合提供了一种简单的进程间通讯机制。伴随着通知可以发送一个载荷字符串,通过使用数据库中的表从通知者向监听者传递额外的数据,也可以构建用于传输结构化数据的高层机制。

由一个通知事件传递给客户端的信息包括通知频道名称、发出通知的会话的服务器进程PID以及载荷字符串,如果载荷字符串没有被指定则它为空字符串。

将在一个给定数据库以及其他数据库中使用的频道名称由数据库设计者定义。通常,频道名称与数据库中某个表的名称相同,并且通知事件其实就意味着:“我改变了这个表,来看看改了什么吧”。但是NOTIFYLISTEN命令并未强制这样的关联。例如,一个数据库设计者可以使用几个不同的频道名称来标志一个表上的不同种类的改变。另外,载荷字符串可以被用于多种不同的情况。

NOTIFY被用来标志对一个特定表的改变时,一种有用的编程技巧是把``NOTIFY``放在一个由表更新触发的语句触发器中。在这种方式中,每当表被改变时都将自动发生通知,并且应用程序员不可能会忘记发出通知。

NOTIFY以一些重要的方式与 SQL事务互动。首先,如果一个NOTIFY在一个事务内执行,在事务被提交之前,该通知事件都不会被递送。这是合适的,因为如果该事务被中止,所有其中的命令都将不会产生效果,包括NOTIFY在内。但如果期望通知事件被立即递送,那这种行为就会令人不安。其次,如果一个监听会话收到了一个通知信号而它正在一个事务中,在该事务完成(提交或者中止)之前,该通知事件将不会被递送给它连接的客户端。同样,原因在于如果一个通知在一个事务内被递送且该事务后来被中止,我们会希望该通知能以某种方式被撤销

但是服务器一旦把通知发送给客户端就无法“收回它”。因此通知事件只能在事务之间递送。其中的要点是把NOTIFY用作实时信号的应用应该让它们事务尽可能短小。

如果从同一个事务多次用相同的载荷字符串对同一个频道名称发送通知,数据库服务器能决定只递送一个单一的通知。另一方面,带有不同载荷字符串的通知将总是作为不同的通知被递送。类似地,来自不同事务的通知将不会被折叠成一个通知。除了丢弃后来生成的重复通知实例之外,NOTIFY保证来自同一个事务的通知按照它们被发送的顺序被递送。还可以保证的是,来自不同事务的消息会按照其事务被提交的顺序递送。

一个执行NOTIFY的客户端自己也同时在监听同一个通知频道是很常见的事。在这种情况下,和所有其他监听会话一样,它会取回一个通知事件。根据应用的逻辑,这可能导致无用的工作,例如从自己刚刚写入的一个表中读出相同的更新。可以通过关注发出通知的服务器进程PID(在通知事件消息中提供)与自己的会话PID(可以从libkci得到)是否相同来避免这种额外的工作。当两者相同时,该通知事件就是当前会话自己发出的,所以可以忽略。

前置条件

语法

NOTIFY channel [ , payload ]

语义

channel

要对其发信号的通知频道的名称(任意标识符)。

payload

要通过通知进行沟通的“载荷”字符串。这必须是一个简单的字符串。在默认配置下,该字符串不能超过8000字节(如果需要发送二进制数据或者更多信息,最好是把它放在一个数据库表中并且发送该记录的键)。

示例

从ksql配置和执行一个监听/通知序列:

LISTEN virtual;
NOTIFY virtual;
Asynchronous notification "virtual" received from server process with PID 8448.
NOTIFY virtual, 'This is the payload';
Asynchronous notification "virtual" with payload "This is the payload" received
from server process with PID 8448.

LISTEN foo;
SELECT sys_notify('fo' || 'o', 'pay' || 'load');
Asynchronous notification "foo" with payload "payload" received from server
process with PID 14728.

兼容性

在 SQL 标准中没有NOTIFY语句。

其他

有一个队列保持着已经发送但是还没有被所有监听会话处理的通知。如果该队列被占满,调用NOTIFY的事务将在提交时失败。该队列非常大(标准安装中是8GB)并且应该足以应付几乎每一种用例。不过,如果一个会话执行了NOTIFY并且接着长时间进入一个事务,不会发生清理操作。一旦该队列使用过半,你将在日志文件中看到警告,它指出哪个会话阻止了清理。在这种情况中,应该确保这个会话结束它的当前事务,这样清理才能够进行下去。

函数sys_notification_queue_usage返回队列中当前被待处理通知所占据的比例。详见 系统信息函数和操作符 。

一个已经执行了NOTIFY的事务不能为两阶段提交做准备。

要发送一个通知,你也能使用函数sys_notify(texttext)。该函数采用频道名称作为第一个参数,而载荷则作为第二个参数。如果你需要使用非常量的频道名称和载荷,这个函数比NOTIFY命令更容易使用。

20.4. PREPARE

用途

PREPARE — 为执行准备一个语句

SELECT INTO创建一个新表并且用一个查询计算得到的数据填充它。这些数据不会像普通的``SELECT``那样被返回给客户端。新表的列具有和SELECT的输出列相关的名称和数据类型。

PREPARE创建一个预备语句。预备语句是一种服务器端对象,它可以被用来优化性能。当PREPARE语句被执行时,指定的语句会被解析、分析并且重写。当后续发出一个EXECUTE命令时,该预备语句会被规划并且执行。这种工作的划分避免了重复性的解析分析工作,不过允许执行计划依赖所提供的特定参数值。

预备语句可以接受参数:在执行时会被替换到语句中的值。在创建预备语句时,可以用位置引用参数,如$1$2等。也可以选择性地指定参数数据类型的一个列表。当一个参数的数据类型没有被指定或者被声明为unknown时,其类型会从该参数被第一次引用的环境中推知(如果可能)。在执行该语句时,在EXECUTE语句中为这些参数指定实际值。更多有关于此的信息可参考 EXECUTE 。

预备语句只在当前数据库会话期间存在。当会话结束时,预备语句会消失,因此在重新使用之前必须重新建立它。这也意味着一个预备语句不能被多个数据库客户端同时使用。不过,每一个客户端可以创建它们自己的预备语句来使用。预备语句可以用 DEALLOCATE 命令手工清除。

当一个会话要执行大量类似语句时,预备语句可能会有最大性能优势。如果该语句很复杂(难于规划或重写),例如,如果查询涉及很多表的连接或者要求应用多个规则,性能差异将会特别明显。如果语句相对比较容易规划和重写,但是执行起来开销相对较大,那么预备语句的性能优势就不那么显著了。

前置条件

语法

PREPARE name [ ( data_type [, ...] ) ] AS statement

语义

name

给这个特定预备语句的任意名称。它在一个会话中必须唯一并且后续将被用来执行或者清除一个之前准备好的语句。

data_type

预备语句一个参数的数据类型。如果一个特定参数的数据类型没有被指定或者被指定为unknown,将从该参数被第一次引用的环境中推得。要在预备语句本身中引用参数,可以使用``$1``、$2等。

statement

任何SELECTINSERTUPDATEDELETE或者VALUES语句。

示例

为一个INSERT语句创建一个预备语句,然后执行它:

PREPARE fooplan (int, text, bool, numeric) AS
    INSERT INTO foo VALUES($1, $2, $3, $4);
EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);

为一个SELECT语句创建一个预备语句,然后执行它:

PREPARE usrrptplan (int) AS
    SELECT * FROM users u, logs l WHERE u.usrid=$1 AND u.usrid=l.usrid
    AND l.date = $2;
EXECUTE usrrptplan(1, current_date);

在本例中,没有指定第二个参数的数据类型,因此,它是从使用$2的上下文中推断出来的。

兼容性

SQL 标准包括一个PREPARE语句,但是它只用于嵌入式 SQL。这个版本的PREPARE语句也使用了一种有些不同的语法。

其他

可以使用generic plancustom plan来执行准备好的语句。通用计划在所有执行中是相同的,而使用调用中给定的参数值为特定执行生成自定义计划。使用通用计划可以避免计划开销,但在某些情况下,自定义计划执行起来更有效,因为计划人员可以利用参数值的知识。(当然,如果准备好的语句没有参数,那么这是没有意义的,通常使用的是通用计划。)

默认情况下(也就是说,当 plan_cache_mode 被设置为auto),服务器将自动选择对一个有参数的准备好的语句使用通用计划还是自定义计划。当前的规则是,前五个执行是使用定制计划完成的,并计算这些计划的平均估计成本。然后创建一个通用计划,并将其估计成本与平均定制计划成本进行比较。如果通用计划的成本并不比平均定制计划成本高得多,从而使重复的重新计划看起来更可取,那么随后的执行将使用通用计划。

通过将plan_cache_mode设置为force_generic_planforce_custom_plan,可以覆盖此启发式,迫使服务器使用通用计划或自定义计划。这个设置主要是有用的,如果通用计划的成本估计由于某种原因很差,允许选择它,即使它的实际成本比定制计划的成本要高得多。

要检查KingbaseES为一个预备语句使用的查询计划,可以使用 EXPLAIN ,例如:

EXPLAIN EXECUTE stmt_name(parameter_values);

如果使用的是一个通用计划,它将包含参数符号$n,而一个定制计划则会把提供的参数值替换进去。

更多关于查询规划以及KingbaseES为此所收集的统计信息的内容,请见 ANALYZE 文档。

尽管预备语句主要是为了避免重复对语句进行解析分析以及规划,但是只要上一次使用该预备语句后该语句中用到的数据库对象发生了定义性(DDL)改变,KingbaseES将会对该语句强制进行重新分析和重新规划。还有,如果 search_path 的值发生变化,也将使用新的search_path重新解析该语句(后一种行为是从KingbaseES V8.2 开始的新行为)。这些规则让预备语句的使用在语义上几乎等效于反复提交相同的查询文本,但是能在性能上获利(如果没有对象定义被改变,特别是如果最优计划保持不变时)。该语义等价性不完美的一个例子是:如果语句用一个未限定的名称引用表,并且之后在search_path中更靠前的模式中创建了一个新的同名表,则不会发生自动的重解析,因为该语句使用的对象没有被改变。不过,如果某些其他更改造成了重解析,后续使用中都会引用新表。

可以通过查询 sys_prepared_statements 系统视图来看到会话中所有可用的预备语句。

20.5. PREPARE TRANSACTION

用途

PREPARE TRANSACTION — 为两阶段提交准备当前事务

PREPARE TRANSACTION为两阶段提交准备当前事务。在这个命令之后,该事务不再与当前会话关联。相反,它的状态被完全存储在磁盘上,并且有很高的可能性它会被提交成功(即便在请求提交前发生数据库崩溃)。

一旦被准备好,事务稍后就可以分别用 COMMIT PREPARED 或者 ROLLBACK PREPARED 提交或者回滚。可以从任何会话而不仅仅是执行原始事务的会话中发出这些命令。

从发出命令的会话的角度来看,PREPARE TRANSACTION不像ROLLBACK命令:在执行它之后,就没有活跃的当前事务,并且该预备事务的效果也不再可见(如果该事务被提交,效果将重新变得可见)。

如果由于任何原因PREPARE TRANSACTION命令失败,它会变成一个ROLLBACK:当前事务会被取消。

前置条件

PREPARE TRANSACTION并不是设计为在应用或者交互式会话中使用。它的目的是允许一个外部事务管理器在多个数据库或者其他事务性来源之间执行原子的全局事务。除非你在编写一个事务管理器,否则你可能不会用到PREPARE TRANSACTION

这个命令必须在一个事务块中使用。事务块用 BEGIN 开始。

当前在已经执行过任何涉及到临时表、创建带WITH HOLD的游标或者执行LISTENUNLISTENNOTIFY的事务中,不允许PREPARE该事务。这些特性与当前会话绑定得太过紧密,所以对一个要被准备的事务来说没有什么用处。

语法

PREPARE TRANSACTION transaction_id

语义

transaction_id

一个任意的事务标识符,COMMIT PREPARED或者ROLLBACK PREPARED以后将用这个标识符来标识这个事务。该标识符必须写成一个字符串,并且长度必须小于 200 字节。它也不能与任何当前已经准备好的事务的标识符相同。

示例

为两阶段提交准备当前事务,使用foobar作为事务标识符:

PREPARE TRANSACTION 'foobar';

兼容性

PREPARE TRANSACTION是一种 KingbaseES扩展。其意图是用于外部事务管理系统,其中有些已经被标准涵盖(例如 X/Open XA),但是那些系统的 SQL 方面未被标准化。

其他

如果用SET(不带LOCAL选项)修改过事务的任何运行时参数,这些效果会持续到PREPARE TRANSACTION之后,并且将不会被后续的任何COMMIT PREPARED或``ROLLBACK PREPARED``所影响。因此,在这一方面PREPARE TRANSACTION的行为更像COMMIT而不是ROLLBACK

所有当前可用的准备好事务被列在 sys_prepared_xacts 系统视图中。

Caution

让一个事务处于准备好状态太久是不明智的。这将会干扰VACUUM回收存储的能力,并且在极限情况下可能导致数据库关闭以阻止事务 ID 回卷(见 防止事务ID回卷失败 )。还要记住,该事务会继续持有它已经持有的锁。该特性的设计用法是,只要一个外部事务管理器已经验证其他数据库也准备好了要提交,一个准备好的事务将被正常地提交或者回滚。

如果没有建立一个外部事务管理器来跟踪准备好的事务并且确保它们被迅速地结束,最好禁用准备好事务特性(设置max_prepared_transactions为零)。这将防止意外地创建准备好事务,不然该事务有可能被忘记并且最终导致问题。

20.6. PURGE TABLE

用途

PURGE TABLE分为删除回收站中指定的一个表和清空回收站。 清理回收站时,回收站视图recyclebin和回收站系统表sys_recyclebin中对象将被清除。 删除回收站中指定的一个表时,将删除表及其相关联对象,例如表的index、constraint、trigger、policy、rule等。 清空回收站将删除回收站中所有的表及关联对象。

PUGRE RECYCLEBIN清空回收站,不属于当前schema的表也将清空。

前置条件

PUGRE TABLE删除回收站中一个指定的table。要执行这个命令你必须是该表的拥有者,如果指定的表不属于当前search_path,则还需要指定schema。

语法

删除回收站中指定的一个表

PURGE TABLE table_name;

清空回收站中所有的表

PURGE RECYCLEBIN;

语义

table_name

指定需要删除的表。

示例

这个命令将删除回收站中名为kinds的表及其关联对象:

PURGE TABLE kinds;

这个命令将清空回收站中所有的对象:

PURGE RECYCLEBIN;

兼容性

PUGRE TABLE语句是一个KingbaseES扩展。

其他

无。

20.7. REASSIGN OWNED

用途

REASSIGN OWNED — 更改一个数据库角色拥有的数据库对象的拥有关系

REASSIGN OWNED指示系统把 ``old_role们``拥有的任何数据库对象的拥有关系更改为 ``new_role``

前置条件

REASSIGN OWNED同时要求源角色和目标角色上的资格。

语法

REASSIGN OWNED BY { old_role | CURRENT_USER | SESSION_USER } [, ...]
                TO { new_role | CURRENT_USER | SESSION_USER }

语义

old_role

一个角色的名称。这个角色在当前数据库中所拥有的 所有对象以及所有共享对象(数据库、表空间)的 所有权都将被重新赋予给 ``new_role``

new_role

将作为受影响对象的新拥有者的角色名称。

示例

移除曾经拥有过对象的角色的方法是:

REASSIGN OWNED BY doomed_role TO successor_role;
DROP OWNED BY doomed_role;
-- 在集簇中的每一个数据库中重复上述命令
DROP ROLE doomed_role;

兼容性

REASSIGN OWNED命令是一种 KingbaseES扩展。

其他

REASSIGN OWNED经常被用来为移除一个或者多个角色做准备。因为REASSIGN OWNED不影响其他数据库中的对象,通常需要在包含有被删除的角色所拥有的对象的每一个数据库中都执行这个命令。

DROP OWNED 命令可以简单地删掉一个或者多个角色所拥有的所有数据库对象。

REASSIGN OWNED命令不会影响授予给 *old_role们``*的在它们不拥有的对象上的任何特权。同样,它也不会影响用\ ``ALTER DEFAULT PRIVILEGES创建的默认特权。DROP OWNED 可以回收那些特权。

更多讨论请见 删除角色 。

20.8. REFRESH MATERIALIZED VIEW

用途

REFRESH MATERIALIZED VIEW — 替换一个物化视图的内容

REFRESH MATERIALIZED VIEW完全替换一个物化视图的内容。旧的内容会被抛弃。如果指定了``WITH DATA``(或者作为默认值),支持查询将被执行以提供新的数据,并且会让物化视图将处于可扫描的状态。如果指定了``WITH NO DATA``,则不会生成新数据并且会让物化视图处于一种不可扫描的状态。

前置条件

CONCURRENTLYWITH NO DATA 不能被一起指定。

语法

REFRESH MATERIALIZED VIEW [ CONCURRENTLY ] name
    [ WITH [ NO ] DATA ]

语义

CONCURRENTLY

对物化视图的刷新不阻塞在该物化视图上的并发选择。如果没有这个选项,一次影响很多行的刷新将使用更少的资源并且更快结束,但是可能会阻塞其他尝试从物化视图中读取的连接。这个选项在只有少量行被影响的情况下可能会更快。

只有当物化视图上有至少一个UNIQUE索引(只用列名并且包括所有行)时,才允许这个选项。也就是说,该索引不能建立在任何表达式上或者包括WHERE子句。

当物化视图还未被填充时,这个选项不能被使用。

即使带有这个选项,对于任意一个物化视图一次也只能运行一个``REFRESH``。

name

要刷新的物化视图的名称(可以被模式限定)。

示例

这个命令将使用物化视图order_summary定义中的查询来替换该物化视图的内容,并且让它处于一种可扫描的状态:

REFRESH MATERIALIZED VIEW order_summary;

这个命令将释放与物化视图annual_statistics_basis相关的存储并且让它变成一种不可扫描的状态:

REFRESH MATERIALIZED VIEW annual_statistics_basis WITH NO DATA;

兼容性

REFRESH MATERIALIZED VIEW是一种 KingbaseES扩展

其他

虽然用于未来的 CLUSTER 操作的默认索引会被保持,REFRESH MATERIALIZED VIEW不会基于这个属性排序产生的行。如果希望数据在产生时排序,必须在支持查询中使用``ORDER BY``子句。

20.9. REINDEX

用途

REINDEX — 重建索引

REINDEX使用索引的表里存储的数据重建一个索引,并且替换该索引的旧拷贝。有一些场景需要使用REINDEX

  • 一个索引已经损坏,并且不再包含合法数据。尽管理论上这不会发生,实际上索引会因为软件缺陷或硬件失效损坏。 REINDEX提供了一种恢复方法。

  • 一个索引变得“臃肿”,其中包含很多空的或者近乎为空的页面。KingbaseES中的 B-树索引在特定的非常规访问模式下可能会发生这种情况。``REINDEX``提供了一种方法来减少索引的空间消耗,即制造一个新版本的索引,其中没有死亡页面。详见 日常重建索引 。

  • 修改了一个索引的存储参数(例如填充因子),并且希望确保这种修改完全生效。

  • 如果CONCURRENTLY选项的索引构建失败,该索引被保留为“invalid”。这样的索引是无用的,但是可以方便地使用REINDEX来重建它们。注意,只有REINDEX INDEX能够在无效索引上执行并发构建。

前置条件

语法

REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] name

语义

INDEX

重新创建指定的索引。

TABLE

重新创建指定表的所有索引。如果该表有一个二级 “TOAST”表,它也会被重索引。

SCHEMA

重建指定方案的所有索引。如果这个方案中的一个表有次级的“TOAST”表,它也会被重建索引。共享系统目录上的索引也会被处理。这种形式的REINDEX不能在事务块内执行。

DATABASE

重新创建当前数据库内的所有索引。共享的系统目录上的索引也会被 处理。这种形式的REINDEX不能在一个 事务块内执行。

SYSTEM

重新创建当前数据库中在系统目录上的所有索引。共享系统目录上的 索引也被包括在内。用户表上的索引则不会被处理。这种形式的 REINDEX不能在一个事务块内执行。

name

要被重索引的特定索引、表或者数据库的名字。索引和表名可以被 模式限定。当前,REINDEX DATABASE和 REINDEX SYSTEM只能重索引当前数据库,因此 它们的参数必须匹配当前数据库的名称。

CONCURRENTLY

当使用此选项时,KingbaseES将重新构建索引,而不采取任何锁来防止表上的并发插入、更新或删除;而标准的索引重新构建将锁定表上的写操作(而不是读操作),直到完成为止。 在使用这个选项时需要注意几个注意事项参见 同时重建索引_ .

VERBOSE

在每个索引被重建时打印进度报告。

示例

重建单个索引:

REINDEX INDEX my_index;

重建表my_table上的所有索引:

REINDEX TABLE my_table;

重建一个特定数据库中的所有索引,且不假设系统索引已经可用:

$ export KINGBASE_OPTIONS="-P"
$ ksql broken_db
...
broken_db=> REINDEX DATABASE broken_db;
broken_db=> \q

重新建立表的索引,在重新建立索引的过程中不阻塞对相关关系的读写操作:

REINDEX TABLE CONCURRENTLY my_broken_table;

兼容性

在 SQL 标准中没有REINDEX命令。

其他

如果怀疑一个用户表上的索引损坏,可以使用 REINDEX INDEX或者``REINDEX TABLE``简单地重建该索引 或者表上的所有索引。

如果你需要从一个系统表上的索引损坏中恢复,就更困难一些。在这种情况下,对系统来说重要的是没有使用过任何可疑的索引本身(实际上,这种场景中,你可能会发现服务器进程会在启动时立刻崩溃,这是因为对于损坏的索引的依赖)。要安全地恢复,服务器必须用``-P``选项启动,这将阻止它使用索引来进行系统 目录查找。

这样做的一种方法是关闭服务器,并且启动一个单用户的KingbaseES服务器,在其命令行 中包括-P选项。然后,可以发出``REINDEX DATABASE``、REINDEX SYSTEMREINDEX TABLE或者REINDEX INDEX,具体使用哪个命令取决于你想要重构多少东西。如果有疑问,可以使用``REINDEX SYSTEM``来选择重建数据库中的所有系统索引。然后退出单用户服务器会话并且重启常规的服务器。更多关于如何与单用户服务器接口交互的内容请见 kingbase 参考页。

在另一种方法中,可以开始一个常规的服务器会话,在其命令行选项中包括-P。这样做的方法与客户端有关,但是在所有基于libkci的客户端中都可以在开始客户端之前设置KINGBASE_OPTIONS环境变量为-P。注意虽然这种方法不要求用锁排斥其他客户端,在修复完成之前避免其他用户连接到受损的数据库才是更加明智的。

REINDEX类似于删除索引并且重建索引,在其中索引内容会被从头开始建立。不过,锁定方面的考虑却相当不同。REINDEX会用锁排斥写,但不会排斥在索引的父表上的读。它也会在被处理的索引上取得一个排他锁,该锁将会阻塞对该索引的使用尝试。相反,DROP INDEX 会暂时在附表上取得一个排他锁,阻塞写和读。后续的CREATE INDEX会排斥写但不排斥读,由于该索引不存在,所以不会有读取它的尝试,这意味着不会有阻塞但是读操作可能被强制成昂贵的顺序扫描。

重索引单独一个索引或者表要求用户是该索引或表的拥有者。对方案或数据库重建索引要求是该方案或者数据库的拥有者。注意因此非超级用户有时无法重建其他用户拥有的表上的索引。不过,作为一种特例,当一个非超级用户发出REINDEX DATABASEREINDEX SCHEMA或者REINDEX SYSTEM时,共享目录上的索引将被跳过,除非该用户拥有该目录(通常不会是这样)。当然,超级用户总是可以重建所有的索引。

不支持重建分区表的索引或者分区索引。不过可以单独为每个分区重建索引。重建索引可能会干扰数据库的正常操作。通常KingbaseES会锁定一个表,这个表的索引是根据写操作重新构建的,并且只扫描一次表就可以执行整个索引构建。其他事务仍然可以读取表,但是如果它们试图插入、更新或删除表中的行,它们将阻塞这些行,直到完成索引重建。如果系统是一个实时的生产数据库,这可能会产生严重的影响。非常大的表可能需要花费很多小时来建立索引,甚至对于更小的表,重新构建索引可能会将编写者锁定在生产系统无法接受的长时间内。

KingbaseES支持最小化写锁的重建索引。该方法调用CONCURRENTLYREINDEX选项。当使用这个选项时,KingbaseES必须为每个需要重建的索引执行两次表扫描,并等待可能使用该索引的所有现有事务的终止。与标准的索引重建相比,此方法需要更多的总工作,而且完成所需的时间要长得多,因为它需要等待可能修改索引的未完成事务。但是,由于它允许在重新构建索引时继续正常操作,所以此方法对于在生产环境中重新构建索引非常有用。的当然,由索引重新生成的额外CPU、内存和I/O负载可能会减慢其他操作。

在并发重索引中执行以下步骤。每个步骤都在一个单独的事务中运行。如果有多个索引需要重新构建,那么每个步骤在进入下一个步骤之前循环遍历所有索引。

  1. 一个新的临时索引定义被添加到目录sys_index。此定义将用于替换旧索引。会话级别的SHARE UPDATE EXCLUSIVE锁对正在重编索引的索引及其关联表执行锁,以防止在处理时进行任何模式修改。

  2. 为每个新索引完成构建索引的第一次遍历。一旦建立了索引,它的标志sys_index.indisready被切换为“true”,以使它为插入做好准备,使它在执行构建的事务完成后对其他会话可见。此步骤在每个索引的单独事务中完成。

  3. 然后执行第二个遍历来添加在第一个遍历运行时添加的元组。此步骤也在每个索引的单独事务中完成。

  4. 所有引用索引的约束都被更改为引用新的索引定义,索引的名称也被更改。此时,sys_index.indisvalid是转向“true”新指数和“false”,缓存失效导致所有会话引用旧的索引失效。

  5. 旧的索引由sys_index.indisready切换到“false”以防止任何新的元组插入,在等待可能引用旧索引的查询完成之后。

  6. 旧的索引被删除。索引和表的SHARE UPDATE EXCLUSIVE会话锁被释放。

如果在重新构建索引时出现问题,例如惟一索引中的唯一性冲突,则REINDEX命令将失败,但会留下一个“invalid”的新索引附加于已存在的索引。出于查询的目的,这个索引将被忽略,因为它可能是不完整的;但是,它仍然会消耗更新开销。ksql``d``命令将报告这样一个索引:INVALID:

kingbase=# \d tab
       Table "public.tab"
 Column |  Type   | Modifiers
--------+---------+-----------
 col    | integer |
Indexes:
    "idx" btree (col)
    "idx_ccnew" btree (col) INVALID

在这种情况下,建议的恢复方法是删除无效的索引,然后再次尝试并发地执行REINDEX CONCURRENTLY。在处理过程中创建的并发索引的名称以后缀ccnew,或ccold(如果它是我们未能删除的旧索引定义)结尾。可以使用DROP INDEX删除无效索引,包括无效的toast索引。

常规索引构建允许同一表上的其他常规索引构建同时发生,但是一次只能在一个表上发生一个并发索引构建。在这两种情况下,不允许同时对表进行其他类型的模式修改。另一个区别是常规的REINDEX TABLEREINDEX INDEX命令可以在一个事务块中执行,但是REINDEX CONCURRENTLY不能执行。

REINDEX SYSTEM不支持``CONCURRENTLY``,因为系统目录不能并发重索引。

此外,排除约束的索引不能并发地重新建立索引。如果在此命令中直接命名这样的索引,则会引发错误。如果具有排它约束索引的表或数据库被并发地重新索引,那么这些索引将被跳过。(可以在不使用CONCURRENTLY选项的情况下重新索引这些索引。)

20.10. RELEASE SAVEPOINT

用途

RELEASE SAVEPOINT — 销毁一个之前定义的保存点

RELEASE SAVEPOINT销毁在当前事务中之前定义的一个保存点。

销毁一个保存点会使得它不能再作为一个回滚点,但是它没有其他用户可见的行为。它不会撤销在该保存点被建立之后执行的命令的效果(要这样做,可见 ROLLBACK TO SAVEPOINT )。当不再需要一个保存点时销毁它允许系统在事务结束之前回收一些资源。

RELEASE SAVEPOINT也会销毁所有在该保存点建立之后建立的保存点。

前置条件

指定一个不是之前定义的保存点名称是错误。

当事务处于中止状态时不能释放保存点。

如果多个保存点具有相同的名称,只有最近被定义的那个会被释放。

语法

RELEASE [ SAVEPOINT ] savepoint_name

语义

savepoint_name

要销毁的保存点的名称。

示例

建立并且销毁一个保存点:

BEGIN;
    INSERT INTO table1 VALUES (3);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (4);
    RELEASE SAVEPOINT my_savepoint;
COMMIT;

上述事务将插入 3 和 4。

兼容性

这个命令符合SQL标准。该标准指定关键词``SAVEPOINT``是强制需要的,但 KingbaseES允许省略。

20.11. RESET

用途

RESET — 把一个运行时参数的值恢复到默认值

RESET把运行时参数恢复到它们的默认值。 RESET

SET configuration_parameter TO DEFAULT

的另一种写法。 详见 :ref:`SET` 。

前置条件

语法

RESET configuration_parameter
RESET ALL

语义

configuration_parameter

一个可设置的运行时参数名称。可用的参数记录在 服务器配置参数参考手册 以及 SET 参考页中。

ALL

把所有可设置的运行时参数重置为默认值。

示例

timezone配置变量设置为默认值:

RESET timezone;

兼容性

RESET是一种 KingbaseES扩展。

其他

默认值被定义为如果在当前会话中没有发出过SET,参数必须具有的值。这个值的实际来源可能是一个编译在内部的默认值、配置文件、命令行选项、或者针对每个数据库或者每个用户的默认设置。这和把它定义成“在会话开始时该参数得到的值”有细微的差别,因为如果该值来自于配置文件,它将被重置为现在配置文件所指定的任何东西。详见 服务器配置参数参考手册 。

RESET的事务行为和SET相同:它的效果会被事务回滚撤销。

20.12. REVOKE

用途

REVOKE命令收回之前从一个或者更多角色 授予的特权。关键词PUBLIC隐式定义的全部角色的组。

特权类型的含义见 GRANT 命令的描述。

注意任何特定角色拥有的特权包括直接授予给它的特权、从它作为其成员的 角色中得到的特权以及授予给PUBLIC的特权。因此, 从PUBLIC收回SELECT特权并不一定会意味 着所有角色都会失去在该对象上的SELECT特权:那些直接被授 予的或者通过另一个角色被授予的角色仍然会拥有它。类似地,从一个用户 收回SELECT后,如果PUBLIC或者另一个 成员关系角色仍有SELECT权利,该用户还是可以使用 SELECT

如果指定了GRANT OPTION FOR,只会回收该特权 的授予选项,特权本身不被回收。否则,特权及其授予选项都会被回收。

如果一个用户持有一个带有授予选项的特权并且把它授予给了其他用户, 那么被那些其他用户持有的该特权被称为依赖特权。如果第一个用户持有 的该特权或者授予选项正在被收回且存在依赖特权,指定 CASCADE可以连带回收那些依赖特权,不指定则会 导致回收动作失败。这种递归回收只影响通过可追溯到该 REVOKE命令的主体的用户链授予的特权。因此, 如果该特权经由其他用户授予给受影响用户,受影响用户可能实际上还 保留有该特权。

在回收一个表上的特权时,也会在该表的每一个列上自动回收对应的列 特权(如果有)。在另一方面,如果一个角色已经被授予一个表上的 特权,那么从个别的列上回收同一个特权将不会生效。

在回收一个角色中的成员关系时,GRANT OPTION被改 称为ADMIN OPTION,但行为是类似的。也要注意这种 形式的命令不允许噪声词GROUP

前置条件

用户只能回收由它直接授出的特权。例如,如果用户 A 已经把一个带有授予选项的特权授予给了用户 B,并且用户 B 接着把它授予给了用户 C,那么用户 A 无法直接从 C 收回该特权。反而,用户 A 可以从用户 B 收回该授予选项并且使用CASCADE选项,这样该特权会被 依次从用户 C回收。对于另一个例子,如果 A 和 B 都把同一个特权授予 给了 C,A能够收回它们自己的授权但不能收回 B 的授权,因此 C 实际上仍将拥有该特权。

当一个对象的非拥有者尝试REVOKE该对象上的特权时,如果该用户在该对象上什么特权都不拥有,该命令会立刻失败。只要有某个特权可用,该命令将继续,但是它只会收回那些它具有授予选项的特权。如果没有持有授予选项,REVOKE ALL PRIVILEGES形式将发出一个警告,而其他形式在没有持有该命令中特别提到的任何特权的授予选项时就会发出警告(原则上,这些语句也适用于对象拥有者,但是由于拥有者总是被认为持有所有授予选项,这些情况永远不会发生)。

如果一个超级用户选择发出一个GRANT或者``REVOKE``命令,该命令就好像被受影响对象的拥有者发出的一样被执行。因为所有特权最终来自于对象拥有者(可能是间接地通过授予选项链),可以由超级用户收回所有特权,但是这可能需要前述的``CASCADE``。

REVOKE也可以由一个并非受影响对象的拥有者的角色完成,但是该角色应该是一个拥有该对象的角色的成员或者是一个在该对象上拥有特权的WITH GRANT OPTION的角色的成员。在这种情况中,该命令就好像被实际拥有该对象或者特权的``WITH GRANT OPTION``的包含角色发出的一样被执行。例如,如果表t1被角色g1拥有,而u1``是\ ``g1的一个成员,那么u1能收回t1``上被记录为由\ ``g1授出的特权。这会包括由u1``以及由角色\ ``g1的其他成员完成的授予。

如果执行REVOKE的角色持有通过多于一条角色成员关系路径间接得到的特权,其中哪一条包含将被用于执行该命令的角色是没有被指明的。在这种情况中,最好使用``SET ROLE``成为你想作为其身份执行``REVOKE``的特定角色。如果无法做到这一点可能会导致回收超过你预期的特权,或者根本回收不了任何东西。

查看 权限 获得更多关于特定特权类型的信息,以及如何检查对象的特权。

语法

REVOKE [ GRANT OPTION FOR ]
    { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
    [, ...] | ALL [ PRIVILEGES ] }
    ON { [ TABLE ] table_name [, ...]
         | ALL TABLES IN SCHEMA schema_name [, ...] }
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [, ...] )
    [, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) }
    ON [ TABLE ] table_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { { USAGE | SELECT | UPDATE }
    [, ...] | ALL [ PRIVILEGES ] }
    ON { SEQUENCE sequence_name [, ...]
         | ALL SEQUENCES IN SCHEMA schema_name [, ...] }
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
    ON DATABASE database_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { USAGE | ALL [ PRIVILEGES ] }
    ON DOMAIN domain_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { USAGE | ALL [ PRIVILEGES ] }
    ON FOREIGN DATA WRAPPER fdw_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { USAGE | ALL [ PRIVILEGES ] }
    ON FOREIGN SERVER server_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { EXECUTE | ALL [ PRIVILEGES ] }
    ON { { FUNCTION | PROCEDURE | ROUTINE } function_name [ ( [ [ argmode ] [
    arg_name ] arg_type [, ...] ] ) ] [, ...]
         | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA schema_name [,
         ...] }
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { USAGE | ALL [ PRIVILEGES ] }
    ON LANGUAGE lang_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
    ON LARGE OBJECT loid [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
    ON SCHEMA schema_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { CREATE | ALL [ PRIVILEGES ] }
    ON TABLESPACE tablespace_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

REVOKE [ GRANT OPTION FOR ]
    { USAGE | ALL [ PRIVILEGES ] }
    ON TYPE type_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]


REVOKE [ ADMIN OPTION FOR ]
    role_name [, ...] FROM role_name [, ...]
    [ CASCADE | RESTRICT ]

语义

示例

从 public 收回表films上的插入特权:

REVOKE INSERT ON films FROM PUBLIC;

从用户manuel收回视图 kinds上的所有特权:

REVOKE ALL PRIVILEGES ON kinds FROM manuel;

注意着实际意味着“收回所有我授出的特权”。

从用户joe收回角色admins中的成员关系:

REVOKE admins FROM joe;

兼容性

GRANT 命令的兼容性注解同样适用于 REVOKE。根据标准,关键词 RESTRICTCASCADE 是必要的,但是KingbaseES默认假定为 RESTRICT

20.13. ROLLBACK

用途

ROLLBACK回滚当前事务并且导致 该事务所作的所有更新都被抛弃。

前置条件

在事务中

语法

ROLLBACK [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ]

语义

WORK TRANSACTION

可选关键词,没有效果。

AND CHAIN

如果指定了AND CHAIN,则立即启动具有与刚刚完成的事务相同的事务特征的新事务(参见 SET TRANSACTION )。否则,不会启动任何新事务。

示例

要回滚所有更改:

ROLLBACK;

兼容性

ROLLBACK命令符合SQL标准。ROLLBACK TRANSACTION是一个KingbaseES扩展。

20.14. ROLLBACK PREPARED

用途

ROLLBACK PREPARED — 取消一个之前为两阶段提交准备好的事务

ROLLBACK PREPARED回滚 一个处于准备好状态的事务

前置条件

要回滚一个准备好的事务,你必须是原先执行该事务的同一个用户或者是一个超级用户。但是你必须处在执行该事务的同一个会话中。

语法

ROLLBACK PREPARED transaction_id

语义

transaction_id

要被回滚的事务的事务标识符。

示例

用事务标识符foobar回滚对应的事务:

ROLLBACK PREPARED 'foobar';

兼容性

ROLLBACK PREPARED是一种 KingbaseES扩展。其意图是用于外部事务管理系统,其中有些已经被标准涵盖(例如 X/Open XA),但是那些系统的 SQL 方面未被标准化。

其他

这个命令不能在一个事务块内被执行。准备好的事务会被立刻回滚。

sys_prepared_xacts 系统视图中列出了当前可用的所有准备好的事务。

20.15. ROLLBACK TO SAVEPOINT

用途

ROLLBACK TO SAVEPOINT — 回滚到一个保存点

回滚在该保存点被建立之后执行的所有命令。该保存点保持有效并且可以在以后再次回滚到它(如果需要)。

ROLLBACK TO SAVEPOINT隐式地销毁在所提及的保存点之后建立的所有保存点。

前置条件

保存点需要提前先建立好

语法

ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] savepoint_name

语义

savepoint_name

要回滚到的保存点。

示例

要撤销在my_savepoint建立后执行的命令的效果:

ROLLBACK TO SAVEPOINT my_savepoint;

游标位置不会受保存点回滚的影响:

BEGIN;

DECLARE foo CURSOR FOR SELECT 1 UNION SELECT 2;

SAVEPOINT foo;

FETCH 1 FROM foo;
 ?column?
----------
        1

ROLLBACK TO SAVEPOINT foo;

FETCH 1 FROM foo;
 ?column?
----------
        2

COMMIT;

兼容性

SQL标准指定关键词 SAVEPOINT是强制的,但是KingbaseES和Oracle允许省略它。SQL 只允许WORK而不是TRANSACTION作为ROLLBACK之后的噪声词。还有,SQL 有一个可选的子句 AND [ NO ] CHAIN,当前KingbaseES并不支持。在其他方面,这个命令符合 SQL 标准。

其他

使用 RELEASE SAVEPOINT 销毁一个保存点而不抛弃在它建立之后被执行的命令的效果。

指定一个没有被建立的保存点是一种错误。

相对于保存点,游标有一点非事务的行为。在保存点被回滚时,任何在该保存点内被打开的游标将会被关闭。如果一个先前打开的游标在一个保存点内被``FETCH``或MOVE命令所影响,而该该保存点后来又被回滚,那么该游标将保持FETCH使它指向的位置(也就是说由FETCH导致的游标动作不会被回滚)。回滚也不能撤销关闭一个游标。不过,其他由游标查询导致的副作用(例如被该查询所调用的易变函数的副作用)可以被回滚,只要它们发生在一个后来被回滚的保存点期间。如果一个游标的执行导致事务中止,它会被置于一种不能被执行的状态,这样当事务被用ROLLBACK TO SAVEPOINT恢复后,该游标也不再能被使用。

20.16. SAVEPOINT

用途

SAVEPOINT在当前事务中建立一个新保存点。

保存点是事务内的一种特殊标记,它允许所有在它被建立之后执行的命令被 回滚,把该事务的状态恢复到它处于保存点时的样子。

前置条件

保存点只能在一个事务块内建立。可以在一个事务内定义多个保存点。

语法

SAVEPOINT savepoint_name

语义

savepoint_name

给新保存点的名字。

示例

要建立一个保存点并且后来撤销在它建立之后执行的所有命令的效果:

BEGIN;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (2);
    ROLLBACK TO SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (3);
COMMIT;

上面的事务将插入值 1 和 3,但不会插入 2。

要建立并且稍后销毁一个保存点:

BEGIN;
    INSERT INTO table1 VALUES (3);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (4);
    RELEASE SAVEPOINT my_savepoint;
COMMIT;

上面的事务将插入 3 和 4。

兼容性

当建立另一个同名保存点时,SQL 标准要求之前的那个保存点自动被销毁。在 KingbaseES中,旧的保存点会被保留,不过在进行 回滚或释放时只能使用最近的那一个(用 RELEASE SAVEPOINT释放较新的保存点将会 导致较旧的保存点再次变得可以被 ROLLBACK TO SAVEPOINT和 RELEASE SAVEPOINT访问)。在其他方面, SAVEPOINT完全符合 SQL。

其他

使用 ROLLBACK TO 回滚到一个保存点。 使用 RELEASE SAVEPOINT 销毁一个保存点, 但保持在它被建立之后执行的命令的效果。

20.17. SECURITY LABEL

用途

SECURITY LABEL — 定义或更改应用到一个对象的安全标签

SECURITY LABEL对一个数据库对象应用一个安全标签。可以把任意数量的安全标签(每个标签提供者对应一个)关联到一个给定的数据库对象。标签提供者是使用函数``register_label_provider``注册自己的可装载模块。

注意

register_label_provider不是一个 SQL 函数,它只能在被载入 到后端的 C 代码中调用。

前置条件

语法

SECURITY LABEL [ FOR provider ] ON
{
  TABLE object_name |
  COLUMN table_name.column_name |
  AGGREGATE aggregate_name ( aggregate_signature ) |
  DATABASE object_name |
  DOMAIN object_name |
  EVENT TRIGGER object_name |
  FOREIGN TABLE object_name
  FUNCTION function_name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] |
  LARGE OBJECT large_object_oid |
  MATERIALIZED VIEW object_name |
  [ PROCEDURAL ] LANGUAGE object_name |
  PUBLICATION object_name |
  ROLE object_name |
  SCHEMA object_name |
  SEQUENCE object_name |
  SUBSCRIPTION object_name |
  TABLESPACE object_name |
  TYPE object_name |
  VIEW object_name
} IS 'label'

其中 aggregate_signature 是:

* |
[ argmode ] [ argname ] argtype [ , ... ] |
[ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ]
argtype [ , ... ]

语义

object_name table_name.column_name aggregate_name function_name

要被贴上标签的对象的名称。表、聚集、域、外部表、函数、序列、类型和视图 的名称可以是模式限定的。

provider

这个标签相关联的提供者的名称。所提到的提供者必须已被载入并且必须赞同所提出 的标签操作。如果正好只载入了一个提供者,可以出于简洁的需要忽略提供者的名称。

argmode

一个函数或者聚集参数的模式:INOUT、 INOUT或者VARIADIC。如果被忽略,默认值会是 IN。注意SECURITY LABEL并不真正 关心OUT参数,因为判断函数的身份时只需要输入参数。因此列出 ININOUTVARIADIC参数足矣。

argname

一个函数或者聚集参数的名称。注意SECURITY LABEL 并不真正关心参数的名称,因为判断函数的身份时只需要参数的数据类型。

argtype

一个函数或聚集参数的数据类型。

large_object_oid

大对象的 OID。

PROCEDURAL

这是一个噪声词。

label

写成一个字符串文本的新安全标签。如果写成NULL表示删除 原有的安全标签。

示例

下面的例子展示了如何更改一个表的安全标签。

SECURITY LABEL FOR selinux ON TABLE mytable IS 'system_u:object_r: sekbsql_table_t:s0';

兼容性

在 SQL 标准中没有SECURITY LABEL命令。

其他

标签提供者决定一个给定标签是否合法并且它是否可以被分配该标签给一个给定对象。一个给定标签的含义也同样由标签提供者判断。KingbaseES没有对一个标签提供者是否必须或者如何解释安全标签做出限定,它仅仅只是提供了一种机制来存储它们。实际上,这个功能是为了允许与基于标签的强制访问控制(MAC)系统集成(例如SE-Linux)。这类系统会基于对象标签而不是传统的自主访问控制(DAC)概念(例如用户和组)做出所有访问控制决定。

20.18. SELECT

用途

SELECT, TABLE, WITH — 从一个表或视图检索行。

SELECT从零或更多表中检索行。 SELECT的通常处理如下:

  1. WITH列表中的所有查询都会被计算。这些查询实际 充当了在FROM列表中可以引用的临时表。在 FROM中被引用多次的WITH查询只会被计算一次。 unless specified otherwise with NOT MATERIALIZED.

  2. FROM列表中的所有元素都会被计算( FROM中的每一个元素都是一个真实表或者虚拟表)。 如果在FROM列表中指定了多于一个元素,它们会被 交叉连接在一起。

  3. 如果指定了WHERE子句,所有不满足该条件的行都会 被从输出中消除。

  4. 如果指定了GROUP BY子句或者如果有聚集函数,输出 会被组合成由在一个或者多个值上匹配的行构成的分组,并且在其上计算聚 集函数的结果。如果出现了HAVING子句,它会消除不 满足给定条件的分组。

  5. 对于每一个被选中的行或者行组,会使用SELECT 输出表达式计算实际的输出行。

  6. SELECT DISTINCT从结果中消除重复的行。 SELECT DISTINCT ON消除在所有指定表达式上匹 配的行。SELECT ALL(默认)将返回所有候选行, 包括重复的行。同时KingbaseES中的SELECT UNIQUE也可以从结果中消除重复的行。 SELECT UNIQUE ON消除在所有指定表达式上匹 配的行。SELECT ALL(默认)将返回所有候选行, 包括重复的行。

  7. 通过使用操作符UNION、 INTERSECTEXCEPT,多于 一个SELECT语句的输出可以被整合形成 一个结果集。UNION操作符返回位于一个或者两 个结果集中的全部行。INTERSECT操作符返回同时 位于两个结果集中的所有行。EXCEPT操作符返回 位于第一个结果集但不在第二个结果集中的行。在所有三种情况下, 重复行都会被消除(除非指定ALL)。可以增加噪 声词DISTINCT来显式地消除重复行。注意虽然 ALLSELECT自身的默认行为, 但这里DISTINCT是默认行为。

  8. 如果指定了ORDER BY子句,被返回的行会以指定的 顺序排序。如果没有给定ORDER BY,系统会以能最 快产生行的顺序返回它们(。

  9. 如果指定了LIMIT(或FETCH FIRST) 或者OFFSET子句,SELECT 语句只返回结果行的一个子集。

  10. 如果指定了FOR UPDATE、 FOR NO KEY UPDATE、 FOR SHARE 或者FOR KEY SHARE, SELECT语句会把被选中的行锁定而不让并发 更新访问它们。

前置条件

你必须拥有在一个SELECT命令中使用的每一列上的SELECT特权。FOR NO KEY UPDATEFOR UPDATEFOR SHARE或者FOR KEY SHARE还要求(对这样选中的每一个表至少一列的)UPDATE特权。

语法

[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT | UNIQUE [ ON ( expression [, ...] ) ] ]
    [ * | expression [ [ AS ] output_name ] [, ...] ]
    [ FROM from_item [, ...] ]
    [ WHERE condition ]
    [ GROUP BY grouping_element [, ...] ]
    [ HAVING condition [, ...] ]
    [ WINDOW window_name AS ( window_definition ) [, ...] ]
    [ { UNION | INTERSECT | EXCEPT | MINUS } [ ALL | DISTINCT ] select ]
    [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST |
    LAST } ] [, ...] ]
    [ LIMIT { count | ALL } ]
    [ OFFSET start [ ROW | ROWS ] ]
    [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
    [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name
    [, ...] ]
    [ NOWAIT | SKIP LOCKED | WAIT seconds] [...] ]

其中 from_item 可以是以下之一:

    [ ONLY ] table_name [ * ] [ @dblink ]
                [ PARTITION partition | SUBPARTITION subpartition ]
                [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
                [ [ AS OF { TIMESTAMP | CSN | SCN } asof_item ] | [ VERSIONS BETWEEN { TIMESTAMP | CSN | SCN } start_item  AND end_item ] ]
                [ TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE
                (                 seed ) ] ]

    [ LATERAL ] ( select ) [ AS ] alias [ ( column_alias [, ...] ) ] with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
    [ LATERAL ] function_name ( [ argument [, ...] ] )
                [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
    [ LATERAL ] function_name ( [ argument [, ...] ] ) [ AS ] alias (  column_definition [, ...] )
    [ LATERAL ] function_name ( [ argument [, ...] ] ) AS ( column_definition  [, ...] )
    [ LATERAL ] ROWS FROM( function_name ( [ argument [, ...] ] ) [ AS ( column_definition [, ...] ) ] [, ...] )
                [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
    from_item [ NATURAL ] join types from_item [ ON join_condition | USING ( join_column [, ...] ) ]

并且 grouping_element 可以是以下之一:

    ( )
    expression
    ( expression [, ...] )
    ROLLUP ( { expression | ( expression [, ...] ) } [, ...] )
    CUBE ( { expression | ( expression [, ...] ) } [, ...] )
    GROUPING SETS ( grouping_element [, ...] )

并且 with_query 是:

    with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( select | values | insert | update | delete )

TABLE [ ONLY ] table_name [ * ]

    plsql_declarations

语义

  1. WITH子句

    WITH子句允许你指定一个或者多个在主查询中可以 其名称引用的子查询。在主查询期间子查询实际扮演了临时表或者视图 的角色。每一个子查询都可以是一个SELECT、 TABLEVALUES、 INSERT、 UPDATE或者 DELETE语句。在WITH中书写 一个数据修改语句(INSERT、 UPDATE或者 DELETE)时,通常要包括一个 RETURNING子句。构成被主查询读取的临时表的是 RETURNING的输出,而不是该语句修改的 底层表。如果省略RETURNING,该语句仍会被执行,但是它 不会产生输出,因此它不能作为一个表从主查询引用。

    对于每一个WITH查询,都必须指定一个名称(无需模 式限定)。可选地,可以指定一个列名列表。如果省略该列表,会从该子查 询中推导列名。

    如果指定了RECURSIVE,则允许一个 SELECT子查询使用名称引用自身。 这样一个子查询的形式必须是

    non_recursive_term UNION [ ALL | DISTINCT ] recursive_term
    

    其中递归自引用必须出现在UNION的右手边。每个 查询中只允许一个递归自引用。不支持递归数据修改语句,但是 可以在一个数据查询语句中使用一个递归 SELECT查询的结果。例子可见 WITH查询 。

    RECURSIVE的另一个效果是 WITH查询不需要被排序:一个查询可以引用另一个 在列表中比它靠后的查询(不过,循环引用或者互递归没有实现)。 如果没有RECURSIVEWITH 查询只能引用在WITH列表中位置更前面的兄弟 WITH查询。

    主查询以及WITH查询全部(理论上)在同一时间 被执行。这意味着从该查询的任何部分都无法看到 WITH中的一个数据修改语句的效果,不过可以读 取其RETURNING输出。如果两个这样的数据修改语句 尝试修改相同的行,结果将无法确定。

    WITH查询的关键属性是,在每次执行主查询时,它们通常只被求值一次,即使主查询不止一次地引用它们。特别是,数据修改语句保证只执行一次,而不管主查询是否读取所有或任何输出。

    但是,WITH查询能够标记为NOT MATERIALIZED来移除此保证。在这种情况下,WITH查询可以折叠成主查询,就像它是在主查询的FROM子句中一个简单的SELECT。如果主查询多次引用WITH查询,则会导致重复计算;但是,如果每个这样的使用只需要WITH查询的总输出的几行数据,NOT MATERIALIZED可以通过允许联合优化查询来提供净节省。NOT MATERIALIZED将被忽略,如果它是递归或者不是无副作用的WITH查询附加的(例如:,不是一个普通的SELECT不包含volatile functions)。

    默认情况下,如果在主查询的FROM子句中仅使用一次,那么无副作用的WITH查询将被折叠到主查询中。这允许在语义不可见的情况下联合优化两个查询级别。但是,可以通过将WITH查询标记为MATERIALIZED来防止这种折叠。这可能是有用的,例如,如果WITH查询被用作一个优化围栏,以防止计划员选择一个糟糕的计划。在v12之前的版本中,KingbaseES从未做过这样的折叠,所以为旧版本编写的查询可能依赖于WITH来充当优化屏障。

    更多信息请见 WITH查询 。

  2. FROM子句

    FROM子句为SELECT 指定一个或者更多源表。如果指定了多个源表,结果将是所有源表的 笛卡尔积(交叉连接)。但是通常会增加限定条件(通过 WHERE)来把返回的行限制为该笛卡尔积的一个小子集。

    FROM子句可以包含下列元素:

    table_name

    一个现有表或视图的名称(可以是模式限定的)。如果在表名前指定了 ONLY,则只会扫描该表。如果没有指定 ONLY,该表及其所有后代表(如果有)都会被扫描。可 选地,可以在表名后指定*来显式地指示包括后代表。

    @dblink

    在SELECT语句的FROM子句中,用户可以直接在远程数据库对象名称后加@dblink来指定一个外部数据库中的对象。 访问形式:remote-obj@dblink 对象名称:支持限定名(schema.name格式) 远程对象:可以是表、视图、物化视图,对象类型对本地数据库透明。 使用dblink前需配置对应数据库的ODBC数据源。

    partition

    PARTITION指定一个单层分区表的分区或者复合分区的主分区名称。

    subpartition

    SUBPARTITION指定一个复合分区的子分区名称。

    alias

    一个包含别名的FROM项的替代名称。别名被用于 让书写简洁或者消除自连接中的混淆(其中同一个表会被扫描多 次)。当提供一个别名时,表或者函数的实际名称会被隐藏。例 如,给定FROM foo AS f, SELECT的剩余部分就必须以 f而不是foo来引用这个 FROM项。如果写了一个别名,还可以写一个列别 名列表来为该表的一个或者多个列提供替代名称。

    asof_item

    ``table_name``之后的``AS OF``子句表示应用闪回查询的功能。闪回查询可以通过指定时间戳(timestamp)、csn 两种方式进行查询。 asof_item即通过时间戳(timestamp) 或者csn 进行闪回查询的时候的一个历史快照时刻的表达式。

    更多信息请见《Oracle至KingbaseES V8R6 迁移最佳实践》中的闪回技术。

    start_item和end_item

    ``table_name``之后的``VERSIONS BETWEEN``子句表示应用闪回查询的版本历史查询功能, 和``AS OF``子句里类似,也可以通过时间戳(timestamp)、csn 两种方式进行查询。闪回版本查询通过指定起始的快照时刻即:start_item``和结束的快照时刻``end_item,返回这段时间内的所有可见的版本。

    更多信息请见《Oracle至KingbaseES V8R6 迁移最佳实践》中的闪回技术。

    TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ]

    ``table_name``之后的 TABLESAMPLE子句表示应该用指定的 ``sampling_method`` 来检索表中行的子集。这种采样优先于任何其他过滤器(例如 WHERE子句)。标准 KingbaseES发布包括两种采样 方法:BERNOULLISYSTEM, 其他采样方法可以通过扩展安装在数据库中。

    BERNOULLI以及SYSTEM采样方法都接受 一个``参数``,它表示要采样的表 的分数,表示为一个 0 到 100 之间的百分数。这个参数可以是任意的 实数值表达式(其他的采样方法可能接受更多或者不同的 参数)。这两种方法都返回一个随机选取的该表采样,其中包含了指定 百分数的表行。BERNOULLI方法扫描整个表并且 用指定的几率选择或者忽略行。SYSTEM方法会做 块层的采样,每个块都有指定的机会能被选中,被选中块中的所有行都 会被返回。在指定较小的采样百分数时,SYSTEM 方法要比BERNOULLI方法快很多,但是前者可能 由于聚簇效应返回随机性较差的表采样。

    可选的REPEATABLE子句指定一个用于产生采样方法中随机数的``种子``数或表达式。种子值可以是任何非空浮点值。如果查询时表没有被更改,指定相同种子和``argument``值的两个查询将会选择该表相同的采样。但是不同的种子值通常将会产生不同的采样。如果没有给出REPEATABLE,则会基于一个系统产生的种子为每一个查询选择一个新的随机采样。注意有些扩展采样方法不接受REPEATABLE,并且将总是为每一次使用产生新的采样。

    select

    一个子-SELECT可以出现在 FROM子句中。这就好像把它的输出创建为一个 存在于该SELECT命令期间的临时表。注意 子-SELECT必须用圆括号包围,并且 必须为它提供一个别名。也可以在这里 使用一个 VALUES 命令。

    with_query_name

    可以通过写一个WITH查询的名称来引用它,就好像 该查询的名称是一个表名(实际上,该WITH查询会 为主查询隐藏任何具有相同名称的真实表。如果必要,你可以使用 带模式限定的方式以相同的名称来引用真实表)。可以像表一样, 以同样的方式提供一个别名。

    plsql_declarations

    select语句的with子句中,使用plsql_declarations子句声明和定义函数和存储过程。

    具体定义请参见:具体定义参数信息参见CREATE FUNCTION、CREATE PROCEDURE等。

    使用规则:

    1.With子句定义的函数或者存储过程遵守普通函数或者存储过程的使用规则;

    2.With子句创建的函数或者存储过程的生命周期是当前select语句;

    3.一个with子句可以定义多个plsql函数或者存储过程。并且被调用;

    4.with子句定义存储过程时,不能在select语句中被直接使用,但可以在定义的function里调用。

    function_name

    函数调用可以出现在FROM子句中(对于返回结果 集合的函数特别有用,但是可以使用任何函数)。这就好像把该函数的 输出创建为一个存在于该SELECT命令期 间的临时表。当为该函数调用增加可选的 WITH ORDINALITY子句时,会在该函数 的输出列之后追加一个新的列来为每一行编号。

    可以用和表一样的方式提供一个别名。如果写了一个别名,还可以写一个 列别名列表来为该函数的组合返回类型的一个或者多个属性提供替代名称, 包括由ORDINALITY(如果有)增加的新列。

    通过把多个函数调用包围在ROWS FROM( ... )中可以把它们 整合在单个FROM-子句项中。这样一个项的输出是把每一个 函数的第一行串接起来,然后是每个函数的第二行,以此类推。如果有些 函数产生的行比其他函数少,则在缺失数据的地方放上空值,这样被返回 的总行数总是和产生最多行的函数一样。

    如果函数被定义为返回record数据类型,那么必须出现一个 别名或者关键词AS,后面跟上形为 ( column_name ``data_type`` [, ... ])的列定义列表。列定义列表必须匹配该函数返回的列的实际 数量和类型。

    在使用ROWS FROM( ... )语法时,如果函数之一要求一个列 定义列表,最好把该列定义列表放在ROWS FROM( ... )中该 函数的调用之后。当且仅当正好只有一个函数并且没有 WITH ORDINALITY子句时,才能把列定义列表放在 ROWS FROM( ... )结构后面。

    要把ORDINALITY和列定义列表一起使用,你必须使用 ROWS FROM( ... )语法,并且把列定义列表放在 ROWS FROM( ... )里面。

    join types

    • [ INNER ] JOIN

    • LEFT [ OUTER ] JOIN

    • RIGHT [ OUTER ] JOIN

    • FULL [ OUTER ] JOIN

    • CROSS JOIN

    对于INNEROUTER连接类型,必须指定 一个连接条件,即 NATURALON join_condition或者 USING (join_column [, ...]) 之一(只能有一种)。其含义见下文。对于 CROSS JOIN,上述子句不能出现。

    一个JOIN子句联合两个FROM项( 为了方便我们称之为“表”,尽管实际上它们可以是任何类型 的FROM项)。如有必要可以使用圆括号确定嵌套的顺序。 在没有圆括号时,JOIN会从左至右嵌套。在任何情 况下,JOIN的联合比分隔FROM-列表 项的逗号更强。

    CROSS JOININNER JOIN 会产生简单的笛卡尔积,也就是与在FROM的顶层列出两个 表得到的结果相同,但是要用连接条件(如果有)约束该结果。 CROSS JOININNER JOIN ON (TRUE)等效,也就是说条件不会移除任何行。这些连接类型只是一种 记号上的方便,因为没有什么是你用纯粹的FROM和 WHERE能做而它们不能做的。

    LEFT OUTER JOIN返回被限制过的笛卡尔积 中的所有行(即所有通过了其连接条件的组合行),外加左手表中 没有相应的通过了连接条件的右手行的每一行的拷贝。通过在右手 列中插入空值,这种左手行会被扩展为连接表的完整行。注意在决 定哪些行匹配时,只考虑JOIN子句自身的条件。之后 才应用外条件。

    相反,RIGHT OUTER JOIN返回所有连接行,外加每 一个没有匹配上的右手行(在左端用空值扩展)。这只是为了记号 上的方便,因为你可以通过交换左右表把它转换成一个LEFT OUTER JOIN

    FULL OUTER JOIN返回所有连接行,外加每 一个没有匹配上的左手行(在右端用空值扩展),再外加每一个没有 匹配上的右手行(在左端用空值扩展)。

    ON join_condition

    ``join_condition`` 是一个会得到boolean类型值的表达式(类似于一个 WHERE子句),它说明一次连接中哪些行被认为 相匹配。

    USING ( join_column [, ...] )

    形式USING ( a, b, ... )的子句是 ON left_table.a = right_table.a AND left_table.b = right_table.b ...的简写。还有, USING表示每一对相等列中只有一个会被 包括在连接输出中。

    NATURAL

    NATURAL是一个USING列表的速记,该列表中提到两个表中具有匹配名称的所有的列。如果没有公共列名,则NATURAL等效于ON TRUE

    LATERAL

    LATERAL关键词可以放在一个 子-SELECT FROM项前面。这允许该 子-SELECT引用FROM列表中在它之 前的FROM项的列(如果没有LATERAL,每一 个子-SELECT会被独立计算并且因此不能交叉引用 任何其他的FROM项)。

    LATERAL也可以放在一个函数调用 FROM项前面,但是在这种情况下它只是一个噪声 词,因为在任何情况下函数表达式都可以引用在它之前的 FROM项。

    LATERAL项可以出现在FROM列表 顶层,或者一个JOIN中。在后一种情况中,它也可以引 用其作为右手端的JOIN左手端上的任何项。

    当一个FROM项包含LATERAL交叉引用 时,计算会如此进行:对提供被交叉引用列的FROM项的每 一行或者提供那些列的多个FROM项的每一个行集,使用该 行或者行集的那些列值计算LATERAL项。结果行会与 计算得到它们的行进行通常的连接。对来自哪些列的源表的每一行或者行 集都会重复这样的步骤。

    列的源表必须以INNER或者LEFT的方式连接到 LATERAL项,否则就没有用于为 LATERAL项计算每一个行集的良定行集。尽管 X RIGHT JOIN LATERAL ``Y``这样的结构在语法上是合法的, 但实际上不允许用于在``Y``中引用 ``X``

  3. WHERE子句

    可选的WHERE子句的形式

    WHERE condition
    

    其中``condition`` 是任一计算得到布尔类型结果的表达式。任何不满足 这个条件的行都会从输出中被消除。如果用一行的实际值替换其中的 变量引用后,该表达式返回真,则该行符合条件。

  4. GROUP BY子句

    可选的GROUP BY子句的形式

    GROUP BY grouping_element [, ...]
    

    GROUP BY将会把所有被选择的行中共享相同分组表达式 值的那些行压缩成一个行。一个被用在 ``grouping_element``中的 ``expression``可以是输入列名、输出列 (SELECT列表项)的名称或序号或者由输入列 值构成的任意表达式。在出现歧义时,GROUP BY名称 将被解释为输入列名而不是输出列名。

    如果任何GROUPING SETSROLLUP或者 CUBE作为分组元素存在,则GROUP BY子句 整体上定义了数个独立的``分组集``。其效果等效于在子 查询间构建一个UNION ALL,子查询带有分组集作为它们 的GROUP BY子句。

    聚集函数(如果使用)会在组成每一个分组的所有行上进行计算,从而为每 一个分组产生一个单独的值(如果有聚集函数但是没有 GROUP BY子句,则查询会被当成是由所有选中行构成 的一个单一分组)。传递给每一个聚集函数的行集合可以通过在聚集函数调 用附加一个FILTER子句来进一步过滤,详见 聚集表达式 。当存在一个 FILTER子句时,只有那些匹配它的行才会被包括在该聚 集函数的输入中。

    当存在GROUP BY子句或者任何聚集函数时, SELECT列表表达式不能引用非分组列(除非它 出现在聚集函数中或者它函数依赖于分组列),因为这样做会导致返回 非分组列的值时会有多种可能的值。如果分组列是包含非分组列的表的主键( 或者主键的子集),则存在函数依赖。

    记住所有的聚集函数都是在HAVING子句或者 SELECT列表中的任何“标量”表达式之前被计算。 这意味着一个CASE表达式不能被用来跳过一个聚集表达式的 计算,见 表达式计算规则 。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHAREFOR KEY SHARE不能和 GROUP BY一起指定。

  5. HAVING子句

    可选的HAVING子句的形式

    HAVING condition
    

    其中``condition``与 WHERE子句中指定的条件相同。

    HAVING消除不满足该条件的分组行。 HAVINGWHERE不同: WHERE会在应用GROUP BY之前过滤个体行,而HAVING过滤由 GROUP BY创建的分组行。 ``condition``中引用 的每一个列必须无歧义地引用一个分组列(除非该引用出现在一个聚集 函数中或者该非分组列函数依赖于分组列。

    即使没有GROUP BY子句,HAVING 的存在也会把一个查询转变成一个分组查询。这和查询中包含聚集函数但没有 GROUP BY子句时的情况相同。所有被选择的行都被认为是一个 单一分组,并且SELECT列表和 HAVING子句只能引用聚集函数中的表列。如果该 HAVING条件为真,这样一个查询将会发出一个单一行; 否则不返回行。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHAREFOR KEY SHARE不能与 HAVING一起指定。

  6. WINDOW子句

    可选的WINDOW子句的形式

    WINDOW window_name AS ( window_definition ) [, ...]
    

    其中``window_name`` 是一个可以从OVER子句或者后续窗口定义中引用的名称。 ``window_definition``

    [ existing_window_name ]
    [ PARTITION BY expression [, ...] ]
    [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
    [ frame_clause ]
    

    如果指定了一个``existing_window_name``, 它必须引用WINDOW列表中一个更早出现的项。新窗口将从 该项中复制它的划分子句以及排序子句(如果有)。在这种情况下,新窗口 不能指定它自己的PARTITION BY子句,并且它只能在被复制 窗口没有ORDER BY的情况下指定该子句。新窗口总是使用它 自己的帧子句,被复制的窗口不必指定一个帧子句。

    PARTITION BY列表元素的解释以 GROUP BY 元素的方式 进行,不过它们总是简单表达式并且绝不能是输出列的名称或编号。另一个区 别是这些表达式可以包含聚集函数调用,而这在常规GROUP BY 子句中是不被允许的。它们被允许的原因是窗口是出现在分组和聚集之后的。

    类似地,ORDER BY列表元素的解释也以 ORDER BY 元素的方式进行, 不过该表达式总是被当做简单表达式并且绝不会是输出列的名称或编号。

    可选的``frame_clause``为依赖帧的窗口函数 定义窗口帧(并非所有窗口函数都依赖于帧)。窗口帧是查询中 每一样(称为当前行)的相关行的集合。 ``frame_clause``可以是

    { RANGE | ROWS | GROUPS } frame_start [ frame_exclusion ]
    { RANGE | ROWS | GROUPS } BETWEEN frame_start AND frame_end [ frame_exclusion ]
    

    之一,其中``frame_start````frame_end``可以是

    UNBOUNDED PRECEDING
    offset PRECEDING
    CURRENT ROW
    offset FOLLOWING
    UNBOUNDED FOLLOWING
    

    之一,并且``frame_exclusion``可以是

    EXCLUDE CURRENT ROW
    EXCLUDE GROUP
    EXCLUDE TIES
    EXCLUDE NO OTHERS
    

    之一。如果省略``frame_end``,它会被默认为CURRENT ROW。限制是: ``frame_start``不能是UNBOUNDED FOLLOWING, ``frame_end``不能是UNBOUNDED PRECEDING, 并且``frame_end``的选择在上面of ``frame_start``以及``frame_end`` 选项的列表中不能早于 ``frame_start``的选择 — 例如 RANGE BETWEEN CURRENT ROW AND offset PRECEDING是不被允许的。

    默认的帧选项是RANGE UNBOUNDED PRECEDING,它和 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW相同。它把帧设置为从分区开始直到当前行的最后一个平级行(被该窗口的ORDER BY子句认为等价于当前行的行,如果没有ORDER BY则所有的行都是平级的)。通常, UNBOUNDED PRECEDING表示从分区第一行开始的帧,类似地 UNBOUNDED FOLLOWING表示以分区最后一行结束的帧,不论是处于RANGEROWS或者GROUPS模式中。在ROWS模式中, CURRENT ROW表示以当前行开始或者结束的帧。而在 RANGE或者GROUPS模式中它表示当前行在ORDER BY排序中的第一个 或者最后一个平级行开始或者结束的帧。 ``offset`` PRECEDING``offset`` FOLLOWING选项的含义会随着帧模式而变化。在ROWS模式中,``offset``是一个整数,表示帧开始或者结束于当前行之前或者之后的那么多行处。在GROUPS模式中,``offset``是一个整数,表示真开始或者结束于当前行的平级组之前或者之后那么多个平级组处,其中平级组是一组根据窗口的ORDER BY子句等效的行。在RANGE模式中,``offset``选项的使用要求在窗口定义中正好有一个ORDER BY列。那么该帧包含的行的排序列值不超过``offset``且小于(对于PRECEDING)或者大于(对于FOLLOWING)当前行的排序列值。在这些情况中,``offset``表达式的数据类型取决于排序列的数据类型。对于数字排序列,它通常与排序列是相同类型,但对于datetime类型的排序列它是interval。在所有这些情况中,``offset``的值必须是非空和非负。此外,虽然``offset``并非必须是简单常量,但它不能包含变量、聚集函数或者窗口函数。

    ``frame_exclusion``选项允许从帧中排除当前行周围的行,即便根据帧的起始选项来说它们应该被包含在帧中。EXCLUDE CURRENT ROW把当前行从帧中排除。EXCLUDE GROUP把当前行和它在排序上的平级行从帧中排除。EXCLUDE TIES从帧中排除当前行的任何平级行,但是不排除当前行本身。EXCLUDE NO OTHERS只是明确地指定不排除当前行或其平级行的默认行为。

    注意,如果ORDER BY排序无法把行唯一地排序,则ROWS模式可能产生不可预测的结果。RANGE以及GROUPS模式的目的是确保在ORDER BY顺序中平等的行被同样对待:一个给定平级组中的所有行将在一个帧中或者被从帧中排除。

    WINDOW子句的目的是指定出现在查询的 SELECT列表 或 ORDER BY 中的 窗口函数的行为。这些函数可以在它们的 OVER子句中用名称引用WINDOW 子句项。不过,WINDOW子句项不是必须被引用。 如果在查询中没有用到它,它会被简单地忽略。可以使用根本没有任何 WINDOW子句的窗口函数,因为窗口函数调用可 以直接在其OVER子句中指定它的窗口定义。不过,当多 个窗口函数都需要相同的窗口定义时, WINDOW子句能够减少输入。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHAREFOR KEY SHARE不能和 WINDOW一起被指定。

    窗口函数的详细描述在 高级特性 窗口函数 、 窗口函数调用`以及 :ref:`窗口函数处理 中。

  7. SELECT列表

    SELECT列表(位于关键词 SELECTFROM之间)指定构成 SELECT语句输出行的表达式。这些表达式 可以(并且通常确实会)引用FROM子句中计算得到的列。

    正如在表中一样,SELECT的每一个输出列都有一个名称。 在一个简单的SELECT中,这个名称只是被用来标记要显 示的列,但是当SELECT是一个大型查询的一个子查询时,大型查询 会把该名称看做子查询产生的虚表的列名。要指定用于输出列的名称,在该列的表达式 后面写上 AS ``output_name``( 你可以省略AS,但只能在期望的输出名称不匹配任何 KingbaseES关键词(见 SQL关键词 )时省略。为了避免和未来增加的关键词冲突, 推荐总是写上AS或者用双引号引用输出名称)。如果你不指定列名, KingbaseES会自动选择一个名称。如果列的表达式 是一个简单的列引用,那么被选择的名称就和该列的名称相同。在使用函数或者类型名称 的更复杂的情况中,系统可能会生成诸如 ?column?之类的名称。

    一个输出列的名称可以被用来在ORDER BY以及 GROUP BY子句中引用该列的值,但是不能用于 WHEREHAVING子句(在其中 必须写出表达式)。

    可以在输出列表中写*来取代表达式,它是被选中 行的所有列的一种简写方式。还可以写 table_name.*,它 是只来自那个表的所有列的简写形式。在这些情况中无法用 AS指定新的名称,输出行的名称将和表列的名称相同。

    根据 SQL 标准,输出列表中的表达式应该在应用DISTINCTORDER BY或者LIMIT之前计算。在使用DISTINCT时显然必须这样做,否则就无法搞清到底在区分什么值。不过,在很多情况下如果先计算ORDER BYLIMIT再计算输出表达式会很方便,特别是如果输出列表中包含任何 volatile 函数或者代价昂贵的函数时尤其如此。通过这种行为,函数计算的顺序更加直观并且对于从未出现在输出中的行将不会进行计算。只要输出表达式没有被DISTINCTORDER BY或者GROUP BY引用,KingbaseES实际将在排序和限制行数之后计算输出表达式(作为一个反例,SELECT f(x) FROM tab ORDER BY 1显然必须在排序之前计算f(x))。包含有集合返回函数的输出表达式实际是在排序之后和限制行数之前被计算,这样LIMIT才能切断来自集合返回函数的输出。

    注意

    V8.2 版本之前的KingbaseES不对执行输出表达式、排序、限制行数的时间顺序做任何保证,那将取决于被选中的查询计划的形式。

  8. DISTINCT子句

    如果指定了SELECT DISTINCT,所有重复的行会被从结果 集中移除(为每一组重复的行保留一行)。SELECT ALL则 指定相反的行为:所有行都会被保留,这也是默认情况。

    SELECT DISTINCT ON ( expression [, ...] ) 只保留在给定表达式上计算相等的行集合中的第一行。 DISTINCT ON表达式使用和 ORDER BY相同的规则(见上文)解释。注意,除非用 ORDER BY来确保所期望的行出现在第一位,每一个集 合的“第一行”是不可预测的。例如:

    SELECT DISTINCT ON (location) location, time, report
        FROM weather_reports
        ORDER BY location, time DESC;
    

    为每个地点检索最近的天气报告。但是如果我们不使用 ORDER BY来强制对每个地点的时间值进行降序排序, 我们为每个地点得到的报告的时间可能是无法预测的。

    DISTINCT ON表达式必须匹配最左边的 ORDER BY表达式。ORDER BY子句通常 将包含额外的表达式,这些额外的表达式用于决定在每一个 DISTINCT ON分组内行的优先级。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHAREFOR KEY SHARE不能和 DISTINCT一起使用。

  9. UNIQUE子句

    如果指定了SELECT UNIQUE,所有重复的行会被从结果 集中移除(为每一组重复的行保留一行)。SELECT ALL则 指定相反的行为:所有行都会被保留,这也是默认情况。

    SELECT UNIQUE ON ( expression [, ...] ) 只保留在给定表达式上计算相等的行集合中的第一行。 UNIQUE ON表达式使用和 ORDER BY相同的规则(见上文)解释。注意,除非用 ORDER BY来确保所期望的行出现在第一位,每一个集 合的“第一行”是不可预测的。例如:

    SELECT UNIQUE ON (location) location, time, report
        FROM weather_reports
        ORDER BY location, time DESC;
    

    为每个地点检索最近的天气报告。但是如果我们不使用 ORDER BY来强制对每个地点的时间值进行降序排序, 我们为每个地点得到的报告的时间可能是无法预测的。

    UNIQUE ON表达式必须匹配最左边的 ORDER BY表达式。ORDER BY子句通常 将包含额外的表达式,这些额外的表达式用于决定在每一个 DISTINCT ON分组内行的优先级。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHAREFOR KEY SHARE不能和 UNIQUE一起使用。

  10. UNION子句

    UNION子句具有下面的形式:

    select_statement UNION [ ALL | DISTINCT ] select_statement
    

    ``select_statement`` 是任何没有ORDER BYLIMIT、 FOR NO KEY UPDATEFOR UPDATE、 FOR SHAREFOR KEY SHARE子句的 SELECT语句(如果子表达式被包围在圆括号内, ORDER BYLIMIT可以被附着到其上。如果没有 圆括号,这些子句将被应用到UNION的结果而不是右手边 的表达式上)。

    UNION操作符计算所涉及的 SELECT语句所返回的行的并集。如果一行 至少出现在两个结果集中的一个内,它就会在并集中。作为 UNION两个操作数的 SELECT语句必须产生相同数量的列并且 对应位置上的列必须具有兼容的数据类型。

    UNION的结果不会包含重复行,除非指定了 ALL选项。ALL会阻止消除重复(因此, UNION ALL通常显著地快于UNION, 尽量使用ALL)。可以写DISTINCT来 显式地指定消除重复行的行为。

    除非用圆括号指定计算顺序, 同一个SELECT语句中的多个 UNION操作符会从左至右计算。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHARE和 FOR KEY SHARE不能用于UNION结果或者 UNION的任何输入。

  11. INTERSECT子句

    INTERSECT子句具有下面的形式:

    select_statement INTERSECT [ ALL | DISTINCT ] select_statement
    

    ``select_statement`` 是任何没有ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATE、 FOR SHARE以及FOR KEY SHARE子句的 SELECT语句。

    INTERSECT操作符计算所涉及的 SELECT语句返回的行的交集。如果 一行同时出现在两个结果集中,它就在交集中。

    INTERSECT的结果不会包含重复行,除非指定了 ALL选项。如果有ALL,一个在左表中有 ``m``次重复并且在右表中有``n`` 次重复的行将会在结果中出现 min(``m``,``n``) 次。 DISTINCT可以写DISTINCT来 显式地指定消除重复行的行为。

    除非用圆括号指定计算顺序, 同一个SELECT语句中的多个 INTERSECT操作符会从左至右计算。 INTERSECT的优先级比 UNION更高。也就是说, A UNION B INTERSECT C将被读成A UNION (B INTERSECT C)

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHARE和 FOR KEY SHARE不能用于INTERSECT结果或者 INTERSECT的任何输入。

  12. EXCEPT子句

    EXCEPT子句具有下面的形式:

    select_statement EXCEPT [ ALL | DISTINCT ] select_statement
    

    ``select_statement`` 是任何没有ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATE、 FOR SHARE以及FOR KEY SHARE子句的 SELECT语句。

    EXCEPT操作符计算位于左 SELECT语句的结果中但不在右 SELECT语句结果中的行集合。

    EXCEPT的结果不会包含重复行,除非指定了 ALL选项。如果有ALL,一个在左表中有 ``m``次重复并且在右表中有 ``n``次重复的行将会在结果集中出现 max(``m``-``n``,0) 次。 DISTINCT可以写DISTINCT来 显式地指定消除重复行的行为。

    除非用圆括号指定计算顺序, 同一个SELECT语句中的多个 EXCEPT操作符会从左至右计算。 EXCEPT的优先级与 UNION相同。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHARE和 FOR KEY SHARE不能用于EXCEPT结果或者 EXCEPT的任何输入。

  13. MINUS子句

    MINUS子句具有下面的形式:

    select_statement MINUS [ ALL | DISTINCT ] select_statement
    

    ``select_statement`` 是任何没有ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATE、 FOR SHARE以及FOR KEY SHARE子句的 SELECT语句。

    MINUS操作符计算位于左 SELECT语句的结果中但不在右 SELECT语句结果中的行集合。

    MINUS的结果不会包含重复行,除非指定了 ALL选项。如果有ALL,一个在左表中有 ``m``次重复并且在右表中有 ``n``次重复的行将会在结果集中出现 max(``m``-``n``,0) 次。 DISTINCT可以写DISTINCT来 显式地指定消除重复行的行为。

    除非用圆括号指定计算顺序, 同一个SELECT语句中的多个 MINUS操作符会从左至右计算。 MINUS的优先级与 UNION相同。

    当前,FOR NO KEY UPDATEFOR UPDATE、 FOR SHARE和 FOR KEY SHARE不能用于MINUS结果或者 MINUS的任何输入。

  14. ORDER BY子句

    可选的ORDER BY子句的形式如下:

    ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]
    

    ORDER BY子句导致结果行被按照指定的表达式排序。 如果两行按照最左边的表达式是相等的,则会根据下一个表达式比较它们, 依次类推。如果按照所有指定的表达式它们都是相等的,则它们被返回的 顺序取决于实现。

    每一个``expression`` 可以是输出列(SELECT列表项)的名称或 者序号,它也可以是由输入列值构成的任意表达式。

    序号指的是输出列的顺序(从左至右)位置。这种特性可以为不具有唯一 名称的列定义一个顺序。这不是绝对必要的,因为总是可以使用 AS子句为输出列赋予一个名称。

    也可以在ORDER BY子句中使用任意表达式,包括没 有出现在SELECT输出列表中的列。因此, 下面的语句是合法的:

    SELECT name FROM distributors ORDER BY code;
    

    这种特性的一个限制是一个应用在UNION、 INTERSECTEXCEPT子句结果上的 ORDER BY只能指定输出列名称或序号,但不能指定表达式。

    如果一个ORDER BY表达式是一个既匹配输出列名称又匹配 输入列名称的简单名称,ORDER BY将把它解读成输出列名 称。这与在同样情况下GROUP BY会做出的选择相反。这种 不一致是为了与 SQL 标准兼容。

    可以为ORDER BY子句中的任何表达式之后增加关键词 ASC(上升)DESC(下降)。如果没有指定, ASC被假定为默认值。或者,可以在USING 子句中指定一个特定的排序操作符名称。一个排序操作符必须是某个 B-树操作符族的小于或者大于成员。ASC通常等价于 USING <DESC通常等价于 USING >(但是一种用户定义数据类型的创建者可以 准确地定义默认排序顺序是什么,并且它可能会对应于其他名称的操作符)。

    如果指定NULLS LAST,空值会排在非空值之后;如果指定 NULLS FIRST,空值会排在非空值之前。如果都没有指定, 在指定或者隐含ASC时的默认行为是NULLS LAST, 而指定或者隐含DESC时的默认行为是 NULLS FIRST(因此,默认行为是空值大于非空值)。 当指定USING时,默认的空值顺序取决于该操作符是否为 小于或者大于操作符。

    注意顺序选项只应用到它们所跟随的表达式上。例如 ORDER BY x, y DESC和 ORDER BY x DESC, y DESC是不同的。

    字符串数据会被根据引用到被排序列上的排序规则排序。根据需要可以通过在 ``expression``中包括一个 COLLATE子句来覆盖,例如 ORDER BY mycolumn COLLATE "en_US"。更多信息请见 排序规则表达式 和 排序规则 。

  15. LIMIT子句

    LIMIT子句由两个独立的子句构成:

    LIMIT { count | ALL }
    OFFSET start
    

    ``count``指定要返回 的最大行数,而``start`` 指定在返回行之前要跳过的行数。在两者都被指定时,在开始计算要返回的 ``count``行之前会跳过 ``start``行。

    如果``count``表达式计算 为 NULL,它会被当成LIMIT ALL,即没有限制。如果 ``start``计算为 NULL,它会被当作OFFSET 0

    SQL:2008 引入了一种不同的语法来达到相同的结果, KingbaseES也支持它:

    OFFSET start { ROW | ROWS }
    FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY
    

    在这种语法中,标准要求``start````count``是一个文本常量、一个参数或者一个变量名。而作为一种 KingbaseES的扩展,还允许其他的表达式,但通常需要被封闭在圆括号中以避免歧义。如果在一个 FETCH子句中省略 ``count``,它的默认值为 1。 ROWROWS以及 FIRSTNEXT是噪声,它们不影响 这些子句的效果。根据标准,如果都存在,OFFSET子句 必须出现在FETCH子句之前。但是 KingbaseES更宽松,它允许两种顺序。

    在使用LIMIT时,用一个ORDER BY子句把 结果行约束到一个唯一顺序是个好办法。否则你讲得到该查询结果行的 一个不可预测的子集 — 你可能要求从第 10 到第 20 行,但是在 什么顺序下的第 10 到第 20 呢?除非指定ORDER BY,你 是不知道顺序的。

    查询规划器在生成一个查询计划时会考虑LIMIT,因此 根据你使用的LIMITOFFSET,你很可能 得到不同的计划(得到不同的行序)。所以,使用不同的 LIMIT/OFFSET值来选择一个查询结果的 不同子集将会给出不一致的结果,除非你 用ORDER BY强制一种可预测的结果顺序。这不是一个 缺陷,它是 SQL 不承诺以任何特定顺序(除非使用 ORDER BY来约束顺序)给出一个查询结果这一事实造 成的必然后果。

    如果没有一个ORDER BY来强制选择一个确定的子集, 重复执行同样的LIMIT查询甚至可能会返回一个表中行 的不同子集。同样,这也不是一种缺陷,再这样一种情况下也无法 保证结果的确定性。

  16. 锁定子句

    FOR UPDATEFOR NO KEY UPDATE、 FOR SHAREFOR KEY SHARE 是锁定子句,它们影响SELECT 把行从表中取得时如何对它们加锁。

    锁定子句的一般形式:

    FOR lock_strength [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED | WAIT seconds ]
    

    其中``lock_strength``可以是

    UPDATE
    NO KEY UPDATE
    SHARE
    KEY SHARE
    

    之一。

    为了防止该操作等待其他事务提交,可使用NOWAIT或者 SKIP LOCKED或者WAIT seconds选项。使用NOWAIT时, 如果选中的行不能被立即锁定,该语句会报告错误而不是等待。使用 SKIP LOCKED时,无法被立即锁定的任何选中行都 会被跳过。跳过已锁定行会提供数据的一个不一致的视图,因此这不适合 于一般目的的工作,但是可以被用来避免多个用户访问一个类似队列的表 时出现锁竞争。使用WAIT seconds时,在被锁定的行变为可用之前, 最多等待seconds秒,如果等待成功则返回结果集,否则超时报错返回。 注意NOWAITSKIP LOCKEDWAIT seconds只适合行级锁 — 所要求的ROW SHARE表级锁仍然会以常规的方式取得。 如果想要不等待的表级锁,可以先使用带NOWAIT的 LOCK 。

    如果在一个锁定子句中提到了特定的表,则只有来自于那些表的 行会被锁定,任何SELECT中用到的 其他表还是被简单地照常读取。一个没有表列表的锁定子句会影响 该语句中用到的所有表。如果一个锁定子句被应用到一个视图或者 子查询,它会影响在该视图或子查询中用到的所有表。不过,这些 子句不适用于主查询引用的WITH查询。如果你希望 在一个WITH查询中发生行锁定,应该在该 WITH查询内指定一个锁定子句。

    如果有必要对不同的表指定不同的锁定行为,可以写多个锁定子句。 如果同一个表在多于一个锁定子句中被提到(或者被隐式的影响到), 那么会按照所指定的最强的锁定行为来处理它。类似地,如果在任何 影响一个表的子句中指定了NOWAIT,就会按照 NOWAIT的行为来处理该表。否则如果 SKIP LOCKED在任何影响该表的子句中被指定, 该表就会被按照SKIP LOCKED来处理。

    如果被返回的行无法清晰地与表中的行保持一致,则不能使用锁定子句。 例如锁定子句不能与聚集一起使用。

    当一个锁定子句出现在一个SELECT查询的顶层时, 被锁定的行正好就是该查询返回的行。在连接查询的情况下,被锁定 的行是那些对返回的连接行有贡献的行。此外,自该查询的快照起满足 查询条件的行将被锁定,如果它们在该快照后被更新并且不再满足 查询条件,它们将不会被返回。如果使用了LIMIT,只要 已经返回的行数满足了限制,锁定就会停止(但注意被 OFFSET跳过的行将被锁定)。类似地,如果在一个游标 的查询中使用锁定子句,只有被该游标实际取出或者跳过的行才将被 锁定。

    当一个锁定子句出现在一个子-SELECT中时,被锁定 行是那些该子查询返回给外层查询的行。这些被锁定的行的数量可能比 从子查询自身的角度看到的要少,因为来自外层查询的条件可能会被用 来优化子查询的执行。例如:

    SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;
    

    将只锁定具有col1 = 5的行(虽然在子查询中并没有写上 该条件)。

    早前的发行无法维持一个被之后的保存点升级的锁。例如,这段代码:

    BEGIN;
    SELECT * FROM mytable WHERE key = 1 FOR UPDATE;
    SAVEPOINT s;
    UPDATE mytable SET ... WHERE key = 1;
    ROLLBACK TO s;
    

    ROLLBACK TO之后将无法维持 FOR UPDATE锁。在 9.3 中已经修复这个问题。

    Caution

    一个运行在READ COMMITTED事务隔离级别并且使用ORDER BY和锁定子句的SELECT命令有可能返回无序的行。 这是因为ORDER BY会被首先应用。该命令对结果排序,但是可能 接着在尝试获得一个或者多个行上的锁时阻塞。一旦SELECT解除 阻塞,某些排序列值可能已经被修改,从而导致那些行变成无序的(尽管它们根 据原始列值是有序的)。根据需要,可以通过在子查询中放置 FOR UPDATE/SHARE来解决之一问题,例如

    SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;
    

    注意这将导致锁定mytable的所有行,而顶层的 FOR UPDATE只会锁定实际被返回的行。这可能会导致显著的 性能差异,特别是把ORDER BYLIMIT或者其他 限制组合使用时。因此只有在并发更新排序列并且要求严格的排序结果时才推 荐使用这种技术。

    REPEATABLE READ或者SERIALIZABLE 事务隔离级别上这可能导致一个序列化失败(SQLSTATE 是'40001'),因此在这些隔离级别下不可能收到无序行。

  17. TABLE命令

    命令

    TABLE name
    

    等价于

    SELECT * FROM name
    

    它可以被用作一个顶层命令,或者用在复杂查询中以节省空间。只有 WITH、 UNIONINTERSECTEXCEPTMINUSORDER BYLIMITOFFSET、 FETCH以及FOR锁定子句可以用于 TABLE。不能使用WHERE子句和任何形式 的聚集。

示例

把表films与表 distributors连接:

SELECT f.title, f.did, d.name, f.date_prod, f.kind
    FROM distributors d, films f
    WHERE f.did = d.did

       title       | did |     name     | date_prod  |   kind
-------------------+-----+--------------+------------+----------
 The Third Man     | 101 | British Lion | 1949-12-23 | Drama
 The African Queen | 101 | British Lion | 1951-08-11 | Romantic
 ...

要对所有电影的len列求和并且用 kind对结果分组:

SELECT kind, sum(len) AS total FROM films GROUP BY kind;

   kind   | total
----------+-------
 Action   | 07:34
 Comedy   | 02:58
 Drama    | 14:28
 Musical  | 06:42
 Romantic | 04:38

要对所有电影的len列求和、对结果按照``kind``分组并且显示总长小于 5 小时的分组:

SELECT kind, sum(len) AS total
    FROM films
    GROUP BY kind
    HAVING sum(len) < interval '5 hours';

   kind   | total
----------+-------
 Comedy   | 02:58
 Romantic | 04:38

下面两个例子都是根据第二列(name)的内容来排序结果:

SELECT * FROM distributors ORDER BY name;
SELECT * FROM distributors ORDER BY 2;

 did |       name
-----+------------------
 109 | 20th Century Fox
 110 | Bavaria Atelier
 101 | British Lion
 107 | Columbia
 102 | Jean Luc Godard
 113 | Luso films
 104 | Mosfilm
 103 | Paramount
 106 | Toho
 105 | United Artists
 111 | Walt Disney
 112 | Warner Bros.
 108 | Westward

接下来的例子展示了如何得到表distributors和 actors的并集,把结果限制为那些在每个表中以 字母 W 开始的行。只想要可区分的行,因此省略了关键词 ALL

distributors:               actors:
 did |     name              id |     name
-----+--------------        ----+----------------
 108 | Westward               1 | Woody Allen
 111 | Walt Disney            2 | Warren Beatty
 112 | Warner Bros.           3 | Walter Matthau
 ...                         ...

SELECT distributors.name
    FROM distributors
    WHERE distributors.name LIKE 'W%'
UNION
SELECT actors.name
    FROM actors
    WHERE actors.name LIKE 'W%';

      name
----------------
 Walt Disney
 Walter Matthau
 Warner Bros.
 Warren Beatty
 Westward
 Woody Allen

这个例子展示了如何在FROM子句中使用函数, 分别使用和不使用列定义列表:

CREATE FUNCTION distributors(int) RETURNS SETOF distributors AS $$
    SELECT * FROM distributors WHERE did = $1;
$$ LANGUAGE SQL;

SELECT * FROM distributors(111);
 did |    name
-----+-------------
 111 | Walt Disney

CREATE FUNCTION distributors_2(int) RETURNS SETOF record AS $$
    SELECT * FROM distributors WHERE did = $1;
$$ LANGUAGE SQL;

SELECT * FROM distributors_2(111) AS (f1 int, f2 text);
 f1  |     f2
-----+-------------
 111 | Walt Disney

这里是带有增加的序数列的函数的例子:

SELECT * FROM unnest(ARRAY['a','b','c','d','e','f']) WITH ORDINALITY;
 unnest | ordinality
--------+----------
 a      |        1
 b      |        2
 c      |        3
 d      |        4
 e      |        5
 f      |        6
(6 rows)

这个例子展示了如何使用简单的WITH子句:

WITH t AS (
    SELECT random() as x FROM generate_series(1, 3)
  )
SELECT * FROM t
UNION ALL
SELECT * FROM t

         x
--------------------
  0.534150459803641
  0.520092216785997
 0.0735620250925422
  0.534150459803641
  0.520092216785997
 0.0735620250925422

注意该WITH查询只被计算一次,这样我们得到的两个 集合具有相同的三个随机值。

这个例子使用WITH RECURSIVE从一个只显示 直接下属的表中寻找雇员 Mary 的所有下属(直接的或者间接的)以及他们的间接层数:

WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS (
    SELECT 1, employee_name, manager_name
    FROM employee
    WHERE manager_name = 'Mary'
  UNION ALL
    SELECT er.distance + 1, e.employee_name, e.manager_name
    FROM employee_recursive er, employee e
    WHERE er.employee_name = e.manager_name
  )
SELECT distance, employee_name FROM employee_recursive;

注意这种递归查询的典型形式:一个初始条件,后面跟着 UNION,然后是查询的递归部分。要确保 查询的递归部分最终将不返回任何行,否则该查询将无限循环( WITH查询 )。

这个例子使用LATERALmanufacturers 表的每一行应用一个集合返回函数get_product_names()

SELECT m.name AS mname, pname
FROM manufacturers m, LATERAL get_product_names(m.id) pname;

当前没有任何产品的制造商不会出现在结果中,因为这是一个内连接。 如果我们希望把这类制造商的名称包括在结果中,我们可以:

SELECT m.name AS mname, pname
FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true;

兼容性

当然,SELECT语句是兼容 SQL 标准的。但是也有一些扩展和缺失的特性。

  1. 省略的FROM子句

    KingbaseES允许我们省略 FROM子句。一种简单的使用是计算简单表达式 的结果:

    SELECT 2+2;
    
     ?column?
    ----------
            4
    

    某些其他SQL数据库需要引入一个假的 单行表放在该SELECT的 FROM子句中才能做到这一点。

    注意,如果没有指定一个FROM子句,该查询 就不能引用任何数据库表。例如,下面的查询是非法的:

    SELECT distributors.* WHERE distributors.name = 'Westward';
    

    KingbaseES在 8.1 之前的发行 会接受这种形式的查询,并且为该查询引用的每一个表在 FROM子句中隐式增加一个项。现在已经不再允许 这样做。

  2. 空SELECT列表

    SELECT之后的输出表达式列表可以为空, 这会产生一个零列的结果表。对 SQL 标准来说这不是合法的 语法。KingbaseES允许 它是为了与允许零列表保持一致。不过在使用 DISTINCT时不允许空列表。

  3. 省略AS关键词

    在 SQL 标准中,只要新列名是一个合法的列名(就是说与任何保留关键词不同), 就可以省略输出列名之前的可选关键词AS。 KingbaseES要稍微严格些:只要新列名匹配 任何关键词(保留或者非保留)就需要AS。推荐的习惯是使用 AS或者带双引号的输出列名来防止与未来增加的关键词可能的冲突。

    FROM项中,标准和 KingbaseES都允许省略非保留 关键词别名之前的AS。但是由于语法的歧义,这无法 用于输出列名。

  4. ONLY和继承

    在书写ONLY时,SQL 标准要求在表名周围加上圆括号,例如 SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...。KingbaseES 认为这些圆括号是可选的。

    KingbaseES允许写一个拖尾的*来 显式指定包括子表的非-ONLY行为。而标准则不允许 这样。

    (这些点同等地适用于所有支持ONLY选项的 SQL 命令)。

  5. TABLESAMPLE子句限制

    当前只在常规表和物化视图上接受TABLESAMPLE子句。 根据 SQL 标准,应该可以把它应用于任何FROM项。

  6. FROM中的函数调用

    KingbaseES允许一个函数调用被直接写作 FROM列表的一个成员。在 SQL 标准中,有必要把这样一个函数 调用包裹在一个子-SELECT中。也就是说,语法 FROM func(...) ``alias`` 近似等价于 FROM LATERAL (SELECT func(...)) ``alias``。 注意该LATERAL被认为是隐式的,这是因为标准对于 FROM中的一个UNNEST()项要求 LATERAL语义。KingbaseES会把 UNNEST()和其他集合返回函数同样对待。

  7. GROUP BY和ORDER BY可用的名字空间

    在 SQL-92 标准中,一个ORDER BY子句只能使用输出 列名或者序号,而一个GROUP BY子句只能使用基于输 入列名的表达式。KingbaseES扩展了 这两种子句以允许它们使用其他的选择(但如果有歧义时还是使用标准的 解释)。KingbaseES也允许两种子句 指定任意表达式。注意出现在一个表达式中的名称将总是被当做输入列名而 不是输出列名。

    SQL:1999 及其后的标准使用了一种略微不同的定义,它并不完全向后兼容 SQL-92。不过,在大部分的情况下, KingbaseES会以与 SQL:1999 相同的 方式解释ORDER BYGROUP BY表达式。

  8. 函数依赖

    只有当一个表的主键被包括在GROUP BY列表中时, KingbaseES才识别函数依赖(允许 从GROUP BY中省略列)。SQL 标准指定了应该要识别 的额外情况。

  9. LIMIT和OFFSET

    LIMITOFFSET子句是 KingbaseES-特有的语法,在 MySQL也被使用。SQL:2008 标准已经 引入了具有相同功能的子句OFFSET ... FETCH {FIRST|NEXT} ...(如上文 :ref`LIMIT子句` 中所示)。这种语法 也被IBM DB2使用( Oracle编写的应用常常使用自动生成的 rownum列来实现这些子句的效果,这在 KingbaseES 中是没有的)。

  10. FOR NO KEY UPDATE、FOR UPDATE 、FOR SHARE 、FOR KEY SHARE

    尽管 SQL 标准中出现了FOR UPDATE,但标准只允许它作为 DECLARE CURSOR的一个选项。 KingbaseES允许它出现在任何 SELECT查询以及子-SELECT中,但这是 一种扩展。FOR NO KEY UPDATEFOR SHARE 以及FOR KEY SHARE变体以及NOWAIT 和SKIP LOCKED选项没有在标准中出现。

  11. WITH中的数据修改语句

    KingbaseES允许把INSERT、 UPDATE以及DELETE用作WITH 查询。这在 SQL 标准中是找不到的。

  12. 非标准子句

    DISTINCT ON ( ... )是 SQL 标准的扩展。

    ROWS FROM( ... )是 SQL 标准的扩展。

    WITHMATERIALIZEDNOT MATERIALIZED选项是SQL标准的扩展。

    该部分不是必有的,如有需做其他说明的内容放在这里。

20.19. SELECT INTO

用途

SELECT INTO — 从一个查询的结果定义一个新表

SELECT INTO创建一个新表并且用一个查询计算得到的数据填充它。这些数据不会像普通的``SELECT``那样被返回给客户端。新表的列具有和SELECT的输出列相关的名称和数据类型。

前置条件

语法

[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
    * | expression [ [ AS ] output_name ] [, ...]
    INTO [ TEMPORARY | TEMP | UNLOGGED ] [ TABLE ] new_table
    [ FROM from_item [, ...] ]
    [ WHERE condition ]
    [ GROUP BY expression [, ...] ]
    [ HAVING condition [, ...] ]
    [ WINDOW window_name AS ( window_definition ) [, ...] ]
    [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
    [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST
    } ] [, ...] ]
    [ LIMIT { count | ALL } ]
    [ OFFSET start [ ROW | ROWS ] ]
    [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
    [ FOR { UPDATE | SHARE } [ OF table_name [, ...] ] [ NOWAIT ] [...] ]

语义

TEMPORARY or TEMP

如果被指定,该表被创建为一个临时表。详见 CREATE TABLE 。

UNLOGGED

如果被指定,该表被创建为一个不做日志的表。详见 CREATE TABLE 。

new_table

要创建的表的名字(可以是模式限定的)。

所有其他参数在 SELECT 中有详细描述。

示例

创建一个只由来自films的最近项构成的新表films_recent

SELECT * INTO films_recent FROM films WHERE date_prod >= '2002-01-01';

兼容性

SQL 标准使用SELECT INTO表示把值选择到一个宿主程序的标量变量中,而不是创建一个新表。这实际上就是ESQL(见 ESQL C中的嵌入式SQL )和PL/SQL(见 PLSQL SQL过程语言 )中的用法。

KingbaseES使用 SELECT INTO的来表示表创建是有历史原因的。最好在新代码中使用CREATE TABLE AS

其他

SELECT INTO创建一个新表并且用一个查询计算得到的数据填充它。这些数据不会像普通的``SELECT``那样被返回给客户端。新表的列具有和SELECT的输出列相关的名称和数据类型。

20.20. SET

用途

SET — 更改一个运行时参数

SET命令更改运行时配置参数。很多 服务器配置参数参考手册 中列出的参数可以用``SET``即时更改。

SET只影响当前会话所使用的值。

前置条件

有些参数需要超级用户特权才能更改,并且还有一些在服务器或者会话启动之后不能被更改

语法

SET [ SESSION | LOCAL ] configuration_parameter { TO | = } { value | 'value' | DEFAULT }
{ ALTER } SET [ SESSION | LOCAL ] TIME ZONE { TIME_ZONE | time_zone | timezone | LOCAL | DEFAULT }

语义

SESSION

指定该命令对当前会话有效(这是默认值)。

LOCAL

指定该命令只对当前事务有效。在COMMIT或者 ROLLBACK之后,会话级别的设置会再次生效。 在事务块外部发出这个参数会发出一个警告并且不会有效果。

configuration_parameter

一个可设置运行时参数的名称。可用的参数被记录在 服务器配置参数参考手册 和下文中。

value

参数的新值。根据特定的参数,值可以被指定为字符串常量、标识符、 数字或者以上构成的逗号分隔列表。写DEFAULT 可以指定把该参数重置成它的默认值(也就是说在当前会话中还没有 执行SET命令时它具有的值)。

除了在 服务器配置参数参考手册 中记录的配置参数,还有一些参数只能用SET命令设置 或者具有特殊的语法:

SCHEMA

SET SCHEMA 'value'是 SET search_path TO value的一个别名。 使用这种语法只能指定一个模式。

NAMES

SET NAMES value是 SET client_encoding TO value的一个别名。

SEED

为随机数生成器(函数random)设置 一个内部种子。允许的值是 -1 和 1 之间的浮点数,它会被乘上 231-1。

也可以通过调用函数setseed来设置种子:

SELECT setseed(value);

TIME ZONE

SET TIME ZONE value是 SET timezone TO value的一个别 名。语法SET TIME ZONE允许用于时区指定的特 殊语法。这里是合法值的例子:

'PST8PDT'

加州伯克利的时区。

'Europe/Rome'

意大利的时区。

-7

UTC 以西 7 小时的时区(等效于 PDT)。正值则是 UTC 以东。

INTERVAL '-08:00' HOUR TO MINUTE

UTC 以西 8 小时的时区(等效于 PST)。

LOCAL DEFAULT

把时区设置为你的本地时区(也就是说服务器的timezone默认值)。

以数字或区间给出的时区设置在内部被翻译成 POSIX 时区语法。 例如,在SET TIME ZONE -7之后, SHOW TIME ZONE将会报告 <-07>+07

示例

设置模式搜索路径:

SET search_path TO my_schema, public;

把日期风格设置为传统 KINGBASE的 “日在月之前”的输入习惯:

SET datestyle TO kingbase, dmy;

设置时区为加州伯克利:

SET TIME ZONE 'PST8PDT';

设置时区为意大利:

SET TIME ZONE 'Europe/Rome';

兼容性

SET TIME ZONE扩展了 SQL 标准定义的语法。标准只允许数字的时区偏移量而 KingbaseES允许更灵活的时区说明。所有其他SET特性都是 KingbaseES扩展。

其他

如果在一个事务内发出SET``(或者等效的\ ``SET SESSION)而该事务后来中止,在该事务被回滚时SET命令的效果会消失。一旦所在的事务被提交,这些效果将会持续到会话结束(除非被另一个SET所覆盖)。

SET LOCAL的效果只持续到当前事务结束,不管事务是否被提交。一种特殊情况是在一个事务内 SET后面跟着``SET LOCAL``: SET LOCAL值将会在该事务结束前一直可见,但是之后(如果该事务被提交)SET值将会生效。SET``SET LOCAL``的效果也会因为回滚到早于它们的保存点而消失。

如果在一个函数内使用SET LOCAL并且该函数还有对同一变量的SET选项(见 CREATE FUNCTION语句 ),在函数退出时``SET LOCAL``命令的效果会消失。也就是说,该函数被调用时的值会被恢复。这允许用``SET LOCAL``在函数内动态地或者重复地更改一个参数,同时仍然能便利地使用SET选项来保存以及恢复调用者的值。不过,一个常规的SET命令会覆盖它所在的任何函数的SET选项,除非回滚,它的效果将一直保持。

注意

在KingbaseES V7版本中,一个SET LOCAL的效果会因为释放较早的保存点或者成功地从一个PL/SQL异常块中退出而被取消。这种行为已经被更改,因为它被认为不直观。

20.21. SET CONSTRAINTS

用途

SET CONSTRAINTS设置当前事务内约束检查 的行为。IMMEDIATE约束在每个语句结束时被检查。 DEFERRED约束直到事务提交时才被检查。每个约束都有 自己的IMMEDIATEDEFERRED模式。

在创建时,一个约束会被给定三种特性之一: DEFERRABLE INITIALLY DEFERRED、 DEFERRABLE INITIALLY IMMEDIATE或者 NOT DEFERRABLE。第三类总是 IMMEDIATE并且不会受到 SET CONSTRAINTS命令的影响。前两类在每个 事务开始时都处于指定的模式,但是它们的行为可以在一个事务内用 SET CONSTRAINTS更改。

带有一个约束名称列表的SET CONSTRAINTS 只更改那些约束(都必须是可延迟的)的模式。每一个约束名称都可以是 模式限定的。如果没有指定模式名称,则当前的模式搜索路径将被用来寻找 第一个匹配的名称。SET CONSTRAINTS ALL 更改所有可延迟约束的模式。

SET CONSTRAINTS把一个约束的模式从 DEFERRED改成IMMEDIATE时, 新模式会有追溯效果:任何还没有解决的数据修改(本来会在事务结束时 被检查)会转而在SET CONSTRAINTS命令 的执行期间被检查。如果任何这种约束被违背, SET CONSTRAINTS将会失败(并且不会改 变该约束模式)。这样,SET CONSTRAINTS可以被用来在一个事务中的特定点强制进 行约束检查。

当前,只有UNIQUEPRIMARY KEY、 REFERENCES(外键)以及EXCLUDE 约束受到这个设置的影响。 NOT NULL以及CHECK约束总是在一行 被插入或修改时立即检查(不是在语句结束时)。 没有被声明为DEFERRABLE的唯一和排除约束也会被 立刻检查。

被声明为“约束触发器”的触发器的引发也受到这个设置 的控制 — 它们会在相关约束被检查的同时被引发。

前置条件

语法

SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE }

语义

name

指定约束名称

ALL

指定所有约束

示例

设置约束模式为结束时检查

SET CONSTRAINTS my_constraint IMMEDIATE;

兼容性

这个命令符合 SQL 标准中定义的行为,但有一点限制:在 KingbaseES中,它不会应用在 NOT NULLCHECK约束上。还有, KingbaseES会立刻检查非可延迟的 唯一约束,而不是按照标准建议的在语句结束时检查。

其他

因为KingbaseES并不要求约束名称在模式内 唯一(但是在表内要求唯一),可能有多于一个约束匹配指定的约束名称。在这种 情况下SET CONSTRAINTS将会在所有的匹配上操作。 对于一个非模式限定的名称,一旦在搜索路径中的某个模式中发现一个或者多个匹 配,路径中后面的模式将不会被搜索。

这个命令只修改当前事务内约束的行为。在事务块外部发出这个命令会产生一个 警告并且也不会有任何效果。

20.22. SET ROLE

用途

这个命令把当前 SQL 会话的当前用户标识符设置为 ``role_name``。 角色名可以写成一个标识符或者一个字符串。在 SET ROLE之后,对 SQL 命令的权限检查时就 好像该角色就是原先登录的角色一样。

当前会话用户必须是指定的 角色``role_name`` 的一个成员(如果会话用户是一个超级用户,则可以选择任何角色)。

SESSIONLOCAL修饰符发挥的作用和 常规的 SET 命令一样。

NONERESET形式把当前用户标识符 重置为当前会话用户标识符。这些形式可以由任何用户执行。

前置条件

你必须拥有该角色以使用 SET ROLE 。

语法

SET [ SESSION | LOCAL ] ROLE role_name
SET [ SESSION | LOCAL ] ROLE NONE
RESET ROLE

语义

role_name

要设定的角色名

NONE

重置为当前会话用户标识符

示例

SELECT SESSION_USER, CURRENT_USER;

 session_user | current_user
--------------+--------------
 peter        | peter

SET ROLE 'paul';

SELECT SESSION_USER, CURRENT_USER;

 session_user | current_user
--------------+--------------
 peter        | paul

兼容性

KingbaseES允许标识符 语法("rolename"),而 SQL 标准要求 角色名被写成字符串。SQL 不允许在事务中使用这个命令,而 KingbaseES并不做此限 制,因为并没有原因需要这样做。和RESET语法 一样,SESSION和 LOCAL修饰符是一种 KingbaseES扩展。

其他

使用这个命令可以增加特权或者限制特权。如果会话用户角色具有 INHERITS属性,则它会自动具有它能 SET ROLE到的所有角色的全部特权。在这种情况下 SET ROLE实际会删除所有直接分配给会话用户的特 权以及分配给会话用户作为其成员的其他角色的特权,只留下所提及 角色可用的特权。换句话说,如果会话用户没有 NOINHERITS属性,SET ROLE会删除 直接分配给会话用户的特权而得到所提及角色可用的特权。

特别地,当一个超级用户选择SET ROLE到一个非 超级用户角色时,它们会丢失其超级用户特权。

SET ROLE的效果堪比 SET SESSION AUTHORIZATION ,但是涉及的特权检查 完全不同。还有,SET SESSION AUTHORIZATION决定 后来的SET ROLE命令可以使用哪些角色, 不过用 SET ROLE更改角色并不会改变后续 SET ROLE能够使用的角色集。

SET ROLE不会处理角色的 ALTER ROLE 设置指定的会话变量。这只在登录期间发生。

SET ROLE不能在一个 SECURITY DEFINER函数中使用。

20.23. SET SESSION AUTHORIZATION

用途

SET SESSION AUTHORIZATION — 设置当前会话的会话用户标识符和当前用户标识符

会话用户标识符初始时被设置为客户端提供的(可能已认证的)用户名。当前用户标识符通常等于会话用户标识符,但是可能在``SECURITY DEFINER``函数和类似机制的环境中临时更改。也可以用 SET ROLE 更改它。当前用户标识符与权限检查相关。

会话用户标识符只能在初始会话用户已认证用户具有超级用户特权时被更改。否则,只有该命令指定已认证用户名时才会被接受。

SESSIONLOCAL修饰符发挥的作用和常规 SET 命令一样。

DEFAULTRESET形式把会话用户标识符和当前用户标识符重置为初始的已认证用户名。这些形式可以由任何用户执行。

前置条件

会话用户标识符只能在初始会话用户 已认证用户具有超级用户特权时被更改。

语法

SET [ SESSION | LOCAL ] SESSION AUTHORIZATION user_name
SET [ SESSION | LOCAL ] SESSION AUTHORIZATION DEFAULT
RESET SESSION AUTHORIZATION

语义

user_name

这个命令把当前 SQL 会话的会话用户标识符和当前用户标识符设置为``user_name``。用户名可以被写成一个标识符或者一个字符串。例如,可以使用这个命令临时成为一个无特权用户并且稍后切换回来成为一个超级用户。

SESSION

指定该命令对当前会话有效(这是默认值)。

LOCAL

指定该命令只对当前事务有效。在COMMIT或者ROLLBACK之后,会话级别的设置会再次生效。在事务块外部发出这个参数会发出一个警告并且不会有效果。

DEFAULTRESET

当前用户标识符重置为初始的已认证用户名。这些形式可以由任何用户执行。

示例

SELECT SESSION_USER, CURRENT_USER;

 session_user | current_user
--------------+--------------
 peter        | peter

SET SESSION AUTHORIZATION 'paul';

SELECT SESSION_USER, CURRENT_USER;

 session_user | current_user
--------------+--------------
 paul         | paul

兼容性

SQL 标准允许一些其他表达式出现在文本*``user_name``*的位置上,但是实际上这些选项并不重要。KingbaseES允许标 识符语法("username"),而SQL 标准不允许。 SQL 不允许在事务中使用这个命令,而KingbaseES并不做此限制,因为并没有原因需要这样做。和RESET语法一样,SESSION和 LOCAL修饰符是一种 KingbaseES扩展。

标准把执行这个命令所需的特权留给实现定义。

其他

SET SESSION AUTHORIZATION不能在一个``SECURITY DEFINER``函数中使用。

20.24. SET TRANSACTION

用途

SET TRANSACTION命令设置当前 会话的特性。SET SESSION CHARACTERISTICS设置一个会话后续事务的默认 事务特性。在个体事务中可以用 SET TRANSACTION覆盖这些默认值。

前置条件

语法

SET TRANSACTION transaction_mode [, ...]
SET TRANSACTION SNAPSHOT snapshot_id
SET SESSION CHARACTERISTICS AS TRANSACTION transaction_mode [, ...]

其中 transaction_mode 是下列之一:

    ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
    READ WRITE | READ ONLY
    [ NOT ] DEFERRABLE

语义

可用的事务特性是事务隔离级别、事务访问模式(读/写或只读)以及 可延迟模式。此外,可以选择一个快照,不过只能用于当前事务而不能 作为会话默认值。

一个事务的隔离级别决定当其他事务并行运行时该事务能看见什么数据:

READ COMMITTED

一个语句只能看到在它开始前提交的行。这是默认值。

REPEATABLE READ

当前事务的所有语句只能看到这个事务中执行的第一个查询或者 数据修改语句之前提交的行。

SERIALIZABLE

当前事务的所有语句只能看到这个事务中执行的第一个查询或者 数据修改语句之前提交的行。如果并发的可序列化事务间的读写 模式可能导致一种那些事务串行(一次一个)执行时不可能出现 的情况,其中之一将会被回滚并且得到一个 serialization_failure错误。

SQL 标准定义了一种额外的级别:READ UNCOMMITTED。在 KingbaseES中READ UNCOMMITTED被视作 READ COMMITTED

一个事务执行了第一个查询或者数据修改语句( SELECT、 INSERTDELETE、 UPDATEFETCH或 COPY)之后就无法更改事务隔离级别。

事务的访问模式决定该事务是否为读/写或者只读。读/写是默认值。 当一个事务为只读时,如果 SQL 命令 INSERTUPDATE、 DELETECOPY FROM 要写的表不是一个临时表,则它们不被允许。不允许 CREATEALTER以及 DROP命令。不允许COMMENT、 GRANTREVOKE、 TRUNCATE。如果EXPLAIN ANALYZE 和EXECUTE要执行的命令是上述命令之一, 则它们也不被允许。这是一种高层的只读概念,它不能阻止所有对 磁盘的写入。

只有事务也是SERIALIZABLE以及 READ ONLY时,DEFERRABLE 事务属性才会有效。当一个事务的所有这三个属性都被选择时,该事务在 第一次获取其快照时可能会阻塞,在那之后它运行时就不会有 SERIALIZABLE事务的开销并且不会有任何牺牲或者 被一次序列化失败取消的风险。这种模式很适合于长时间运行的报表或者 备份。

SET TRANSACTION SNAPSHOT命令允许新的事务 使用与一个现有事务相同的快照运行。已经存在的事务 必须已经把它的快照用sys_export_snapshot函数(见 快照同步函数 )导出。 该函数会返回一个快照标识符,SET TRANSACTION SNAPSHOT需要被给定一个快照标识符来指定要导入的快照。 在这个命令中该标识符必须被写成一个字符串,例如 '000003A1-1'。 SET TRANSACTION SNAPSHOT只能在一个事务的 开始执行,并且要在该事务的第一个查询或者数据修改语句( SELECT、 INSERTDELETE、 UPDATEFETCH或 COPY)之前执行。此外,该事务必须已经被设置 为SERIALIZABLE或者 REPEATABLE READ隔离级别(否则,该快照将被立刻抛弃, 因为READ COMMITTED模式会为每一个命令取一个新快照)。 如果导入事务使用了SERIALIZABLE隔离级别,那么导入快照 的事务必须也使用该隔离级别。还有,一个非只读可序列化事务不能导入来自只读 事务的快照。

示例

要用一个已经存在的事务的同一快照开始一个新事务,首先要从该现有 事务导出快照。这将会返回快照标识符,例如:

BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT sys_export_snapshot();
 sys_export_snapshot
---------------------
 00000003-0000001B-1
(1 row)

然后在一个新开始的事务的开头把该快照标识符用在一个 SET TRANSACTION SNAPSHOT命令中:

BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION SNAPSHOT '00000003-0000001B-1';

兼容性

SQL标准中定义了这些命令,不过 DEFERRABLE事务模式和 SET TRANSACTION SNAPSHOT形式除外,这两者是 KingbaseES扩展。

SERIALIZABLE是标准中默认的事务隔离级别。在 KingbaseES中默认值是普通的 READ COMMITTED,但是你可以按上述的方式更改。

在 SQL 标准中,可以用这些命令设置一个其他的事务特性:诊断区域 的尺寸。这个概念与嵌入式 SQL 有关,并且因此没有在 KingbaseES服务器中实现。

SQL 标准要求连续的``transaction_modes``之间有逗号, 但是出于历史原因 KingbaseES允许省略逗号。

其他

如果执行SET TRANSACTION之前没有 START TRANSACTION或者 BEGIN,它会发出一个警告并且不会有任何效果。

可以通过在BEGIN或者 START TRANSACTION中指定想要的``transaction_modes``来省掉 SET TRANSACTION。但是在 SET TRANSACTION SNAPSHOT中该选项不可用。

会话默认的事务模式也可以通过设置配置参数 default_transaction_isolation 、default_transaction_read_only 和 default_transaction_deferrable 来设置(实际上 SET SESSION CHARACTERISTICS只是用 SET设置这些变量的等效体)。这意味着可以通过配置文件、 ALTER DATABASE等方式设置默认值。详见 服务器配置参数参考手册 。

20.25. SHOW

用途

SHOW — 显示一个运行时参数的值

SHOW将显示运行时参数的当前设置。这些变量可以使用SET语句、编辑``kingbase.conf``配置参数、通过``KINGBASE_OPTIONS``环境变量(使用libkci或者基于libkci的应用时)或者启动kingbase服务器时通过命令行标志设置。详见 服务器配置参数参考手册 。

前置条件

语法

SHOW name
SHOW ALL

语义

name

一个运行时参数的名称。可用的参数记录在 服务器配置参数参考手册 和 SET 参考页。此外,有一些可以显示但不能设置的参数:

SERVER_VERSION

显示服务器的版本号。

SERVER_ENCODING

显示服务器端的字符集编码。当前,这个参数可以被显示 但不能被设置,因为该设置是在数据库创建时决定的。

LC_COLLATE

显示数据库的排序规则(文本序)的区域设置。当前, 这个参数可以被显示但不能被设置,因为该设置是在 数据库创建时决定的。

LC_CTYPE

显示数据库的字符分类的区域设置。当前, 这个参数可以被显示但不能被设置,因为该设置 是在数据库创建时决定的。

IS_SUPERUSER

如果当前角色具有超级用户特权则为真。

ALL

显示所有配置参数的值,并带有描述。

示例

显示参数DateStyle的当前设置:

SHOW DateStyle;
 DateStyle
-----------
 ISO, MDY
(1 row)

显示参数geqo的当前设置:

SHOW geqo;
 geqo
------
 on
(1 row)

显示所有设置:

SHOW ALL;
            name         |setting |                description
-------------------------+--------+---------------------------------------------
 allow_system_table_mods |off     | Allows modifications of the structure of ...
    .
    .
    .
 xmloption               |content| Sets whether XML data in implicit parsing ...
 zero_damaged_pages      |off    |Continues processing past damaged page headers.
(196 rows)

兼容性

SHOW命令是一种 KingbaseES扩展。

20.26. START TRANSACTION

用途

START TRANSACTION — 开始一个事务块

这个命令开始一个新的事务块。如果指定了隔离级别、读写模式或者可延迟模式,新的事务将会具有这些特性,就像执行了 SET TRANSACTION 一样。这和 BEGIN 命令一样。

前置条件

语法

START TRANSACTION [ transaction_mode [, ...] ]

其中 transaction_mode 是下列之一:

    ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
    READ WRITE | READ ONLY
    [ NOT ] DEFERRABLE

语义

这些参数对于这个语句的含义可参考 SET TRANSACTION 。

示例

开始一个隔离级别是READ COMMIT的事物

start transaction ISOLATION LEVEL READ COMMITTED;

兼容性

在标准中,没有必要发出``START TRANSACTION``来开始一个事务块:任何 SQL 命令会隐式地开始一个块。

KingbaseES的行为可以被视作 在每个命令之后隐式地发出一个没有跟随在``START TRANSACTION``( 或者BEGIN)之后的``COMMIT``并且因此通常被称作“自动提交”。为了方便,其他关系型数据库系统也可能会提供自动提交特性。

DEFERRABLE ``transaction_mode`` 是一种KingbaseES语言扩展。

SQL 标准要求在连续的``transaction_modes``之间有逗号,但是由于历史原因KingbaseES允许 省略逗号。

另见 SET TRANSACTION 的兼容性小节。

20.27. TRUNCATE

用途

TRUNCATE可以从一组表中快速地移除所有行。它具有和在每个表上执行无条件DELETE相同的效果,不过它会更快,因为它没有实际扫描表。此外,它会立刻回收磁盘空间,而不是要求一个后续的VACUUM操作。在大表上 它最有用。

前置条件

要截断一个表,你必须具有其上的TRUNCATE特权。

语法

TRUNCATE [ TABLE ] [ ONLY ] name [ * ] [, ... ]
    [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]

语义

name

要截断的表的名字(可以是模式限定的)。如果在表名前指定了 ONLY,则只会截断该表。如果没有指定ONLY, 该表及其所有后代表(如果有)都会被截断。可选地,可以在表名后指定 *来显式地包括后代表。

RESTART IDENTITY

自动重新开始被截断表的列所拥有的序列。

CONTINUE IDENTITY

不更改序列值。这是默认值。

CASCADE

自动截断所有对任一所提及表有外键引用的表以及任何由于 CASCADE被加入到组中的表。

RESTRICT

如果任一表上具有来自命令中没有列出的表的外键引用,则拒绝截断。这是默认值。

示例

截断表bigtable和 fattable

TRUNCATE bigtable, fattable;

做同样的事情,并且还重置任何相关联的序列发生器:

TRUNCATE bigtable, fattable RESTART IDENTITY;

截断表othertable,并且级联地截断任何通过 外键约束引用othertable的表:

TRUNCATE othertable CASCADE;

兼容性

SQL:2008 标准包括了一个TRUNCATE命令, 语法是TRUNCATE TABLE tablename。子句 CONTINUE IDENTITY/RESTART IDENTITY 也出现在了该标准中,但是含义有些不同。这个命令的一些并发行为被标准 留给实现来定义,因此如果必要应该考虑上述注解并且与其他实现进行比较。

其他

TRUNCATE在要操作的表上要求一个 ACCESS EXCLUSIVE锁,这会阻塞所有其他在该表上的 并发操作。当指定RESTART IDENTITY时,任何需要被 重新开始的序列也会被排他地锁住。如果要求表上的并发访问,那么 应该使用DELETE命令。

TRUNCATE不能被用在被其他表外键引用的表上, 除非那些表也在同一个命令中被阶段。这些情况中的可行性检查将会 要求表扫描,并且重点不是为了做扫描。CASCADE 选项可以被用来自动地包括所有依赖表 — 但使用它时要非常 小心,否则你可能丢失数据!

TRUNCATE将不会引发表上可能存在的任何 ON DELETE触发器。但是它将会引发 ON TRUNCATE触发器。如果在这些表的任意一个 上定义了ON TRUNCATE触发器,那么所有的 BEFORE TRUNCATE触发器将在任何截断发生之前 被引发,而所有AFTER TRUNCATE触发器将在最后 一次截断完成并且所有序列被重置之后引发。触发器将以表被处理的顺 序被引发(首先是那些被列在命令中的,然后是由于级联被加入的)。

TRUNCATE不是 MVCC 安全的。截断之后, 如果并发事务使用的是一个在截断发生前取得的快照, 表将对这些并发事务呈现为空。

从表中数据的角度来说,TRUNCATE是事务安全的: 如果所在的事务没有提交,阶段将会被安全地回滚。

在指定了RESTART IDENTITY时,隐含的 ALTER SEQUENCE RESTART操作也会被事务性地完成。 也就是说,如果所在事务没有提交,它们也将被回滚。这和 ALTER SEQUENCE RESTART的通常行为不同。注意如果 事务回滚前在被重启序列上还做了额外的序列操作,这些操作在序列上的效果 也将被回滚,但是它们在currval()上的效果不会被回滚。也就 是说,在事务之后,currval()将继续反映在失败事务内得到的 最后一个序列值,即使序列本身可能已经不再与此一致。这和失败事务之后 currval()的通常行为类似。

TRUNCATE当前不支持外部表。 这表示如果一个指定的表具有任何外部的后代表,这个命令将会失败。

20.28. UNLISTEN

用途

UNLISTEN — 停止监听一个通知

UNLISTEN被用来移除一个已经存在的对 NOTIFY事件的注册。

UNLISTEN取消任何已经存在的把当前 KingbaseES会话作为名为*``channel``*的通知频道的监听者的注册。特殊的通配符*取消当前会话的所有监听者注册。

NOTIFY 包含有关LISTEN``和\ ``NOTIFY使用的更深入讨论。

前置条件

无。

语法

UNLISTEN { channel | * }

语义

channel

一个通知频道的名称(任何标识符)。

*

所有用于这个会话的当前监听注册都会被清除。

示例

做一次注册:

LISTEN virtual;
NOTIFY virtual;
Asynchronous notification "virtual" received from server process with PID 8448.

一旦执行了UNLISTEN,进一步的NOTIFY 消息将被忽略:

UNLISTEN virtual;
NOTIFY virtual;
-- no NOTIFY event is received

兼容性

在SQL标准中没有VACUUM语句。

其他

你可以 unlisten 你没有监听的东西,不会出现警告或者错误。

在每一个会话末尾,会自动执行UNLISTEN *

一个已经执行了UNLISTEN的事务不能为 两阶段提交做准备。

20.29. UPDATE

用途

UPDATE更改满足条件的所有行中指定列 的值。只有要被修改的列需要在SET子句中提及, 没有被显式修改的列保持它们之前的值。

有两种方法使用包含在数据库其他表中的信息来修改一个表:使用子查询 或者在FROM子句中指定额外的表。这种技术只适合 特定的环境。

可选的RETURNING子句导致UPDATE 基于实际被更新的每一行计算并且返回值。任何使用该表的列以及 FROM中提到的其他表的列的表达式都能被计算。 计算时会使用该表的列的新(更新后)值。RETURNING 列表的语法和SELECT的输出列表相同。

前置条件

你必须拥有该表上的UPDATE特权,或者至少拥有 要被更新的列上的该特权。如果任何一列的值需要被 ``expressions``或者 ``condition``读取, 你还必须拥有该列上的SELECT特权。

语法

[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ]
    SET {[{ column_name = { expression | DEFAULT } |
          ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
          ( column_name [, ...] ) = ( sub-SELECT )
        } [, ...]] | [ ROW = record]}
    [ FROM from_list ]
    [ WHERE condition | WHERE CURRENT OF cursor_name ]
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

语义

with_query

WITH子句允许你指定一个或者更多个在 UPDATE中可用其名称引用的子查询。详见 WITH查询 和 SELECT 。

table_name

要更新的表的名称(可以是模式限定的)。如果在表名前指定了 ONLY,只会更新所提及表中的匹配行。如果没有指定 ONLY,任何从所提及表继承得到的表中的匹配行也会 被更新。可选地,在表名之后指定*可以显式地指示要 把后代表也包括在内。

alias

目标表的一个替代名称。在提供了一个别名时,它会完全隐藏表的真实 名称。例如,给定UPDATE foo AS f, UPDATE语句的剩余部分必须用 f而不是foo来引用该表。

column_name

``table_name`` 所指定的表的一列的名称, 可以用表名(可以被模式名限定)做限定。如果需要,该列名可以用一个子域名称(子域名需要和表名、模式名一同用小括号包围起来进行限定)或者 数组下标限定。

expression

要被赋值给该列的一个表达式。该表达式可以使用该表中这一列或者 其他列的旧值。

DEFAULT

将该列设置为它的默认值(如果没有为它指定默认值表达式,默认值 将会为 NULL)。

sub-SELECT

一个SELECT子查询,它产生和在它之前的圆括号中的列表中 一样多的输出列。被执行时,该子查询必须得到不超过一行。如果它得到 一行,其列值会被赋予给目标列。如果它得不到行,NULL 值将被赋予给 目标列。该子查询可以引用被更新表中当前行的旧值。

from_list

表表达式的列表,允许来自其他表的列出现在WHERE 条件和更新表达式中。这类似于可以在 SELECT语句的 FROM 中指定的表列表。注意目标表不能出现在 ``from_list``中,除非你想做自连接(这种情况下它必须 以别名出现在``from_list``中)。

condition

一个返回boolean类型值的表达式。让这个 表达式返回true的行将会被更新。

cursor_name

要在WHERE CURRENT OF条件中使用的游标名。 要被更新的是从这个游标中最近取出的行。该游标必须是一个 在UPDATE目标表上的非分组查询。注意 WHERE CURRENT OF不能和一个布尔条件一起 指定。有关对游标使用WHERE CURRENT OF的 更多信息请见 DECLARE 。

output_expression

在每一行被更新后,要被UPDATE命令计算并且返回 的表达式。该表达式可以使用 ``table_name``指定 的表或者FROM列出的表中的任何列名。写* 可以返回所有列。

output_name

用于一个被返回列的名称。

record

record变量名,变量类型是自定义RECORD或%ROWTYPE。UPDATE语句更新行数据为record变量值。对于行数据的每列,record的成员必须与表对应列类型兼容。如果表列有NOT NULL约束,对应的record成员不能有NULL值。record成员个数必须与前面table的列数相同,且类型兼容。否则报错。

示例

把表films的列kind 中的单词Drama改成Dramatic

UPDATE films SET kind = 'Dramatic' WHERE kind = 'Drama';

在表weather的一行中调整温度项并且把沉淀物重置为它的默认值:

UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
  WHERE city = 'San Francisco' AND date = '2003-07-03';

执行相同的操作并且返回更新后的项:

UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
  WHERE city = 'San Francisco' AND date = '2003-07-03'
  RETURNING temp_lo, temp_hi, prcp;

使用另一种列列表语法来做同样的更新:

UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT)
  WHERE city = 'San Francisco' AND date = '2003-07-03';

为管理Acme Corporation账户的销售人员增加销售量,使用 FROM子句语法:

UPDATE employees SET sales_count = sales_count + 1 FROM accounts
  WHERE accounts.name = 'Acme Corporation'
  AND employees.id = accounts.sales_person;

执行相同的操作,在 WHERE子句中使用子选择:

UPDATE employees SET sales_count = sales_count + 1 WHERE id =
  (SELECT sales_person FROM accounts WHERE name = 'Acme Corporation');

更新 accounts 表中的联系人姓名以匹配当前被分配的销售员:

UPDATE accounts SET (contact_first_name, contact_last_name) =
    (SELECT first_name, last_name FROM salesmen
     WHERE salesmen.id = accounts.sales_id);

可以用连接完成类似的结果:

UPDATE accounts SET contact_first_name = first_name,
                    contact_last_name = last_name
  FROM salesmen WHERE salesmen.id = accounts.sales_id;

不过,如果salesmen.id不是一个唯一键, 第二个查询可能会给出令人意外的结果,然而如果有多个id匹配, 第一个查询保证会发生错误。还有,如果对于一个特定的 accounts.sales_id项没有匹配,第一个查询将 把相应的姓名域设置为 NULL,而第二个查询完全不会更新该行。

更新一个统计表中的统计数据以匹配当前数据:

UPDATE summary s SET (sum_x, sum_y, avg_x, avg_y) =
    (SELECT sum(x), sum(y), avg(x), avg(y) FROM data d
     WHERE d.group_id = s.group_id);

尝试插入一个新库存项及其库存量。如果该项已经存在,则转而更新已有项的库存量。要这样做并且不让整个事务失败,可以使用保存点:

BEGIN;
-- 其他操作
SAVEPOINT sp1;
INSERT INTO wines VALUES('Chateau Lafite 2003', '24');
-- 假定上述语句由于未被唯一键失败,
-- 那么现在我们发出这些命令:
ROLLBACK TO sp1;
UPDATE wines SET stock = stock + 24 WHERE winename = 'Chateau Lafite 2003';
-- 继续其他操作,并且最终
COMMIT;

更改表films中由游标c_films``定位的行的\ ``kind列:

UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;

更改表数据为record变量值:

CREATE TABLE t1(id INT, name VARCHAR(20));
DECLARE
  TYPE myrecord IS RECORD(id INT, name VARCHAR(20));
  r1 myrecord;
BEGIN
  r1.id := 1;
  r1.name := 'new';
  UPDATE t1 SET ROW = r1;
END;
/

兼容性

这个命令符合SQL标准,不过FROMRETURNING子句是 KingbaseES扩展,把WITH用于UPDATE也是扩展。

有些其他数据库系统提供了一个FROM选项,在其中在其中目标表 可以在FROM中被再次列出。但 KingbaseES不是这样解释 FROM的。在移植使用这种扩展的应用时要小心。

根据标准,一个目标列名的圆括号子列表的来源值可以是任意得到正确列数的行值 表达式。KingbaseES只允许来源值是一个行构造器或者一个子查询。一个列的 被更新值可以在行构造器的情况中被指定为DEFAULT,但在 子查询的情况中不能这样做。

其他

  1. 输出

    成功完成时,一个UPDATE命令返回形如

    UPDATE count
    

    的命令标签。 ``count``是被更新的行数, 包括值没有更改的匹配行。注意,当更新被一个BEFORE UPDATE 触发器抑制时,这个数量可能比匹配 ``condition``的行数少。如果 ``count``为零,没有行被该查 询更新(这不是一个错误)。

    如果UPDATE命令包含一个RETURNING 子句,其结果将类似于一个包含RETURNING列表中定义的 列和值的SELECT语句(在被该命令更新的行上计算) 的结果。

  2. 说明

    当存在FROM子句时,实际发生的是:目标表被连接到 ``from_list``中的表,并且该连接的每一 个输出行表示对目标表的一个更新操作。在使用FROM 时,你应该确保该连接对每一个要修改的行产生至多一个输出行。换 句话说,一个目标行不应该连接到来自其他表的多于一行上。如果发 生这种情况,则只有一个连接行将被用于更新目标行,但是将使用哪 一行是很难预测的。

    由于这种不确定性,只在一个子选择中引用其他表更安全,不过这种 语句通常很难写并且也比使用连接慢。

    在分区表的情况下,更新一行有可能导致它不再满足其所在分区的分区约束。此时, 如果这个行满足分区树中某个其他分区的分区约束,那么这个行会被移动到那个分区。 如果没有这样的分区,则会发生错误。在后台,行的移动实际上是一次DELETE 操作和一次INSERT操作。

    对于正在移动的行,并发的UPDATEDELETE将会得到序列化失败错误。假设会话1在一个分区键上执行一个UPDATE,同时,一个可以看到这一行的并发会话2在这一行上执行一个UPDATEDELETE操作。在这种情况下,会话2的UPDATEDELETE将检测行移动并引发序列化失败错误(它总是返回一个SQLSTATE代码'40001')。如果发生这种情况,应用程序可能希望重试事务。在通常情况下,如果表没有分区,或者没有行移动,会话2将识别新更新的行,并在这个新行版本上执行UPDATE/DELETE

    注意,虽然行可以从本地分区移动到外部表分区(假设外部数据包装器支持元组路由),但是它们不能从外部表分区移动到另一个分区。

    对于SET ROW = record语句,有下面限制条件:

    1. UPDATE SET ROW = record只能在PLSQL中使用。

    2. Record变量只允许出现在:

      1)UPDATE语句SET子句的右边。 2)RETURNING子句的INTO子句中。

    3. ROW关键字只允许在SET的左边,不可以在子查询中使用ROW。

    4. UPDATE语句中,如果是使用ROW,只允许出现一个ROW子句。

    5. 如果RETURNING INTO子句包含一个record变量,不允许出现其他变量或值。

    6. record成员个数必须都前面table列数相同,且类型兼容。否则报错。

    7. 不支持:

      1)嵌套的record类型。 2)返回record类型的函数。 3)EXECUTE IMMEDIATE的INSERT, UPDATE语句的record

20.30. VACUUM

用途

VACUUM — 垃圾收集并根据需要分析一个数据库 VACUUM收回由死亡元组占用的存储空间。在通常的KingbaseES操作中,被删除或者被更新废弃的元组并没有在物理上从它们的表中移除,它们将一直存在直到一次VACUUM被执行。因此有必要周期性地做VACUUM,特别是在频繁被更新的表上。

在没有``table_and_columns``列表的情况下,VACUUM会处理当前用户具有清理权限的当前数据库中的每一个表和物化视图。如果给出一个列表,VACUUM可以只处理列表中的那些表。

VACUUM ANALYZE对每一个选定的表ANALYZE。这是两种命令的一种方便的组合形式,可以用于例行的维护脚本。其处理细节可参考 ANALYZE 。

简单的``VACUUM``(不带FULL)简单地收回空间并使其可以被重用。这种形式的命令可以和表的普通读写操作并行,因为它不会获得一个排他锁。但是,这种形式中额外的空间并没有被还给操作系统(在大多数情况下),它仅仅被保留在同一个表中以备重用。VACUUM FULL将表的整个内容重写到一个新的磁盘文件中,并且不包含额外的空间,这使得没有被使用的空间被还给操作系统。这种形式的命令更慢并且在其被处理时要求在每个表上保持一个排他锁。

当选项列表被包围在圆括号中时,选项可以被写成任何顺序。如果没有圆括号,选项必须严格按照上面所展示的顺序指定。有圆括号的语法在KingbaseES V8.2 时被加入,无圆括号的语法则被废弃。

前置条件

要清理一个表,操作者通常必须是表的拥有者或者超级用户。但是,数据库拥有者被允许清理他们的数据库中除了共享目录之外的所有表(对于共享目录的限制意味着一个真正的数据库范围的VACUUM只能被超级用户执行)。VACUUM将会跳过执行者不具备清理权限的表。

语法

VACUUM [ ( option [, ...] ) ] [ table_and_columns [, ...] ]
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ table_and_columns [, ...] ]

其中option可以是下列之一:

    FULL [ boolean ]
    FREEZE [ boolean ]
    VERBOSE [ boolean ]
    ANALYZE [ boolean ]
    DISABLE_PAGE_SKIPPING [ boolean ]
    SKIP_LOCKED [ boolean ]
    INDEX_CLEANUP [ boolean ]
    TRUNCATE [ boolean ]

而table_and_columns是:

    table_name [ ( column_name [, ...] ) ]

语义

FULL

选择“完全”清理,它可以收回更多空间,并且需要更长时间和表上的排他锁。这种方法还需要额外的磁盘空间,因为它会创建该表的一个新拷贝,并且在操作完成之前都不会释放旧的拷贝。通常这种方法只用于需要从表中收回数量庞大的空间时。

FREEZE

选择激进的元组“冻结”。指定``FREEZE`` 等价于参数 vacuum_freeze_min_age 和 vacuum_freeze_table_age 设置为0的``VACUUM``。当表被重写时总是会执行激进的冻结,因此指定FULL时这个选项是多余的。

VERBOSE

为每个表打印一份详细的清理活动报告。

ANALYZE

更新优化器用以决定最有效执行一个查询的方法的统计信息。

DISABLE_PAGE_SKIPPING

通常,VACUUM将基于可见性映射跳过页面。已知所有元组都被冻结的页面总是会被跳过,而那些所有元组对所有事务都可见的页面则可能会被跳过(除非执行的是激进的清理)。此外,除非在执行激进的清理时,一些页面也可能会被跳过,这样可避免等待其他页面完成对其使用。这个选项禁用所有的跳过页面的行为,其意图是只在可见性映射内容被怀疑时使用,这种情况只有在硬件或者软件问题导致数据库损坏时才会发生。

SKIP_LOCKED

指定VACUUM在开始处理一个关系时,不应等待任何冲突锁被释放:如果一个关系不能立即被锁定而不等待,则跳过该关系。注意,即使使用这个选项,VACUUM在打开关系的索引时仍然可能阻塞。此外,当从分区、表继承子表和某些类型的外部表获取样本行时,VACUUM ANALYZE可能仍然会阻塞。此外,当VACUUM通常处理指定分区表的所有分区时,如果分区表上有冲突的锁,则此选项将导致VACUUM跳过所有分区。

INDEX_CLEANUP

指定VACUUM尝试删除指向死元组的索引项。这通常是需要的行为,并且是默认的,除非将vacuum_index_cleanup选项设置为false,以便对表进行空化。当需要使vacuum尽可能快地运行时,将该选项设置为false可能是有用的,例如为了避免即将发生的事务ID封装(请参阅 防止事务ID回卷失败 )。但是,如果不定期执行索引清理,性能可能会受到影响,因为当表被修改时,索引将积累死元组,而表本身将积累死行指针,这些指针在索引清理完成之前无法删除。此选项对没有索引的表无效,如果使用FULL选项,则会忽略此选项。

TRUNCATE

指定VACUUM应该尝试截断表末尾的任何空页,并允许将截断的页返回给操作系统。这通常是需要的行为,并且是默认的,除非将vacuum_truncate选项设置为false,以便对表进行真空处理。将此选项设置为false可能有助于避免截断所需的表上的ACCESS EXCLUSIVE锁。如果使用FULL选项,则忽略此选项。

boolean

指定所选选项应该打开还是关闭。可以编写TRUEON,或1来启用这个选项,编写FALSEOFF,或0来禁用它。也可以省略``boolean``,此时假设TRUE

table_name

要清理的表或物化视图的名称(可以有模式修饰)。如果指定的表示一个分区表,则它所有的叶子分区也会被清理。

column_name

要分析的指定列的名称。缺省是所有列。如果指定了一个列的列表,则ANALYZE也必须被指定。

示例

清理单一表onek,为优化器分析它并且打印出详细的清理活动报告:

VACUUM (VERBOSE, ANALYZE) onek;

兼容性

在SQL标准中没有VACUUM语句。

其他

VACUUM不能在一个事务块内被执行。

对具有GIN索引的表,VACUUM(任何形式)也会通过将待处理索引项移动到主要GIN索引结构中的合适位置来完成任何待处理的索引插入。

我们建议经常清理活动的生产数据库(至少每晚一次),以保证移除失效的行。在增加或删除了大量行之后,对受影响的表执行VACUUM ANALYZE命令是一个很好的做法。这样做将把最近的更改更新到系统目录,并且允许KingbaseES查询规划器在规划用户查询时做出更好的选择。

日常使用时,不推荐FULL选项,但在特殊情况时它会有用。一个例子是当你删除或者更新了一个表中的绝大部分行时,如果你希望在物理上收缩表以减少磁盘空间占用并且允许更快的表扫描,则该选项是比较合适的。VACUUM FULL通常会比简单VACUUM更多地收缩表。

VACUUM会导致I/O流量的大幅度增加,这可能导致其他活动会话性能变差。因此,有时建议使用基于代价的清理延迟特性。详情请参阅 基于代价的清理延迟 。

KingbaseES包括了一个“autovacuum”工具,它可以自动进行例行的清理维护。关于自动和手动清理的更多信息请见 日常清理 。

20.31. VALUES

用途

VALUES  --  计算由值表达式指定的一个行值或者一组行值。更常见的是把它用来生成一个大型命令内的“常量表”,但是它也可以被独自使用。

当多于一行被指定时,所有行都必须具有相同数量的元素。结果表的列数据类型由出现在该列的表达式的显式或者推导类型组合决定,决定的规则与 UNION相同(见 UNION CASE和相关结构 )。

在大型的命令中,在语法上允许VALUES出现在``SELECT``出现的任何地方。因为语法把它当做一个``SELECT``,可以为一个VALUES 命令使用ORDER BYLIMIT(或者等效的FETCH FIRST)以及OFFSET子句。

前置条件

无。

语法

VALUES ( expression [, ...] ) [, ...]
  [ ORDER BY sort_expression [ ASC | DESC | USING operator ] [, ...] ]
  [ LIMIT { count | ALL } ]
  [ OFFSET start [ ROW | ROWS ] ]
  [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]

语义

expression

要在结果表(行集合)中指定位置计算并且插入的一个常量或者表达式。 在一个出现于INSERT顶层的 VALUES列表中, ``expression``可以被DEFAULT替代以表示应该插入目标列的默认值。 当VALUES出现在其他环境中时,不能使用 DEFAULT

sort_expression

一个指示如何排序结果行的表达式或者整型常量。这个表达式 可以用column1column2等来 引用该VALUES结果的列。详见 ``ORDER BY``子句 :ref:`ORDER BY 。

operator

一个排序操作符。详见 ```ORDER BY``子句 :ref:`ORDER BY 。

count

要返回的最大行数。详见 ```LIMIT``子句 :ref:`LIMIT 。

start

开始返回行之前要跳过的行数。详见 ```LIMIT``子句 :ref:`LIMIT 。

示例

一个纯粹的VALUES命令:

VALUES (1, 'one'), (2, 'two'), (3, 'three');

这将返回一个具有两列、三行的表。它实际等效于:

SELECT 1 AS column1, 'one' AS column2
UNION ALL
SELECT 2, 'two'
UNION ALL
SELECT 3, 'three';

更常用地,VALUES可以被用在一个大型 SQL 命令中。在INSERT中最常用:

INSERT INTO films (code, title, did, date_prod, kind)
    VALUES ('T_601', 'Yojimbo', 106, '1961-06-16', 'Drama');

INSERT的环境中,一个VALUES列表的项可以是DEFAULT来指示应该使用该列的默认值而不是指定一个值:

INSERT INTO films VALUES
    ('UA502', 'Bananas', 105, DEFAULT, 'Comedy', '82 minutes'),
    ('T_601', 'Yojimbo', 106, DEFAULT, 'Drama', DEFAULT);

VALUES也可以被用在可以写子-SELECT``的地方,例如在一个\ ``FROM子句中:

SELECT f.*
  FROM films f, (VALUES('MGM', 'Horror'), ('UA', 'Sci-Fi')) AS t (studio, kind)
  WHERE f.studio = t.studio AND f.kind = t.kind;

UPDATE employees SET salary = salary * v.increase
  FROM (VALUES(1, 200000, 1.2), (2, 400000, 1.4)) AS v (depno, target, increase)
  WHERE employees.depno = v.depno AND employees.sales >= v.target;

注意当VALUES被用在一个FROM子句中时,需要提供一个AS子句,与SELECT相同。 不需要为所有的列用AS子句指定名称,但是那样做是一种好习惯(在KingbaseES中, VALUES的默认列名是column1column2等,但在其他数据库系统中可能会不同)。

当在INSERT中使用VALUES时,值都会被自动地强制为相应目标列的数据类型。当在其他环境中使用时,有必要指定正确的数据类型。如果项都是带引号的字符串常量,强制第一个就足以为所有项假设数据类型:

SELECT * FROM machines
WHERE ip_address IN (VALUES('192.168.0.1'::inet), ('192.168.0.10'),
('192.168.1.43'));

提示

对于简单的IN测试,最好使用IN的list-of-scalars而不是写一个上面那样的VALUES查询。标量列表方法的书写更少并且常常更加高效。

兼容性

VALUES符合 SQL 标准。 LIMITOFFSET是KingbaseES扩展,另见 SELECT 。

其他

应该避免具有大量行的VALUES列表,否则可能会碰到内存不足失败或者很差的性能。出现在INSERT``中的\ ``VALUES是一种特殊情况(因为想要的列类型可以从INSERT的目标表得知,并且不需要通过扫描该VALUES列表来推导),因此它可以处理比其他环境中更大的列表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值