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标准。
其他
如果源表中有多行与目标表中的一行匹配,并且同时指定了 WHEN MATCHED THEN UPDATE 子句,则报错,因为同一元组不能被重复更新。
对于 set_list 来说,不能指定 ON 条件子句中用于联接条件的目标表中的列。
在 value_list 的值表达式中不能引用目标表中的列。
如果目标表上有约束或目标视图的定义中有 WITH CHECK OPTION,则对目标表所做的更新要满足基表上的约束条件或视图定义的校验条件。
需要有对源表的 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以及载荷字符串,如果载荷字符串没有被指定则它为空字符串。
将在一个给定数据库以及其他数据库中使用的频道名称由数据库设计者定义。通常,频道名称与数据库中某个表的名称相同,并且通知事件其实就意味着:“我改变了这个表,来看看改了什么吧”。但是
NOTIFY
和LISTEN
命令并未强制这样的关联。例如,一个数据库设计者可以使用几个不同的频道名称来标志一个表上的不同种类的改变。另外,载荷字符串可以被用于多种不同的情况。当
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
(text
,text
)。该函数采用频道名称作为第一个参数,而载荷则作为第二个参数。如果你需要使用非常量的频道名称和载荷,这个函数比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
任何
SELECT
、INSERT
、UPDATE
、DELETE
或者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 plan或custom plan来执行准备好的语句。通用计划在所有执行中是相同的,而使用调用中给定的参数值为特定执行生成自定义计划。使用通用计划可以避免计划开销,但在某些情况下,自定义计划执行起来更有效,因为计划人员可以利用参数值的知识。(当然,如果准备好的语句没有参数,那么这是没有意义的,通常使用的是通用计划。)
默认情况下(也就是说,当 plan_cache_mode 被设置为
auto
),服务器将自动选择对一个有参数的准备好的语句使用通用计划还是自定义计划。当前的规则是,前五个执行是使用定制计划完成的,并计算这些计划的平均估计成本。然后创建一个通用计划,并将其估计成本与平均定制计划成本进行比较。如果通用计划的成本并不比平均定制计划成本高得多,从而使重复的重新计划看起来更可取,那么随后的执行将使用通用计划。通过将
plan_cache_mode
设置为force_generic_plan
或force_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
的游标或者执行LISTEN
、UNLISTEN
或NOTIFY
的事务中,不允许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``,则不会生成新数据并且会让物化视图处于一种不可扫描的状态。
前置条件
CONCURRENTLY
和WITH 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 SYSTEM
、REINDEX TABLE
或者REINDEX INDEX
,具体使用哪个命令取决于你想要重构多少东西。如果有疑问,可以使用``REINDEX SYSTEM``来选择重建数据库中的所有系统索引。然后退出单用户服务器会话并且重启常规的服务器。更多关于如何与单用户服务器接口交互的内容请见 kingbase 参考页。在另一种方法中,可以开始一个常规的服务器会话,在其命令行选项中包括
-P
。这样做的方法与客户端有关,但是在所有基于libkci的客户端中都可以在开始客户端之前设置KINGBASE_OPTIONS
环境变量为-P
。注意虽然这种方法不要求用锁排斥其他客户端,在修复完成之前避免其他用户连接到受损的数据库才是更加明智的。
REINDEX
类似于删除索引并且重建索引,在其中索引内容会被从头开始建立。不过,锁定方面的考虑却相当不同。REINDEX
会用锁排斥写,但不会排斥在索引的父表上的读。它也会在被处理的索引上取得一个排他锁,该锁将会阻塞对该索引的使用尝试。相反,DROP INDEX
会暂时在附表上取得一个排他锁,阻塞写和读。后续的CREATE INDEX
会排斥写但不排斥读,由于该索引不存在,所以不会有读取它的尝试,这意味着不会有阻塞但是读操作可能被强制成昂贵的顺序扫描。重索引单独一个索引或者表要求用户是该索引或表的拥有者。对方案或数据库重建索引要求是该方案或者数据库的拥有者。注意因此非超级用户有时无法重建其他用户拥有的表上的索引。不过,作为一种特例,当一个非超级用户发出
REINDEX DATABASE
、REINDEX SCHEMA
或者REINDEX SYSTEM
时,共享目录上的索引将被跳过,除非该用户拥有该目录(通常不会是这样)。当然,超级用户总是可以重建所有的索引。不支持重建分区表的索引或者分区索引。不过可以单独为每个分区重建索引。重建索引可能会干扰数据库的正常操作。通常KingbaseES会锁定一个表,这个表的索引是根据写操作重新构建的,并且只扫描一次表就可以执行整个索引构建。其他事务仍然可以读取表,但是如果它们试图插入、更新或删除表中的行,它们将阻塞这些行,直到完成索引重建。如果系统是一个实时的生产数据库,这可能会产生严重的影响。非常大的表可能需要花费很多小时来建立索引,甚至对于更小的表,重新构建索引可能会将编写者锁定在生产系统无法接受的长时间内。
KingbaseES支持最小化写锁的重建索引。该方法调用
CONCURRENTLY
的REINDEX
选项。当使用这个选项时,KingbaseES必须为每个需要重建的索引执行两次表扫描,并等待可能使用该索引的所有现有事务的终止。与标准的索引重建相比,此方法需要更多的总工作,而且完成所需的时间要长得多,因为它需要等待可能修改索引的未完成事务。但是,由于它允许在重新构建索引时继续正常操作,所以此方法对于在生产环境中重新构建索引非常有用。的当然,由索引重新生成的额外CPU、内存和I/O负载可能会减慢其他操作。在并发重索引中执行以下步骤。每个步骤都在一个单独的事务中运行。如果有多个索引需要重新构建,那么每个步骤在进入下一个步骤之前循环遍历所有索引。
一个新的临时索引定义被添加到目录
sys_index
。此定义将用于替换旧索引。会话级别的SHARE UPDATE EXCLUSIVE
锁对正在重编索引的索引及其关联表执行锁,以防止在处理时进行任何模式修改。为每个新索引完成构建索引的第一次遍历。一旦建立了索引,它的标志
sys_index.indisready
被切换为“true”,以使它为插入做好准备,使它在执行构建的事务完成后对其他会话可见。此步骤在每个索引的单独事务中完成。然后执行第二个遍历来添加在第一个遍历运行时添加的元组。此步骤也在每个索引的单独事务中完成。
所有引用索引的约束都被更改为引用新的索引定义,索引的名称也被更改。此时,
sys_index.indisvalid
是转向“true”新指数和“false”,缓存失效导致所有会话引用旧的索引失效。旧的索引由
sys_index.indisready
切换到“false”以防止任何新的元组插入,在等待可能引用旧索引的查询完成之后。旧的索引被删除。索引和表的
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 TABLE
或REINDEX 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
。根据标准,关键词RESTRICT
或CASCADE
是必要的,但是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
一个函数或者聚集参数的模式:
IN
、OUT
、INOUT
或者VARIADIC
。如果被忽略,默认值会是IN
。注意SECURITY LABEL
并不真正 关心OUT
参数,因为判断函数的身份时只需要输入参数。因此列出IN
、INOUT
和VARIADIC
参数足矣。
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
的通常处理如下:
WITH
列表中的所有查询都会被计算。这些查询实际 充当了在FROM
列表中可以引用的临时表。在FROM
中被引用多次的WITH
查询只会被计算一次。 unless specified otherwise withNOT MATERIALIZED
.
FROM
列表中的所有元素都会被计算(FROM
中的每一个元素都是一个真实表或者虚拟表)。 如果在FROM
列表中指定了多于一个元素,它们会被 交叉连接在一起。如果指定了
WHERE
子句,所有不满足该条件的行都会 被从输出中消除。如果指定了
GROUP BY
子句或者如果有聚集函数,输出 会被组合成由在一个或者多个值上匹配的行构成的分组,并且在其上计算聚 集函数的结果。如果出现了HAVING
子句,它会消除不 满足给定条件的分组。对于每一个被选中的行或者行组,会使用
SELECT
输出表达式计算实际的输出行。
SELECT DISTINCT
从结果中消除重复的行。SELECT DISTINCT ON
消除在所有指定表达式上匹 配的行。SELECT ALL
(默认)将返回所有候选行, 包括重复的行。同时KingbaseES中的SELECT UNIQUE
也可以从结果中消除重复的行。SELECT UNIQUE ON
消除在所有指定表达式上匹 配的行。SELECT ALL
(默认)将返回所有候选行, 包括重复的行。通过使用操作符
UNION
、INTERSECT
和EXCEPT
,多于 一个SELECT
语句的输出可以被整合形成 一个结果集。UNION
操作符返回位于一个或者两 个结果集中的全部行。INTERSECT
操作符返回同时 位于两个结果集中的所有行。EXCEPT
操作符返回 位于第一个结果集但不在第二个结果集中的行。在所有三种情况下, 重复行都会被消除(除非指定ALL
)。可以增加噪 声词DISTINCT
来显式地消除重复行。注意虽然ALL
是SELECT
自身的默认行为, 但这里DISTINCT
是默认行为。如果指定了
ORDER BY
子句,被返回的行会以指定的 顺序排序。如果没有给定ORDER BY
,系统会以能最 快产生行的顺序返回它们(。如果指定了
LIMIT
(或FETCH FIRST
) 或者OFFSET
子句,SELECT
语句只返回结果行的一个子集。如果指定了
FOR UPDATE
、FOR NO KEY UPDATE
、FOR SHARE
或者FOR KEY SHARE
,SELECT
语句会把被选中的行锁定而不让并发 更新访问它们。
前置条件
你必须拥有在一个
SELECT
命令中使用的每一列上的SELECT
特权。FOR NO KEY UPDATE
、FOR UPDATE
、FOR 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
语义
WITH子句
WITH
子句允许你指定一个或者多个在主查询中可以 其名称引用的子查询。在主查询期间子查询实际扮演了临时表或者视图 的角色。每一个子查询都可以是一个SELECT
、TABLE
、VALUES
、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
查询不需要被排序:一个查询可以引用另一个 在列表中比它靠后的查询(不过,循环引用或者互递归没有实现)。 如果没有RECURSIVE
,WITH
查询只能引用在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查询 。
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发布包括两种采样 方法:BERNOULLI
和SYSTEM
, 其他采样方法可以通过扩展安装在数据库中。
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
对于
INNER
和OUTER
连接类型,必须指定 一个连接条件,即NATURAL
、ON join_condition
或者USING (join_column
[, ...]) 之一(只能有一种)。其含义见下文。对于CROSS JOIN
,上述子句不能出现。一个
JOIN
子句联合两个FROM
项( 为了方便我们称之为“表”,尽管实际上它们可以是任何类型 的FROM
项)。如有必要可以使用圆括号确定嵌套的顺序。 在没有圆括号时,JOIN
会从左至右嵌套。在任何情 况下,JOIN
的联合比分隔FROM
-列表 项的逗号更强。
CROSS JOIN
和INNER JOIN
会产生简单的笛卡尔积,也就是与在FROM
的顶层列出两个 表得到的结果相同,但是要用连接条件(如果有)约束该结果。CROSS JOIN
与INNER 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``。WHERE子句
可选的
WHERE
子句的形式WHERE condition其中``condition`` 是任一计算得到
布尔
类型结果的表达式。任何不满足 这个条件的行都会从输出中被消除。如果用一行的实际值替换其中的 变量引用后,该表达式返回真,则该行符合条件。GROUP BY子句
可选的
GROUP BY
子句的形式GROUP BY grouping_element [, ...]
GROUP BY
将会把所有被选择的行中共享相同分组表达式 值的那些行压缩成一个行。一个被用在 ``grouping_element``中的 ``expression``可以是输入列名、输出列 (SELECT
列表项)的名称或序号或者由输入列 值构成的任意表达式。在出现歧义时,GROUP BY
名称 将被解释为输入列名而不是输出列名。如果任何
GROUPING SETS
、ROLLUP
或者CUBE
作为分组元素存在,则GROUP BY
子句 整体上定义了数个独立的``分组集``。其效果等效于在子 查询间构建一个UNION ALL
,子查询带有分组集作为它们 的GROUP BY
子句。聚集函数(如果使用)会在组成每一个分组的所有行上进行计算,从而为每 一个分组产生一个单独的值(如果有聚集函数但是没有
GROUP BY
子句,则查询会被当成是由所有选中行构成 的一个单一分组)。传递给每一个聚集函数的行集合可以通过在聚集函数调 用附加一个FILTER
子句来进一步过滤,详见 聚集表达式 。当存在一个FILTER
子句时,只有那些匹配它的行才会被包括在该聚 集函数的输入中。当存在
GROUP BY
子句或者任何聚集函数时,SELECT
列表表达式不能引用非分组列(除非它 出现在聚集函数中或者它函数依赖于分组列),因为这样做会导致返回 非分组列的值时会有多种可能的值。如果分组列是包含非分组列的表的主键( 或者主键的子集),则存在函数依赖。记住所有的聚集函数都是在
HAVING
子句或者SELECT
列表中的任何“标量”表达式之前被计算。 这意味着一个CASE
表达式不能被用来跳过一个聚集表达式的 计算,见 表达式计算规则 。当前,
FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能和GROUP BY
一起指定。HAVING子句
可选的
HAVING
子句的形式HAVING condition其中``condition``与
WHERE
子句中指定的条件相同。
HAVING
消除不满足该条件的分组行。HAVING
与WHERE
不同:WHERE
会在应用GROUP BY
之前过滤个体行,而HAVING
过滤由GROUP BY
创建的分组行。 ``condition``中引用 的每一个列必须无歧义地引用一个分组列(除非该引用出现在一个聚集 函数中或者该非分组列函数依赖于分组列。即使没有
GROUP BY
子句,HAVING
的存在也会把一个查询转变成一个分组查询。这和查询中包含聚集函数但没有GROUP BY
子句时的情况相同。所有被选择的行都被认为是一个 单一分组,并且SELECT
列表和HAVING
子句只能引用聚集函数中的表列。如果该HAVING
条件为真,这样一个查询将会发出一个单一行; 否则不返回行。当前,
FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能与HAVING
一起指定。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
表示以分区最后一行结束的帧,不论是处于RANGE
、ROWS
或者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 UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能和WINDOW
一起被指定。窗口函数的详细描述在 高级特性 窗口函数 、 窗口函数调用`以及 :ref:`窗口函数处理 中。
SELECT列表
SELECT
列表(位于关键词SELECT
和FROM
之间)指定构成SELECT
语句输出行的表达式。这些表达式 可以(并且通常确实会)引用FROM
子句中计算得到的列。正如在表中一样,
SELECT
的每一个输出列都有一个名称。 在一个简单的SELECT
中,这个名称只是被用来标记要显 示的列,但是当SELECT
是一个大型查询的一个子查询时,大型查询 会把该名称看做子查询产生的虚表的列名。要指定用于输出列的名称,在该列的表达式 后面写上AS
``output_name``( 你可以省略AS
,但只能在期望的输出名称不匹配任何 KingbaseES关键词(见 SQL关键词 )时省略。为了避免和未来增加的关键词冲突, 推荐总是写上AS
或者用双引号引用输出名称)。如果你不指定列名, KingbaseES会自动选择一个名称。如果列的表达式 是一个简单的列引用,那么被选择的名称就和该列的名称相同。在使用函数或者类型名称 的更复杂的情况中,系统可能会生成诸如?column?
之类的名称。一个输出列的名称可以被用来在
ORDER BY
以及GROUP BY
子句中引用该列的值,但是不能用于WHERE
和HAVING
子句(在其中 必须写出表达式)。可以在输出列表中写
*
来取代表达式,它是被选中 行的所有列的一种简写方式。还可以写table_name
.*,它 是只来自那个表的所有列的简写形式。在这些情况中无法用AS
指定新的名称,输出行的名称将和表列的名称相同。根据 SQL 标准,输出列表中的表达式应该在应用
DISTINCT
、ORDER BY
或者LIMIT
之前计算。在使用DISTINCT
时显然必须这样做,否则就无法搞清到底在区分什么值。不过,在很多情况下如果先计算ORDER BY
和LIMIT
再计算输出表达式会很方便,特别是如果输出列表中包含任何 volatile 函数或者代价昂贵的函数时尤其如此。通过这种行为,函数计算的顺序更加直观并且对于从未出现在输出中的行将不会进行计算。只要输出表达式没有被DISTINCT
、ORDER BY
或者GROUP BY
引用,KingbaseES实际将在排序和限制行数之后计算输出表达式(作为一个反例,SELECT f(x) FROM tab ORDER BY 1
显然必须在排序之前计算f(x)
)。包含有集合返回函数的输出表达式实际是在排序之后和限制行数之前被计算,这样LIMIT
才能切断来自集合返回函数的输出。注意
V8.2 版本之前的KingbaseES不对执行输出表达式、排序、限制行数的时间顺序做任何保证,那将取决于被选中的查询计划的形式。
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 UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能和DISTINCT
一起使用。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 UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能和UNIQUE
一起使用。UNION子句
UNION
子句具有下面的形式:select_statement UNION [ ALL | DISTINCT ] select_statement``select_statement`` 是任何没有
ORDER BY
、LIMIT
、FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
子句的SELECT
语句(如果子表达式被包围在圆括号内,ORDER BY
和LIMIT
可以被附着到其上。如果没有 圆括号,这些子句将被应用到UNION
的结果而不是右手边 的表达式上)。
UNION
操作符计算所涉及的SELECT
语句所返回的行的并集。如果一行 至少出现在两个结果集中的一个内,它就会在并集中。作为UNION
两个操作数的SELECT
语句必须产生相同数量的列并且 对应位置上的列必须具有兼容的数据类型。
UNION
的结果不会包含重复行,除非指定了ALL
选项。ALL
会阻止消除重复(因此,UNION ALL
通常显著地快于UNION
, 尽量使用ALL
)。可以写DISTINCT
来 显式地指定消除重复行的行为。除非用圆括号指定计算顺序, 同一个
SELECT
语句中的多个UNION
操作符会从左至右计算。当前,
FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能用于UNION
结果或者UNION
的任何输入。INTERSECT子句
INTERSECT
子句具有下面的形式:select_statement INTERSECT [ ALL | DISTINCT ] select_statement``select_statement`` 是任何没有
ORDER BY
,LIMIT
、FOR NO KEY UPDATE
、FOR 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 UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能用于INTERSECT
结果或者INTERSECT
的任何输入。EXCEPT子句
EXCEPT
子句具有下面的形式:select_statement EXCEPT [ ALL | DISTINCT ] select_statement``select_statement`` 是任何没有
ORDER BY
、LIMIT
、FOR NO KEY UPDATE
、FOR 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 UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能用于EXCEPT
结果或者EXCEPT
的任何输入。MINUS子句
MINUS
子句具有下面的形式:select_statement MINUS [ ALL | DISTINCT ] select_statement``select_statement`` 是任何没有
ORDER BY
、LIMIT
、FOR NO KEY UPDATE
、FOR 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 UPDATE
、FOR UPDATE
、FOR SHARE
和FOR KEY SHARE
不能用于MINUS
结果或者MINUS
的任何输入。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
、INTERSECT
或EXCEPT
子句结果上的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"
。更多信息请见 排序规则表达式 和 排序规则 。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。ROW
和ROWS
以及FIRST
和NEXT
是噪声,它们不影响 这些子句的效果。根据标准,如果都存在,OFFSET
子句 必须出现在FETCH
子句之前。但是 KingbaseES更宽松,它允许两种顺序。在使用
LIMIT
时,用一个ORDER BY
子句把 结果行约束到一个唯一顺序是个好办法。否则你讲得到该查询结果行的 一个不可预测的子集 — 你可能要求从第 10 到第 20 行,但是在 什么顺序下的第 10 到第 20 呢?除非指定ORDER BY
,你 是不知道顺序的。查询规划器在生成一个查询计划时会考虑
LIMIT
,因此 根据你使用的LIMIT
和OFFSET
,你很可能 得到不同的计划(得到不同的行序)。所以,使用不同的LIMIT
/OFFSET
值来选择一个查询结果的 不同子集将会给出不一致的结果,除非你 用ORDER BY
强制一种可预测的结果顺序。这不是一个 缺陷,它是 SQL 不承诺以任何特定顺序(除非使用ORDER BY
来约束顺序)给出一个查询结果这一事实造 成的必然后果。如果没有一个
ORDER BY
来强制选择一个确定的子集, 重复执行同样的LIMIT
查询甚至可能会返回一个表中行 的不同子集。同样,这也不是一种缺陷,再这样一种情况下也无法 保证结果的确定性。锁定子句
FOR UPDATE
、FOR NO KEY UPDATE
、FOR SHARE
和FOR 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秒,如果等待成功则返回结果集,否则超时报错返回。 注意NOWAIT
,SKIP LOCKED
和WAIT 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 BY
与LIMIT
或者其他 限制组合使用时。因此只有在并发更新排序列并且要求严格的排序结果时才推 荐使用这种技术。在
REPEATABLE READ
或者SERIALIZABLE
事务隔离级别上这可能导致一个序列化失败(SQLSTATE
是'40001'
),因此在这些隔离级别下不可能收到无序行。TABLE命令
命令
TABLE name等价于
SELECT * FROM name它可以被用作一个顶层命令,或者用在复杂查询中以节省空间。只有
WITH
、UNION
、INTERSECT
、EXCEPT
、MINUS
、ORDER BY
、LIMIT
、OFFSET
、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查询 )。这个例子使用
LATERAL
为manufacturers
表的每一行应用一个集合返回函数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 标准的。但是也有一些扩展和缺失的特性。
省略的FROM子句
KingbaseES允许我们省略
FROM
子句。一种简单的使用是计算简单表达式 的结果:SELECT 2+2; ?column? ---------- 4某些其他SQL数据库需要引入一个假的 单行表放在该
SELECT
的FROM
子句中才能做到这一点。注意,如果没有指定一个
FROM
子句,该查询 就不能引用任何数据库表。例如,下面的查询是非法的:SELECT distributors.* WHERE distributors.name = 'Westward';KingbaseES在 8.1 之前的发行 会接受这种形式的查询,并且为该查询引用的每一个表在
FROM
子句中隐式增加一个项。现在已经不再允许 这样做。空SELECT列表
SELECT
之后的输出表达式列表可以为空, 这会产生一个零列的结果表。对 SQL 标准来说这不是合法的 语法。KingbaseES允许 它是为了与允许零列表保持一致。不过在使用DISTINCT
时不允许空列表。省略AS关键词
在 SQL 标准中,只要新列名是一个合法的列名(就是说与任何保留关键词不同), 就可以省略输出列名之前的可选关键词
AS
。 KingbaseES要稍微严格些:只要新列名匹配 任何关键词(保留或者非保留)就需要AS
。推荐的习惯是使用AS
或者带双引号的输出列名来防止与未来增加的关键词可能的冲突。在
FROM
项中,标准和 KingbaseES都允许省略非保留 关键词别名之前的AS
。但是由于语法的歧义,这无法 用于输出列名。ONLY和继承
在书写
ONLY
时,SQL 标准要求在表名周围加上圆括号,例如SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...
。KingbaseES 认为这些圆括号是可选的。KingbaseES允许写一个拖尾的
*
来 显式指定包括子表的非-ONLY
行为。而标准则不允许 这样。(这些点同等地适用于所有支持
ONLY
选项的 SQL 命令)。TABLESAMPLE子句限制
当前只在常规表和物化视图上接受
TABLESAMPLE
子句。 根据 SQL 标准,应该可以把它应用于任何FROM
项。FROM中的函数调用
KingbaseES允许一个函数调用被直接写作
FROM
列表的一个成员。在 SQL 标准中,有必要把这样一个函数 调用包裹在一个子-SELECT
中。也就是说,语法FROM func
(...) ``alias`` 近似等价于FROM LATERAL (SELECT func
(...)) ``alias``。 注意该LATERAL
被认为是隐式的,这是因为标准对于FROM
中的一个UNNEST()
项要求LATERAL
语义。KingbaseES会把UNNEST()
和其他集合返回函数同样对待。GROUP BY和ORDER BY可用的名字空间
在 SQL-92 标准中,一个
ORDER BY
子句只能使用输出 列名或者序号,而一个GROUP BY
子句只能使用基于输 入列名的表达式。KingbaseES扩展了 这两种子句以允许它们使用其他的选择(但如果有歧义时还是使用标准的 解释)。KingbaseES也允许两种子句 指定任意表达式。注意出现在一个表达式中的名称将总是被当做输入列名而 不是输出列名。SQL:1999 及其后的标准使用了一种略微不同的定义,它并不完全向后兼容 SQL-92。不过,在大部分的情况下, KingbaseES会以与 SQL:1999 相同的 方式解释
ORDER BY
或GROUP BY
表达式。函数依赖
只有当一个表的主键被包括在
GROUP BY
列表中时, KingbaseES才识别函数依赖(允许 从GROUP BY
中省略列)。SQL 标准指定了应该要识别 的额外情况。LIMIT和OFFSET
LIMIT
和OFFSET
子句是 KingbaseES-特有的语法,在 MySQL也被使用。SQL:2008 标准已经 引入了具有相同功能的子句OFFSET ... FETCH {FIRST|NEXT} ...
(如上文 :ref`LIMIT子句` 中所示)。这种语法 也被IBM DB2使用( Oracle编写的应用常常使用自动生成的rownum
列来实现这些子句的效果,这在 KingbaseES 中是没有的)。FOR NO KEY UPDATE、FOR UPDATE 、FOR SHARE 、FOR KEY SHARE
尽管 SQL 标准中出现了
FOR UPDATE
,但标准只允许它作为DECLARE CURSOR
的一个选项。 KingbaseES允许它出现在任何SELECT
查询以及子-SELECT
中,但这是 一种扩展。FOR NO KEY UPDATE
、FOR SHARE
以及FOR KEY SHARE
变体以及NOWAIT
和SKIP LOCKED
选项没有在标准中出现。WITH中的数据修改语句
KingbaseES允许把
INSERT
、UPDATE
以及DELETE
用作WITH
查询。这在 SQL 标准中是找不到的。非标准子句
DISTINCT ON ( ... )
是 SQL 标准的扩展。
ROWS FROM( ... )
是 SQL 标准的扩展。
WITH
的MATERIALIZED
和NOT 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
orTEMP
如果被指定,该表被创建为一个临时表。详见 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
约束直到事务提交时才被检查。每个约束都有 自己的IMMEDIATE
或DEFERRED
模式。在创建时,一个约束会被给定三种特性之一:
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
可以被用来在一个事务中的特定点强制进 行约束检查。当前,只有
UNIQUE
、PRIMARY KEY
、REFERENCES
(外键)以及EXCLUDE
约束受到这个设置的影响。NOT NULL
以及CHECK
约束总是在一行 被插入或修改时立即检查(不是在语句结束时)。 没有被声明为DEFERRABLE
的唯一和排除约束也会被 立刻检查。被声明为“约束触发器”的触发器的引发也受到这个设置 的控制 — 它们会在相关约束被检查的同时被引发。
前置条件
无
语法
SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE }
语义
name
指定约束名称
ALL
指定所有约束
示例
设置约束模式为结束时检查
SET CONSTRAINTS my_constraint IMMEDIATE;
兼容性
这个命令符合 SQL 标准中定义的行为,但有一点限制:在 KingbaseES中,它不会应用在
NOT NULL
和CHECK
约束上。还有, KingbaseES会立刻检查非可延迟的 唯一约束,而不是按照标准建议的在语句结束时检查。
其他
因为KingbaseES并不要求约束名称在模式内 唯一(但是在表内要求唯一),可能有多于一个约束匹配指定的约束名称。在这种 情况下
SET CONSTRAINTS
将会在所有的匹配上操作。 对于一个非模式限定的名称,一旦在搜索路径中的某个模式中发现一个或者多个匹 配,路径中后面的模式将不会被搜索。这个命令只修改当前事务内约束的行为。在事务块外部发出这个命令会产生一个 警告并且也不会有任何效果。
20.22. SET ROLE
用途
这个命令把当前 SQL 会话的当前用户标识符设置为 ``role_name``。 角色名可以写成一个标识符或者一个字符串。在
SET ROLE
之后,对 SQL 命令的权限检查时就 好像该角色就是原先登录的角色一样。当前会话用户必须是指定的 角色``role_name`` 的一个成员(如果会话用户是一个超级用户,则可以选择任何角色)。
SESSION
和LOCAL
修饰符发挥的作用和 常规的 SET 命令一样。
NONE
和RESET
形式把当前用户标识符 重置为当前会话用户标识符。这些形式可以由任何用户执行。
前置条件
你必须拥有该角色以使用 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 更改它。当前用户标识符与权限检查相关。
会话用户标识符只能在初始会话用户已认证用户具有超级用户特权时被更改。否则,只有该命令指定已认证用户名时才会被接受。
SESSION
和LOCAL
修饰符发挥的作用和常规 SET 命令一样。
DEFAULT
和RESET
形式把会话用户标识符和当前用户标识符重置为初始的已认证用户名。这些形式可以由任何用户执行。
前置条件
会话用户标识符只能在初始会话用户 已认证用户具有超级用户特权时被更改。
语法
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
之后,会话级别的设置会再次生效。在事务块外部发出这个参数会发出一个警告并且不会有效果。
DEFAULT
,RESET
当前用户标识符重置为初始的已认证用户名。这些形式可以由任何用户执行。
示例
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
、INSERT
、DELETE
、UPDATE
、FETCH
或COPY
)之后就无法更改事务隔离级别。事务的访问模式决定该事务是否为读/写或者只读。读/写是默认值。 当一个事务为只读时,如果 SQL 命令
INSERT
、UPDATE
、DELETE
和COPY FROM
要写的表不是一个临时表,则它们不被允许。不允许CREATE
、ALTER
以及DROP
命令。不允许COMMENT
、GRANT
、REVOKE
、TRUNCATE
。如果EXPLAIN ANALYZE
和EXECUTE
要执行的命令是上述命令之一, 则它们也不被允许。这是一种高层的只读概念,它不能阻止所有对 磁盘的写入。只有事务也是
SERIALIZABLE
以及READ ONLY
时,DEFERRABLE
事务属性才会有效。当一个事务的所有这三个属性都被选择时,该事务在 第一次获取其快照时可能会阻塞,在那之后它运行时就不会有SERIALIZABLE
事务的开销并且不会有任何牺牲或者 被一次序列化失败取消的风险。这种模式很适合于长时间运行的报表或者 备份。
SET TRANSACTION SNAPSHOT
命令允许新的事务 使用与一个现有事务相同的快照运行。已经存在的事务 必须已经把它的快照用sys_export_snapshot
函数(见 快照同步函数 )导出。 该函数会返回一个快照标识符,SET TRANSACTION SNAPSHOT
需要被给定一个快照标识符来指定要导入的快照。 在这个命令中该标识符必须被写成一个字符串,例如'000003A1-1'
。SET TRANSACTION SNAPSHOT
只能在一个事务的 开始执行,并且要在该事务的第一个查询或者数据修改语句(SELECT
、INSERT
、DELETE
、UPDATE
、FETCH
或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标准,不过
FROM
和RETURNING
子句是 KingbaseES扩展,把WITH
用于UPDATE
也是扩展。有些其他数据库系统提供了一个
FROM
选项,在其中在其中目标表 可以在FROM
中被再次列出。但 KingbaseES不是这样解释FROM
的。在移植使用这种扩展的应用时要小心。根据标准,一个目标列名的圆括号子列表的来源值可以是任意得到正确列数的行值 表达式。KingbaseES只允许来源值是一个行构造器或者一个子查询。一个列的 被更新值可以在行构造器的情况中被指定为
DEFAULT
,但在 子查询的情况中不能这样做。
其他
输出
成功完成时,一个
UPDATE
命令返回形如UPDATE count的命令标签。 ``count``是被更新的行数, 包括值没有更改的匹配行。注意,当更新被一个
BEFORE UPDATE
触发器抑制时,这个数量可能比匹配 ``condition``的行数少。如果 ``count``为零,没有行被该查 询更新(这不是一个错误)。如果
UPDATE
命令包含一个RETURNING
子句,其结果将类似于一个包含RETURNING
列表中定义的 列和值的SELECT
语句(在被该命令更新的行上计算) 的结果。说明
当存在
FROM
子句时,实际发生的是:目标表被连接到 ``from_list``中的表,并且该连接的每一 个输出行表示对目标表的一个更新操作。在使用FROM
时,你应该确保该连接对每一个要修改的行产生至多一个输出行。换 句话说,一个目标行不应该连接到来自其他表的多于一行上。如果发 生这种情况,则只有一个连接行将被用于更新目标行,但是将使用哪 一行是很难预测的。由于这种不确定性,只在一个子选择中引用其他表更安全,不过这种 语句通常很难写并且也比使用连接慢。
在分区表的情况下,更新一行有可能导致它不再满足其所在分区的分区约束。此时, 如果这个行满足分区树中某个其他分区的分区约束,那么这个行会被移动到那个分区。 如果没有这样的分区,则会发生错误。在后台,行的移动实际上是一次
DELETE
操作和一次INSERT
操作。对于正在移动的行,并发的
UPDATE
或DELETE
将会得到序列化失败错误。假设会话1在一个分区键上执行一个UPDATE
,同时,一个可以看到这一行的并发会话2在这一行上执行一个UPDATE
或DELETE
操作。在这种情况下,会话2的UPDATE
或DELETE
将检测行移动并引发序列化失败错误(它总是返回一个SQLSTATE代码'40001')。如果发生这种情况,应用程序可能希望重试事务。在通常情况下,如果表没有分区,或者没有行移动,会话2将识别新更新的行,并在这个新行版本上执行UPDATE
/DELETE
。注意,虽然行可以从本地分区移动到外部表分区(假设外部数据包装器支持元组路由),但是它们不能从外部表分区移动到另一个分区。
对于SET ROW = record语句,有下面限制条件:
UPDATE SET ROW = record只能在PLSQL中使用。
Record变量只允许出现在:
1)UPDATE语句SET子句的右边。 2)RETURNING子句的INTO子句中。
ROW关键字只允许在SET的左边,不可以在子查询中使用ROW。
UPDATE语句中,如果是使用ROW,只允许出现一个ROW子句。
如果RETURNING INTO子句包含一个record变量,不允许出现其他变量或值。
record成员个数必须都前面table列数相同,且类型兼容。否则报错。
不支持:
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
指定所选选项应该打开还是关闭。可以编写
TRUE
,ON
,或1
来启用这个选项,编写FALSE
,OFF
,或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 BY
、LIMIT
(或者等效的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
一个指示如何排序结果行的表达式或者整型常量。这个表达式 可以用
column1
、column2
等来 引用该VALUES
结果的列。详见 ``ORDER BY``子句 :ref:`ORDER BY 。
operator
一个排序操作符。详见 ```ORDER BY``子句 :ref:`ORDER BY 。
count
要返回的最大行数。详见 ```LIMIT``子句 :ref:`LIMIT 。
start
示例
一个纯粹的
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
的默认列名是column1
、column2
等,但在其他数据库系统中可能会不同)。当在
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 标准。LIMIT
和OFFSET
是KingbaseES扩展,另见 SELECT 。
其他
应该避免具有大量行的
VALUES
列表,否则可能会碰到内存不足失败或者很差的性能。出现在INSERT``中的\ ``VALUES
是一种特殊情况(因为想要的列类型可以从INSERT
的目标表得知,并且不需要通过扫描该VALUES
列表来推导),因此它可以处理比其他环境中更大的列表。