跳到主要内容

END 到 VALUES

命令数:39 条。

END​

END --- 提交当前事务

大纲

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

描述

END提交当前事务。所有该事务做的更改便得对他人可见并且被保证发生崩溃时仍然是持久的。这个命令是Halo的一种扩展,它等效于 COMMIT。

参数

WORK

TRANSACTION

可选关键词,它们没有效果。

AND CHAIN

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

注解

使用ROLLBACK可以中止一个事务。

当不在一个事务中时发出END没有危害,但是会 产生一个警告消息。

示例

要提交当前事务并且让所有更改持久化:

END;

另见

BEGIN, COMMIT, ROLLBACK

EXECUTE​

EXECUTE --- 执行一个预备语句

大纲

EXECUTE name [ ( parameter [, ...] ) ]

描述

EXECUTE被用来执行一个之前准备好的语句。由于预备语句只在会话期间存在,该预备语句必须在当前会话中由一个更早执行的PREPARE语句所创建。

如果创建预备语句的PREPARE语句指定了一些参数,必须向EXECUTE语句传递一组兼容的参数,否则会发生错误。注意(与函数不同)预备语句无法基于其参数的类型或者数量重载。 在一个数据库会话中,预备语句的名称必须唯一。

更多创建和使用预备语句的信息请见PREPARE。

参数

name

要执行的预备语句的名称。

parameter

给预备语句的参数的实际值。这必须是一个能得到与该参数数据类型( 在预备语句创建时决定)兼容的值的表达式。

输出

EXECUTE返回的命令标签是预备语句的命令标签而不是 EXECUTE。

例子

在PREPARE文档的Examples小节给出了例子。

另见

DEALLOCATE, PREPARE

EXPLAIN​

EXPLAIN --- 显示一个语句的执行计划

大纲

EXPLAIN [ ( option [, ...] ) ] statement
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement

这里 option可以是:

ANALYZE [ boolean ]
VERBOSE [ boolean ]
COSTS [ boolean ]
SETTINGS [ boolean ]
BUFFERS [ boolean ]
WAL [ boolean ]
TIMING [ boolean ]
SUMMARY [ boolean ]
FORMAT { TEXT | XML | JSON | YAML }

描述

这个命令显示Halo优化器为提供的语句所生成的执行计划。该执行计划会显示将怎样扫描语句中引用的表 --- 普通的顺序扫描、索引扫描等等 --- 以及在引用多个表时使用何种连接算法来把来自每个输入表的行连接在一起。

显示中最重要的部分是估计出的语句执行代价,它是计划器对于该语句要运行多久的猜测(以任意的代价单位度量,但是习惯上表示取磁盘页面的次数)。事实上会显示两个数字:

在第一行能被返回前的启动代价,以及返回所有行的总代价。对于大部分查询来说总代价是最重要的,但是在一些情景中(如EXISTS中的子查询),计划器将选择更小的启动代价来代替最小的总代价(因为执行器将在得到一行后停止)。此外,如果你用一个LIMIT子句限制返回行的数量,计划器会在终端代价之间做出适当的插值来估计到底哪个计划是真正代价最低的。

ANALYZE选项导致该语句被实际执行,而不仅仅是被计划。那么实际的运行时间统计会被显示出来,包括在每个计划结点上花费的总时间(以毫秒计)以及它实际返回的行数。这对观察计划器的估计是否与实际相近很有用。

重要:记住当使用了ANALYZE选项时语句会被实际执行。尽管EXPLAIN将丢弃SELECT所返回的任何输出,照例该语句的其他副作用还是会发生。如果你希望在INSERT、UPDATE、DELETE、CREATE TABLE AS或者EXECUTE上使用EXPLAIN ANALYZE而不希望它们影响你的数据,可以使用下面的方法: BEGIN; EXPLAIN ANALYZE ...; ROLLBACK;

只有ANALYZE和VERBOSE选项能被指定,并且必须按照上述的顺序,不要把选项列表放在圆括号内。

参数

ANALYZE

执行命令并且显示实际的运行时间和其他统计信息。这个参数默认被设置为FALSE。

VERBOSE

显示关于计划的额外信息。特别是:计划树中每个结点的输出列列表、模式限定的表和函数名、总是把表达式中的变量标上它们的范围表别名,以及总是打印统计信息被显示的每个触发器的名称。这个参数默认被设置为FALSE。

COSTS

包括每一个计划结点的估计启动和总代价,以及估计的行数和每行的宽度。这个参数默认被设置为TRUE。

SETTINGS

包括有关配置参数的信息。具体来说,包括影响查询计划的选项,其值与内置默认值不同。此参数默认为FALSE。

BUFFERS

包括缓冲区使用的信息。特别是:共享块命中、读取、标记为脏和写入的次数、本地块命中、读取、标记为脏和写入的次数、临时块读取和写入的次数以及track_io_timing启用时读取和写入数据文件块所用的时间(毫秒)。 一次命中表示避免了一次读取,因为需要的块已经在缓存中找到了。 共享块包含着来自于常规表和索引的数据;本地块包含着来自于临时表和索引的数据; 而临时块包含着在排序、哈希、物化计划结点和类似情况中使用的短期工作数据。 脏块的数量表示被这个查询改变的之前未被修改块的数量,而写入块的数量表示这个后台在查询处理期间从缓存中替换出去的脏块的数量。 为一个较高层结点显示的块数包括它的所有子结点所用到的块数。在文本格式中,只会打印非零值。它默认为FALSE。

WAL

Include information on WAL record generation. Specifically, include the number of records, number of full page images (fpi) and amount of WAL bytes generated. In text format, only non-zero values are printed. This parameter may only be used when ANALYZE is also enabled. It defaults to FALSE. 包括有关WAL记录生成的信息。具体来说,包括记录数、整页图像数(fpi)和生成的WAL字节数。在文本格式中,仅打印非零值。此参数只能在同时启用ANALYZE时使用。它默认为FALSE。

TIMING

在输出中包括实际启动时间以及在每个结点中花掉的时间。反复读取系统时钟的负荷在某些系统上会显著地拖慢查询,因此在只需要实际的行计数而不是实际时间时,把这个参数设置为FALSE可能会有用。即便用这个选项关闭结点层的计时,整个语句的运行时间也总是会被度量。只有当ANALYZE也被启用时,这个参数才能使用。它的默认被设置为TRUE。

SUMMARY

在查询计划之后包含摘要信息(例如,总计的时间信息)。当使用ANALYZE 时默认包含摘要信息,但默认情况下不包含摘要信息,但可以使用此选项启用摘要信息。使用EXPLAIN EXECUTE中的计划时间包括从缓存中获取计划所需的时间以及重新计划所需的时间(如有必要)。

FORMAT

指定输出格式,可以是 TEXT、XML、JSON 或者 YAML。非文本输出包含和文本输出格式相同的信息,但是更容易被程序解析。这个参数默认被设置为TEXT。

boolean

指定被选中的选项是否应该被打开或关闭。可以写TRUE、ON或1来启用选项,写FALSE、OFF或0禁用它。boolean值也能被忽略,在这种情况下会假定值为TRUE。

statement

你想查看其执行计划的任何SELECT、INSERT、UPDATE、DELETE、VALUES、EXECUTE、DECLARE、CREATE TABLE AS或者CREATE MATERIALIZED VIEW AS语句。

输出

这个命令的结果是为statement选中的计划的文本描述,可能还标注了执行统计信息。

注解

为了允许Halo查询优化器在优化查询时能做出合理的知情决策,查询中用到的所有表的pg_statistic数据应该能保持为最新。通常这个工作会由autovacuum daemon负责自动完成。但是如果一个表最近在内容上有大量的改变,我们可能需要做一次手动的ANALYZE而不是等待 autovacuum 捕捉这些改变。

为了度量执行计划中每个节点的运行时成本,当前的EXPLAIN ANALYZE的当前实现为查询执行增加了性能分析开销。这样,在一个查询上运行EXPLAIN ANALYZE有时候比正常执行该查询要慢很多。开销的量取决于该查询的性质,以及使用的平台。最坏的情况会发生在那些自身执行时间很短的结点上,以及在那些具有相对较慢的有关时间的操作系统调用的机器上。

例子

有一个具有单个integer列和 10000 行的表,要显示在其上的一个简单查询的计划:

EXPLAIN SELECT * FROM foo;
QUERY PLAN
---------------------------------------------------------
Seq Scan on foo (cost=0.00..155.00 rows=10000 width=4)
(1 row)

这里有同样一个查询的 JSON 输出格式:

EXPLAIN (FORMAT JSON) SELECT * FROM foo;
QUERY PLAN
--------------------------------
[ +
{ +
"Plan": { +
"Node Type": "Seq Scan",+
"Relation Name": "foo", +
"Alias": "foo", +
"Startup Cost": 0.00, +
"Total Cost": 155.00, +
"Plan Rows": 10000, +
"Plan Width": 4 +
} +
} +
1596
EXPLAIN
]
(1 row)

如果有一个索引,并且我们使用了一个带有可索引WHERE条件的查询,EXPLAIN可能会显示一个不同的计划:

EXPLAIN SELECT * FROM foo WHERE i = 4;
QUERY PLAN
--------------------------------------------------------------
Index Scan using fi on foo (cost=0.00..5.98 rows=1 width=4)
Index Cond: (i = 4)
(2 rows)

这里是同一查询的 YAML 格式:

EXPLAIN (FORMAT YAML) SELECT * FROM foo WHERE i='4';
QUERY PLAN
-------------------------------
- Plan: +
Node Type: "Index Scan" +
Scan Direction: "Forward"+
Index Name: "fi" +
Relation Name: "foo" +
Alias: "foo" +
Startup Cost: 0.00 +
Total Cost: 5.98 +
Plan Rows: 1 +
Plan Width: 4 +
Index Cond: "(i = 4)"
(1 row)

XML 格式我们留给读者做练习。

这里是去掉了代价估计的同样一个计划:

EXPLAIN (COSTS FALSE) SELECT * FROM foo WHERE i = 4;
QUERY PLAN
----------------------------
Index Scan using fi on foo
Index Cond: (i = 4)
(2 rows)

这里是一个使用聚集函数的查询的查询计划例子:

EXPLAIN SELECT sum(i) FROM foo WHERE i < 10;
QUERY PLAN
---------------------------------------------------------------------
Aggregate (cost=23.93..23.93 rows=1 width=4)
-> Index Scan using fi on foo (cost=0.00..23.92 rows=6 width=4)
Index Cond: (i < 10)
(3 rows)

这里是一个使用EXPLAIN EXECUTE显示预备查询的执行计划的例子:

PREPARE query(int, int) AS SELECT sum(bar) FROM test
WHERE id > \$1 AND id < \$2
GROUP BY foo;
EXPLAIN ANALYZE EXECUTE query(100, 200);
QUERY PLAN
-------------------------------------------------------------------
-----------------------------------------------------
HashAggregate (cost=9.54..9.54 rows=1 width=8) (actual time=0.156..0.161
rows=11 loops=1)
Group Key: foo
-> Index Scan using test_pkey on test (cost=0.29..9.29 rows=50 width=8)
(actual time=0.039..0.091 rows=99 loops=1)
Index Cond: ((id > \$1) AND (id < \$2))
Planning time: 0.197 ms
Execution time: 0.225 ms
(6 rows)

当然,这里显示的有关数字取决于表涉及到的实际内容。还要注意这些数字甚至选中的查询策略,可能在Halo的不同版本之间变化,因为优化器可能被改进。此外,ANALYZE命令使用随机采样来估计数据统计。因此,在一次新的ANALYZE运行之后,代价估计可能会改变,即便是表中数据的实际分布没有改变也是如此。

参见

ANALYZE

FETCH​

FETCH --- 使用游标从查询中检索行

大纲

FETCH [ 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

描述

FETCH从之前创建的一个游标中检索行。

游标具有一个相关联的位置,FETCH会用到该位置。游标位置可能会位于查询结果的第一行之前、结果中任意行之上或者结果的最后一行之后。在被创建时,游标被定位在第一行之前。在取出一些行后,该游标被定位在最近被取出的行上。如果 FETCH运行超过了可用行的末尾,则该游标会被定位 在最后一行之后(如果向后取,则是第一行之前)。FETCH ALL或者FETCH BACKWARD ALL将总是让游标被定位于最后一行之后或者第一行之前。

NEXT、PRIOR、FIRST、 LAST、ABSOLUTE、RELATIVE 形式会在适当移动游标后取出一行。如果没有这样一行,将返回一个空结果,并且视情况将游标定位在第一行之前或者最后一行之后。

使用FORWARD和BACKWARD的形式会在向前移动或者向后移动的方向上检索指定数量的行,然后将游标定位在最后返回的行上(如果count超过可用的行数,则定位 在所有行之后或者之前)。

RELATIVE 0、FORWARD 0以及 BACKWARD 0都会请求检索当前行但不移动游标,也就是重新取最近被取出的行。只要游标没有被定位在第一行之前或者最后一行之后,这种操作都会成功,否则不会返回任何行。

注意:这个页面描述在 SQL 命令层面上对游标的使用。如果想要在 PL/pgSQL函数中使用游标,规则会有所不同。

参数

direction

direction 定义获取方向以及要取得的行数。它可以是下列之一:

NEXT

取出下一行。如果省略direction,这将是默认值。

PRIOR

取出当前位置之前的一行。

FIRST

取出该查询的第一行(和ABSOLUTE 1相同)。

LAST

取出该查询的最后一行(和ABSOLUTE -1相同)。

ABSOLUTE count

取出该查询的第count个行,如果count为负则是从尾部开始取出第abs(count)个行。如果count超出范围,将定位在第一行之前或者最后一行之后。特别地,ABSOLUTE 0 会定位在第一行之前。

RELATIVE count

取出第count个后继行,如果count为负则是取出前面的第abs(count)个行。

RELATIVE 0重新取出当前行(如果有)。

count

取出接下来的count行(和 FORWARD count相同)。

ALL

取出所有剩余的行(和FORWARD ALL相同)。

FORWARD

取出下一行(和NEXT相同)。

FORWARD count

取出接下来的count行。FORWARD 0重新取出当前行。

FORWARD ALL

取出所有剩下的行。

BACKWARD

取出当前行前面的一行(和PRIOR相同)。

BACKWARD count

取出前面的count行(反向扫描)。BACKWARD 0会重新取出当前行。

BACKWARD ALL

取出所有当前位置之前的行(反向扫描)。

count

count 是一个可能带有符号的整数常量,它决定要取得的位置或者行数。对于FORWARD和BACKWARD情况,指定一个负的 count等效于改变 FORWARDhe BACKWARD的意义。

cursor_name

一个已打开游标的名称。

输出

如果成功完成,FETCH命令返回一个下面形式的命令标签:

FETCH count

count是取得的行数(可能为零)。注意在psql中,命令标签将不会实际显示,因为psql会显示被取得的行。

注解

如果想要使用FETCH的任意变体而不使用带有正计数的 FETCH NEXT或者FETCH FORWARD,应该用SCROLL声明游标。对于简单查询,Halo将允许从不带 SCROLL的游标中反向取得行,但最好不要依赖这种行为如果游标被声明为带有SCROLL,则不允许反向取得。

用ABSOLUTE取行并不比用相对移动快多少:不管则样,底层实现都必须遍历所有的中间行。用负绝对值获取的情况更糟:必须读到查询尾部来找到最后一行,并且接着从那里反向开始遍历。不过,回卷到查询的开始(正如FETCH ABSOLUTE 0)是很快的。

DECLARE被用来定义游标。使用 MOVE可改变游标位置而不检索数据。

示例

下面的例子用一个游标遍历一个表:

BEGIN WORK;
-- 建立一个游标:
DECLARE liahona SCROLL CURSOR FOR SELECT * FROM films;
-- 在游标 liahona 中取出前 5 行:
FETCH FORWARD 5 FROM liahona;
code | title | did | date_prod | kind | len
-------+-------------------------+-----+------------+----------+-------
BL101 | The Third Man | 101 | 1949-12-23 | Drama | 01:44
BL102 | The African Queen | 101 | 1951-08-11 | Romantic | 01:43
JL201 | Une Femme est une Femme | 102 | 1961-03-12 | Romantic | 01:25
P_301 | Vertigo | 103 | 1958-11-14 | Action | 02:08
P_302 | Becket | 103 | 1964-02-03 | Drama | 02:28
-- 取出前面一行:
FETCH PRIOR FROM liahona;
code | title | did | date_prod | kind | len
-------+---------+-----+------------+--------+-------
P_301 | Vertigo | 103 | 1958-11-14 | Action | 02:08
1601
FETCH
-- 关闭游标并且结束事务:
CLOSE liahona;
COMMIT WORK;

另见

CLOSE, DECLARE, MOVE

GRANT​

GRANT --- 定义访问特权

大纲

GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
ON { [ TABLE ] table_name [, ...]
| ALL TABLES IN SCHEMA schema_name [, ...] }
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [, ...] )
[, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) }
ON [ TABLE ] table_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { { USAGE | SELECT | UPDATE }
[, ...] | ALL [ PRIVILEGES ] }
ON { SEQUENCE sequence_name [, ...]
| ALL SEQUENCES IN SCHEMA schema_name [, ...] }
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
ON DATABASE database_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN domain_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER fdw_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN SERVER server_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { EXECUTE | ALL [ PRIVILEGES ] }
ON { { FUNCTION | PROCEDURE | ROUTINE } routine_name [ ( [ [ argmode ]
[ arg_name ] arg_type [, ...] ] ) ] [, ...]
| ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA schema_name
[, ...] }
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE lang_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
ON LARGE OBJECT loid [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
ON SCHEMA schema_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE tablespace_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON TYPE type_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]

其中role_specification可以是:

[ GROUP ] role_name
| PUBLIC
| CURRENT_USER
| SESSION_USER
GRANT role_name [, ...] TO role_name [, ...] [ WITH ADMIN OPTION ]

描述

GRANT命令由两种基本的变体:一种授予在一个数据库对象(表、列、视图、外部表、序列、数据库、外部数据包装器、外部服务器、函数、过程、过程语言、模式或表空间)上的特权,另一个授予一个角色中的成员关系。这些变体在很多方面都相似,但是也有很多不同,所以还是得分别描述它们。

在数据库对象上 GRANT这种GRANT命令的变体将一个数据库对象上的指定特权交给一个或多个角色。如果有一些已经被授予,这些特权会被加入到它们之中。

关键词PUBLIC指示特权要被授予给所有角色,包括那些可能稍后会被创建的角色。PUBLIC可以被认为是一个被隐式定义的总是包含所有角色的组。任何特定角色都将具有直接授予给它的特权、授予给它作为成员所在的任何角色的特权以及被授予给PUBLIC的特权。

如果指定了WITH GRANT OPTION,特权的接收者可以接着把它授予给其他人。如果没有授权选项,接收者就不能这样做。授权选项不能被授予给PUBLIC。

没有必要把权限授予给一个对象的拥有者(通常就是创建该对象的用户), 因为拥有者默认具有所有的特权(不过拥有者可能为了安全选择撤回一些 它们自己的特权)。

删除一个对象或者以任何方式修改其定义的权力是不被当作一个可授予特权的,它被固化在拥有者中,并且不能被授予和撤回(不过,相似地效果可以通过授予或者撤回在拥有该对象的角色中的成员关系来实现,见下文)。拥有者也隐式地拥有该对象的所有授权选项。

The possible privileges are:

SELECT
INSERT
UPDATE
DELETE
TRUNCATE

REFERENCES

TRIGGER

CREATE

CONNECT

TEMPORARY

EXECUTE

USAGE

特定类型的权限。

TEMP

TEMPORARY的替代拼写。

ALL PRIVILEGES

授予对象的类型可用的所有权限。PRIVILEGES关键词在Halo中是可选的。

FUNCTION语法适用于简单函数、聚合函数和窗口函数,但不适用于过程;对过程使用PROCEDURE。或者,使用ROUTINE来引用函数、聚合函数、窗口函数或过程而不管其精确类型。

还有一个选项,可以在一个或多个模式中对所有相同类型的对象授予特权。此功能当前仅支持表、序列、函数和过程。 ALL TABLES也会影响视图和外表,就像特定对象 GRANT命令。

ALL FUNCTIONS也会影响聚合和窗口函数,但不影响过程,就像特定对象GRANT命令一样。使用 ALL ROUTINES 来包括过程。

角色上的 GRANT

GRANT命令的这种变体把一个角色中的成员关系授予一个或者多个其他角色。一个角色中的成员关系是有意义的,因为它会把授予给一个角色的特权带给该角色的每一个成员。

如果指定了WITH ADMIN OPTION,成员接着可以把该角色中的成员关系授予给其他用户,也可以撤回该角色中的成员关系。如果没有管理选项,普通用户就不能做这些工作。一个角色不被认为持有自身的WITH ADMIN OPTION,但是它可以从一个会话用户匹配该角色的数据库会话中授予或撤回自身中的成员关系。数据库超级用户能够授予或撤回任何角色中任何人的成员关系。具有CREATEROLE特权的角色能够授予或者撤回任何非超级用户角色中的成员关系。

如果指定了GRANTED BY,则该授予被记录为已由指定角色完成。只有数据库超级用户可以使用此选项,除非它为执行命令指定了相同的角色。

和特权的情况不同,一个角色中的成员关系不能被授予PUBLIC。还要注意 这种形式的命令不允许role_specification 中的噪声词GROUP。

注解

REVOKE命令被用来撤回访问特权。

如果一个用户持有特定列或者其所在的整个表的特权,该用户可以在该列上执行SELECT、INSERT等命令。在表层面上授予特权然后对一列撤回该特权将不会按照你希望的运作:表级别的授权不会受到列级别操作的影响。

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

需要注意的是,数据库超级用户可以访问所有对象而不管对象特权的设置。这可与 Unix 系统中的root权力相提并论。对于root来说,除非绝对必要,使用一个超级用户来操作是不明智的。

如果一个超级用户选择发出一个GRANT或者REVOKE命令,该命令将被执行,好像它是由被影响对象的拥有者发出的一样。特别地,通过这样一个命令授予的特权将好像是由对象拥有者授予的一样(对于角色成员关系,该成员关系好像是由该角色本身授予的一样)。

GRANT以及REVOKE也可以由一个不是受影响对象拥有者的角色完成,不过该角色是拥有该对象的角色的一个成员,或者是在该对象上持有特权的WITH GRANT OPTION的角色的一个成员。

在这种情况下,特权将被记录为由实际拥有该对象的角色授予或者是由持有特权的WITH GRANT OPTION的角色授予。例如,如果表t1被角色g1拥有,u1是它的一个成员,那么u1可以把t1上的特权授予给u2,但是那些特权将好像是直接由g1授予的。角色g1的任何其他成员可以稍后撤回它们。

如果执行GRANT的角色间接地通过多于一条角色成员关系路径持有所需的特权,将不会指定哪一个包含它的角色将被记录为完成了该授权。在这样的情况中,最好使用SET ROLE来成为你想用其做GRANT的特定角色。

授予一个表上的权限不会自动地扩展权限给该表使用的任何序列,包括绑定在SERIAL列上的序列。序列上的权限必须被独立设置。

例子

把表films上的插入特权授予给所有用户:

GRANT INSERT ON films TO PUBLIC;

把视图kinds上的所有可用特权授予给用户manuel:

GRANT ALL PRIVILEGES ON kinds TO manuel;

注意虽然上述语句被一个超级用户或者kinds的拥有者执行时确实会授予所有特权,但是当由其他人执行时将只会授予那些执行者拥有授权选项的权限。

把角色admins中的成员关系授予给用户joe:

GRANT admins TO joe;

参见

REVOKE, ALTER DEFAULT PRIVILEGES

IMPORT FOREIGN SCHEMA​

IMPORT FOREIGN SCHEMA --- 从一个外部服务器导入表定义

大纲

IMPORT FOREIGN SCHEMA remote_schema
[ { LIMIT TO | EXCEPT } ( table_name [, ...] ) ]
FROM SERVER server_name
INTO local_schema
[ OPTIONS ( option 'value' [, ... ] ) ]

简介

IMPORT FOREIGN SCHEMA创建表示存在于外部服务器上的表的外部表。新外部表将由发出该命令的用户所拥有并且用匹配远程表的正确的列定义和选项创建。

默认情况下,存在于外部服务器上一个特定模式中的所有表和视图都会被导入。根据需要,表的列表可以被限制到一个指定的子集,或者可以排除特定的表。新外部表都被创建在一个必须已经存在的目标模式中。

要使用IMPORT FOREIGN SCHEMA,用户必须具有外部服务器上的USAGE特权以及在目标模式上的 CREATE特权。

参数

remote_schema

要从哪个远程模式导入。一个远程模式的特定含义依赖于所使用的外部数据包装器。

**LIMIT TO ( table_name [, ...] )**

只导入匹配给定表名之一的外部表。外部模式中其他的表将被忽略。

**EXCEPT ( table_name [, ...] )**

把指定的外部表排除在导入之外。除了列在这里的表之外,外部模式中存在的所有表都将被导入。

server_name

要从哪个外部服务器导入。

local_schema

被导入的外部表将创建在其中的模式。

**OPTIONS ( option 'value' [, ...] )**

要在导入期间使用的选项。允许使用的选项名称和值与每一个外部数据包装器有关。

示例

从服务器film_server上的远程模式foreign_films 中导入表定义,把外部表创建在本地模式films中:

IMPORT FOREIGN SCHEMA foreign_films
FROM SERVER film_server INTO films;

同上,但是只导入两个表actors和 directors(如果存在):

IMPORT FOREIGN SCHEMA foreign_films LIMIT TO (actors, directors)
FROM SERVER film_server INTO films;

另见

CREATE FOREIGN TABLE, CREATE SERVER

INSERT​

INSERT --- 在一个表中创建新行

大纲

[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
[ OVERRIDING { SYSTEM | USER } VALUE ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...]
| query }
[ ON CONFLICT [ conflict_target ] conflict_action ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

其中 conflict_target 可以是以下之一:

( { index_column_name | ( index_expression ) } [ COLLATE collation ]
[ opclass ] [, ...] ) [ WHERE index_predicate ]
ON CONSTRAINT constraint_name

并且 conflict_action 是以下之一:

DO NOTHING
DO UPDATE SET { column_name = { expression | DEFAULT } |
( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT }
[, ...] ) |( column_name [, ...] ) = ( sub-SELECT )
} [, ...]
[ WHERE condition ]

描述

INSERT将新行插入到一个表中。我们可以插入一个或者更多由值表达式指定的行,或者插入来自一个查询的零行或者更多行。

目标列的名称可以以任意顺序列出。如果没有给出列名列表,则有两种确定 目标列的可能性。第一种是以被声明的顺序列出该表的所有列。另一种可能 性是,如果VALUES 子句或者query只提供N个列,则以被声明的顺序列出该表的前 N列。VALUES 子句或者 query提供的值会被从左至右关联到这些显式或者隐式 给出的目标列。

每一个没有出现在显式或者隐式列列表中的列都将被默认填充,如果为该列 声明过默认值则用默认值填充,否则用空值填充。

如果任意列的表达式不是正确的数据类型,将会尝试自动类型转换。

ON CONFLICT可以用来指定发生唯一约束或者排除约束违背错误时的替换动作(见下文的ON CONFLICT Clause)。

可选的RETURNING子句让INSERT根据实际被插入(如果使用了ON CONFLICT DO UPDATE子

句,可能是被更新)的每一行来计算和返回值。这主要用来获取由默认值提的值,例如一个序列号。不过,允许在其中包括使用该表列的任何表达式。 RETURNING列表的语法与SELECT的输出列表的相同。只有被成功地插入或者更新的行才将被返回。例如,如果一行被锁定但由于不满足ON CONFLICT DO UPDATE ... WHERE clause condition没有被更新,

该行将不被返回。

为了向表中插入,你必须具有其上的INSERT特权。如果存在ON CONFLICT DO UPDATE子句,还要求该表上的UPDATE特权。

如果一个列列表被指定,你只需要其中的列上的INSERT特权。类似地,在指定了ON CONFLICT DO UPDATE时,你只需要被列出要更新的列上的UPDATE特权。不过,ON CONFLICT DO UPDATE还要求其值被 ON CONFLICT DO UPDATE表达式或者 condition使用的列上的SELECT特权。

使用RETURNING子句需要RETURNING中提到的所有列的 SELECT权限。如果使用 query子句从查询中插入行,则当然需要对查询中使用的任何表或列具有SELECT权限。

参数

插入

这个小节介绍了在只插入新行时可以使用的参数。 专门用于ON CONFLICT子句的参数会单独介绍。

with_query

WITH子句允许指定一个或者更多子查询,在 INSERT查询中可以用名称引用这些子查询。

query (SELECT语句)也可以包含一个 WITH子句。在这种情况下 query中可以引用两组with_query,但是第二个优先级更高(因为它被嵌套更近)。

table_name

一个已有表的名称(可以被模式限定)。

alias

table_name 的替补名称。当提供了一个别名时,它会完全隐藏掉表的实际名称。 当ON CONFLICT DO UPDATE的目标是一个被排除的表时这特别有用,因为那将被当作表示要被插入行的特殊表的名称。

column_name

名为table_name的表中的一个列的名称。如有必要,列名可以用一个子域名或者数组下标限定(指向一个组合列的某些列中插入会让其他域为空)。当用 ON CONFLICT DO UPDATE引用一列时,不要在一个目标列的说明中国包括表名。例如,INSERT INTO

table_name ... ON CONFLICT DO UPDATE SET table_name.col = 1是非法的(这遵循UPDATE 的一般行为)。

OVERRIDING SYSTEM VALUE

如果指定了此子句,那么为标识列提供的任何值都将覆盖默认的序列生成的值。

对于定义为GENERATED ALWAYS的标识列,插入显式值(DEFAULT除外)而不指定OVERRIDING SYSTEM VALUE或OVERRIDING USER VALUE是错误的。(对于定义为GENERATED BY DEFAULT的标识列,OVERRIDING SYSTEM VALUE是正常行为,并指定其不执行任何操

作,但是Halo允许它作为扩展名。)

OVERRIDING USER VALUE

如果指定了此子句,则将忽略为标识列提供的任何值,并应用默认的序列生成的值。

例如,当在表之间拷贝值时,这个子句有能派上用场。INSERT INTO tbl2 OVERRIDING USER VALUE SELECT * FROM tbl1将从tbl1中拷贝所有在tbl2中不是标识列的列,而tbl2中标识列的值将由与tbl2关联的序列产生。

DEFAULT VALUES

所有列都将被其默认值填充,就像为每个列显式指定了DEFAULT。 (例如这种形式下不允许OVERRIDING子句)。

expression

要赋予给相应列的表达式或者值。

DEFAULT

相应的列将填充其默认值。标识列将由关联序列生成的新值填充。对于生成的列,允许指定该值,但仅指定根据其生成表达式计算该列的正常行为。

query

提供要被插入行的查询(SELECT语句)。 其语法描述请参考SELECT语句。

output_expression

在每一行被插入或更新后由INSERT命令计算并且返回的表达式。该表达式可以使用table_name 指定的表中的任何列。写成*可返回被插入或更新行的所有列。

output_name

要用于被返回列的名称。

ON CONFLICT 子句

可选的ON CONFLICT子句为出现唯一性违背或排除约束违背错误时提供另一种可供选择的动作。对于每一个要插入的行,不管是插入进行下去还是由conflict_target 指定的一个仲裁者约束或者索引被违背,都会采取可供选择的conflict_action。ON CONFLICT DO NOTHING简单地把避免插入行。 ON CONFLICT DO UPDATE则会更新与要插入的行冲突的已有行。

conflict_target可以执行 唯一索引推断。在执行推断时,它由一个或者多个index_column_name 列或者 index_expression 表达式以及一个可选的 index_predicate构成。所有刚好包含 conflict_target指定的列/表达式的table_name唯一索引(不管顺序)

都会被推断为(选择为)仲裁者索引。如果指定了 index_predicate,它必须满足仲裁者索引(也是推断过程的一个进一步的要求)。注意这意味着如果 有一个满足其他条件的非部分唯一索引(没有谓词的唯一索引)可用,它将被推断为仲裁者(并且会被ON CONFLICT使用)。如果推断尝试不成功,则会发生一个错误。

ON CONFLICT DO UPDATE保证一个原子的 INSERT或者 UPDATE结果。在没有无关错误的前提下,这两种结果之一可以得到保证,即使在很高的并发度也能保证。这也可以被称作UPSERT --- "UPDATE 或 INSERT"。

conflict_target

通过选择仲裁者索引来指定哪些行与 ON CONFLICT在其上采取可替代动作的行相冲突。

要么执行唯一索引推断,要么显式命名一个约束。对于ON CONFLICT DO NOTHING来说,它对于指定一个conflict_target是可选的。 在被省略时,与所有有效约束(以及唯一索引)的冲突都会被处理。对于 ON CONFLICT DO UPDATE,必须提供一个conflict_target。

conflict_action

conflict_action指定一个可替换的 ON CONFLICT动作。它可以是 DO NOTHING,也可以是一个指定在冲突情况下要被执行的UPDATE动作细节的DO UPDATE子句。ON CONFLICT DO UPDATE中的SET和 WHERE子句能够使用该表的名称(或者别名)访问现有的行,并且可以用特殊的被排除表访问要插入的行。这个动作要求被排除列所在目标表的任何列上的SELECT特权。

注意所有行级BEFORE INSERT触发器的效果都会反映在被排除值中,因为那些效果可能会让该行避免被插入。

index_column_name

一个table_name列的名称。它被用来推断仲裁者索引。它遵循CREATE INDEX格式。这要求 index_column_name 上的SELECT特权。

index_expression

和index_column_name类似,但是被用来推断出现在索引定义中的table_name列(非简单列)上的表达式。遵循CREATE INDEX格式。这要求任何出现在index_expression中的列上的 SELECT特权。

collation

指定时,强制相应的index_column_name或 index_expression 使用一种特定的排序规则以便在推断期间能被匹配上。通常会被省略,因为排序规则通常不会影响约束违背的发生。遵循 CREATE INDEX格式。

opclass

指定时,强制相应的index_column_name或 index_expression 使用特定的操作符类以便在推断期间能被匹配上。通常会被省略,因为相等语义在一种类型的操作符类之间都是等价的,或者因为足以信任已定义的唯一索引具有适当的相等定义。遵循CREATEINDEX格式。

index_predicate

用于允许推断部分唯一索引。任何满足该谓词(不一定需要真的是部分索引)的索引都能被推断。遵循CREATE INDEX格式。这要求任何出现在index_predicate中的列上的SELECT特权。

constraint_name

用名称显式地指定一个仲裁者约束,而不是推断一个约束或者索引。

condition

一个能返回boolean值的表达式。只有让这个表达式返回 true的行才将被更新,不过在采用 ON CONFLICT DO UPDATE动作时所有的行都会被锁定。注意condition会被最后计算,即一个冲突被标识为要更新的候选对象之后。

注意不支持把排除约束作为ON CONFLICT DO UPDATE的仲裁者。在所有的情况中,只支持NOT DEFERRABLE约束和唯一索引作为仲裁者。

带有ON CONFLICT DO UPDATE子句的 INSERT是一种"确定性的"语句。这表明不允许该命令影响任何单个现有行超过一次,如果发生则会发生一个基数违背错误。要插入的行不应该在仲裁者索引或约束所限制的属性上相重复。

注意,当前不支持用分区表上的INSERT的ON CONFLICT DO UPDATE子句更新冲突行的分区键,因为那样会让行移动到新的分区中。

提示:使用唯一索引推断通常比使用ON CONFLICT ON CONSTRAINT constraint_name直接提名一个约束更好。当底层索引被以重叠方式替换成另一个或多或少等效的索引时,推断将能继续正确地工作,例如在删除要被替换的索引之前使用CREATE UNIQUE INDEX ... CONCURRENTLY。

输出

成功完成时,INSERT命令会返回以下形式的命令标签:

INSERT oid count

count是被插入或更新的行数。oid总是0(过去,如果count恰好为1, 并且目标表被声明为WITH OIDS,则它是分配给插入行的OID,否则为0,但现在已不再支持创建WITH OIDS表)。

如果INSERT命令包含RETURNING子句,其结果会类似于包含RETURNING列表中定义的列和值的 SELECT语句,这些结果是由该命令在被插入或更新行上计算得到。

注解

如果指定的表是一个分区表,每一行都会被路由到合适的分区并且插入其中。如果指定的表是一个分区,如果输入行之一违背该分区的约束则将发生错误。

示例

向films中插入一行:

INSERT INTO films VALUES
('UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes');

在这个例子中,len列被省略并且因此会具有默认值:

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

这个例子为日期列使用DEFAULT子句而不是指定一个值:

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

插入一个完全由默认值构成的行:

INSERT INTO films DEFAULT VALUES;

用多行VALUES语法插入多个行:

INSERT INTO films (code, title, did, date_prod, kind) VALUES
('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');

这个例子从表tmp_films中获得一些行插入到表 films中,两个表具有相同的列布局:

INSERT INTO films SELECT * FROM tmp_films WHERE date_prod < '2004-05-07';

这个例子插入数组列:

-- 为 noughts-and-crosses 游戏创建一个空的 3x3 棋盘
INSERT INTO tictactoe (game, board[1:3][1:3])
VALUES (1, '{{" "," "," "},{" "," "," "},{" "," "," "}}');
-- 实际上可以不用上面例子中的下标:
INSERT INTO tictactoe (game, board)
VALUES (2, '{{X," "," "},{" ",O," "},{" ",X," "}}');

向表distributors中插入一行,返回由 DEFAULT子句生成的序号:

INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
RETURNING did;

增加为 Acme Corporation 管理账户的销售人员的销量,并且把整个被更新的行以及当前时间记录到一个日志表中:

WITH upd AS (
UPDATE employees SET sales_count = sales_count + 1 WHERE id =
(SELECT sales_person FROM accounts WHERE name = 'Acme Corporation')
RETURNING * )
INSERT INTO employees_log SELECT *, current_timestamp FROM upd;

酌情插入或者更新新的 distributor。假设已经定义了一个唯一索引来约束 出现在did列中的值。注意,特殊的 excluded表被用来引用原来要插入的值:

INSERT INTO distributors (did, dname)
VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
ON CONFLICT (did) DO UPDATE SET dname =EXCLUDED.dname;

插入一个 distributor,或者在一个被排除的行(具有一个匹配约束的列或者 会让行级前(或者后)插入触发器引发的列的行)存在时不处理要插入的行。 例子假设已经定义了一个唯一触发器来约束出现在did列中的值:

INSERT INTO distributors (did, dname) VALUES (7, 'Redline GmbH')
ON CONFLICT (did) DO NOTHING;

酌情插入或者更新新的 distributor。例子假设已经定义了一个唯一触发器来约束出现在did列中的值。WHERE子句被用来限制实际被更新的行(不过,任何没有被更新的已有行仍将被锁定):

-- 根据一个特定的 ZIP 编码更新 distributors
INSERT INTO distributors AS d (did, dname) VALUES (8, 'Anvil Distribution')
ON CONFLICT (did) DO UPDATE
SET dname = EXCLUDED.dname || ' (formerly ' || d.dname || ')'
WHERE d.zipcode <> '21201';
-- 直接在语句中命名一个约束(使用相关的索引来判断是否做
-- DO NOTHING 动作)
INSERT INTO distributors (did, dname) VALUES (9, 'Antwerp Design')
ON CONFLICT ON CONSTRAINT distributors_pkey DO NOTHING;

如果可能就插入新的 distributor,否则DO NOTHING。例子假设已经定义了一个唯一索引,它约束让is_active 布尔列为true的行子集上did列中的值:

-- 这个语句可能推断出一个在 "did" 上带有谓词 "WHERE is_active"
-- 的部分唯一索引,但是它可能也只是使用了 "did" 上的一个常规唯一约束
INSERT INTO distributors (did, dname) VALUES (10, 'Conrad International')
ON CONFLICT (did) WHERE is_active DO NOTHING;

LISTEN​

LISTEN --- 监听一个通知

大纲

LISTEN channel

描述

LISTEN在名为channel的通知频道上将当前会话注册为一个监听者。如果当前会话已经被注册为这个通知频道的一个监听者,则什么也不会发生。

只要命令NOTIFY channel被调用(不管是在这个会话还是在另一个连接到同一数据库的会话中),所有当前正在该通知频道上监听的会话都会被通知,并且每一个会话将会接着通知连接到它的客户端应用。

可以使用UNLISTEN命令在一个给定通知频道上反注册一个会话。当会话结束时,它的监听注册会被自动清除。

一个客户端应用检测通知事件的必用方法取决于它使用的Halo应用编程接口。如果使用libpq库,应用会将LISTEN作为一个普通 SQL 命令发出,并且接着必须周期性地调用函数PQnotifies来查看是否接收到通知事件。其他诸如libpgtcl的接口提供了更高层次上的处理通知事件的方法。事实上,通过使用libpgtcl应用程序员甚至不必直接发出LISTEN或UNLISTEN。更多细节可参阅所使用的接口的文档。

参数

channel

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

注解

LISTEN在事务提交时生效。如果在一个后来被回滚的事务中执行了LISTEN或UNLISTEN,被监听的通知频道集合不会变化。

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

第一次设置侦听会话时有一个竞争条件:如果并发提交的事务正在发送通知事件,那么新的侦听会话将接收哪些事件?答案是,会话将接收在事务提交步骤中的一瞬间之后所有提交的事件。但这比事务在查询中可能观察到的任何 数据库状态都要晚一些。这将导致使用LISTEN的以下规则:首先执行(并提交!)该命令,然后在一个新事务中根据应用程序逻辑的需要检查数据库状态,然后依靠通知来了解数据库状态的后续更改。最初收到的几个通知可能涉及在初始数据库检查中已经观察到的更新,但这通常是无害的。

NOTIFY对LISTEN和NOTIFY的使用进行了更广泛的讨论。

例子

从psql中配置并执行一个监听/通知序列

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

参见

NOTIFY, UNLISTEN

LOAD​

LOAD --- 载入一个共享库文件

大纲

LOAD 'filename'

描述

这个命令把一个共享库文件载入到Halo服务器的地址空间中。如果该文件已经被载入这个命令什么也不会做。只要调用包含 C 函数的共享库文件中的一个函数,这些共享库文件就会被自动载入。因此,一次显式的LOAD通常只在载入一个通过"钩子"修改服务器行为而不是提供一组函数的库时需要。

库文件名通常只是一个裸文件名,在服务器的库搜索路径(由 dynamic_library_path设置)中寻找。或者,它可以作为完整的路径名称给出。无论哪种情况,平台的标准共享库文件扩展名都可以省略。

非超级用户只能把LOAD应用在位于 $libdir/plugins/中的库文件 --- 指定的 filename 必须正好以该字符串开始(确保在那里只安装了"安全的"库是数据库管理员的责任)。

另见

CREATE FUNCTION

LOCK​

LOCK --- 锁定一个表

大纲

LOCK [ TABLE ] [ ONLY ] name [ * ] [, ...] [ IN lockmode MODE ] [ NOWAIT ]

其中 lockmode 可以是以下之一:

ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE

描述

LOCK TABLE获得一个表级锁,必要时会等待任何冲突锁被释放。如果指定了NOWAIT, LOCK TABLE不会等待以获得想要的锁:如果它不能立刻得到,该命令会被中止并且发出一个错误。一旦获取到,该锁会被在当前事务中一直持有(没有UNLOCK TABLE命令,锁总是在事务结束时被释放)。

当一个视图被锁定时,出现在该视图定义查询中的所有关系也将被使用同样的锁模式递归地锁住。

在为引用表的命令自动获取锁时,Halo总是尽可能使用最不严格的锁模式。

提供LOCK TABLE是用于想要更严格的锁定的情况。例如,假设一个应用运行一个READ COMMITTED 隔离级别的事务,并且需要确保一个表中的数据在该事务的期间保持稳定。要实现这个目的,必须在查询之前在表上获得SHARE锁模式。这将阻止并发的数据更改并且确保该表的后续读操作会看到已提交数据的一个稳定视图, 因为SHARE锁模式与写入者所要求的

ROW EXCLUSIVE锁有冲突,并且你的 LOCK TABLE name IN SHARE MODE 语句将等待,直到任何并发持有ROW EXCLUSIVE模式锁的持有者提交或者回滚。因此,一旦得到锁,就不会有未提交的写入还没有解决。更进一步,在释放该锁之前,任何人都不能开始。

要在运行在REPEATABLE READ或SERIALIZABLE 隔离级别的事务中得到类似的效果,你必须在执行任何 SELECT或者数据修改语句之前执行 LOCK TABLE语句。一个 REPEATABLE READ或者SERIALIZABLE事务的数据视图将在它的第一个SELECT或者数据修改语句开始时被冻结。

在该事务中稍后的一个LOCK TABLE仍将阻止并发写 --- 但它不会确保该事务读到的东西对应于最新的已提交值。

如果一个此类事务正要修改表中的数据,那么它应该使用 SHARE ROW EXCLUSIVE锁模式来取代 SHARE模式。这会保证一次只有一个此类事务运行。如果 不用这种模式,死锁就可能出现:两个事务可能都要求 SHARE模式,并且都不能获得 ROW EXCLUSIVE模式来真正地执行它们的更新(注意一个 事务所拥有的锁不会冲突,因此一个事务可以在它持有SHARE 模式时获得ROW EXCLUSIVE模式 --- 但是如果有其他人持有SHARE模式时则不能)。为了避免死锁,确保所有的事务在同样的对象上以相同的顺序获得锁,并且如果在一个对象上涉及多种锁模式,事务应该总是首先获得最严格的那种模式。

参数

name

要锁定的一个现有表的名称(可以是模式限定的)。如果在表名前指定了 ONLY,只有该表会被锁定。如果没有指定了 ONLY,该表和它所有的后代表(如果有)都会被锁定。可选地,在表名后指定*来显式地表示把后代表包括在内。

命令LOCK TABLE a, b;等效于 LOCK TABLE a; LOCK TABLE b;。这些表会被按照在 LOCK TABLE中指定的顺序一个一个被锁定。

lockmode

锁模式指定这个锁和哪些锁冲突。

如果没有指定锁模式,那儿将使用最严格的模式ACCESS EXCLUSIVE。

NOWAIT

指定LOCK TABLE不等待任何冲突锁被释放:如果所指定的锁不能立即获得,那么事务就会中止。

注解

LOCK TABLE ... IN ACCESS SHARE MODE要求目标表上的SELECT特权。LOCK TABLE ... IN ROW EXCLUSIVE MODE要求目标表上的INSERT、UPDATE、DELETE或TRUNCATE特权。所有其他形式的LOCK要求表级UPDATE、DELETE或TRUNCATE特权。

在该视图上执行锁定的用户必须具有该视图上相应的特权。此外视图的拥有者必须拥有底层基关系上的相关特权,但是执行锁定的用户不需要底层基关系上的任何权限。

LOCK TABLE在一个事务块外部没有用处:锁将只保持到语句完成。因此如果在一个事务块外部使用了LOCK,Halo会报告一个错误。使用BEGIN和COMMIT(或者ROLLBACK)定义一个事务块。

LOCK TABLE只处理表级锁,因此涉及到 ROW的模式名称在这里都是不当的。这些模式名称应该通常被解读为用户在被锁定表中获取行级锁的意向。还有, ROW EXCLUSIVE模式是一个可共享的表锁。记住就 LOCK TABLE而言,所有的锁模式都具有相同的语义,只有模式的冲突规则有所不同。关于如何获取一个真正的行级锁的信息,请见SELECT文档中的The Locking Clause。

示例

在将要向一个外键表中执行插入时在主键表上获得一个 SHARE锁:

BEGIN WORK;
LOCK TABLE films IN SHARE MODE;
SELECT id FROM films
WHERE name = 'Star Wars: Episode I - The Phantom Menace';
-- 如果记录没有被返回就做 ROLLBACK
INSERT INTO films_user_comments VALUES
(_id_, 'GREAT! I was waiting for it for so long!');
COMMIT WORK;

在将要执行一次删除操作前在主键表上取一个 SHARE ROW EXCLUSIVE锁:

BEGIN WORK;
LOCK TABLE films IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM films_user_comments WHERE id IN
(SELECT id FROM films WHERE rating < 5);
DELETE FROM films WHERE rating < 5;
COMMIT WORK;

MOVE​

MOVE --- 定位一个游标

大纲

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重新定位一个游标而不检索任何数据。 MOVE的工作完全像 FETCH命令,但是它只定位游标并且不返回行。

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

输出

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

MOVE count

count是一个 具有同样参数的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;

另见

CLOSE, DECLARE, FETCH

NOTIFY​

NOTIFY --- 生成一个通知

大纲

NOTIFY channel [ , payload ]

描述

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

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

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

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

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

NOTIFY以一些重要的方式与 SQL 事务互动。首先,如果一个NOTIFY在一个事务内执行,在事务被提交之前,该通知事件都不会被递送。这是合适的,因为如果该事务被中止,所有其中的命令都将不会产生效果,包括NOTIFY在内。但如果期望通知事件被立即递送,那这种行为就会令人不安。其次,如果一个监听会话收到了一个通知信号而它正在一个事务中,在该事

务完成(提交或者中止)之前,该通知事件将不会被递送给它连接的客户端。同样,原因在于如果一个通知在一个事务内被递送且该事务后来被中止,我们会希望该通知能以某种方式被撤销 --- 但是服务器一旦把通知发送给客户端就无法"收回它"。因此通知事件只能在事务之间递送。其中的要点是把NOTIFY用作实时信号的应用应该让它们事务尽可能短小。

如果在同一事务中使用相同的有效负载字符串多次向同一通道名称发送信号,则只向侦听器传递通知事件的一个实例。另一方面,带有不同载荷字符串的通知将总是作为不同的通知被递送。类似地,来自不同事务的通知将不会被折叠成一个通知。除了丢弃后来生成的重复通知实例之外,NOTIFY保证来自同一个事务的通知按照它们被发送的顺序被递送。还可以保证的是,来自不同事务的消息会按照其事务被提交的顺序递送。

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

参数

channel

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

payload

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

注解

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

函数pg_notification_queue_usage返回队列中当前被待处理通知所占据的比例。

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

pg_notify

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

例子

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

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 pg_notify('fo' || 'o', 'pay' || 'load');
Asynchronous notification "foo" with payload "payload" received from server
process with PID 14728.

参见

LISTEN, UNLISTEN

PREPARE​

PREPARE --- 为执行准备一个语句

大纲

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

描述

PREPARE创建一个预备语句。预备语句是一种服务器端对象,它可以被用来优化性能。

当PREPARE语句被执行时,指定的语句会被解析、分析并且重写。当后续发出一个EXECUTE命令时,该预备语句会被规划并且执行。这种工作的划分避免了重复性的解析分析工作,不过允许执行计划依赖所提供的特定参数值。

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

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

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

参数

name

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

data_type

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

statement

任何SELECT、INSERT、UPDATE、DELETE或者VALUES语句。

注解

可以使用generic plan或custom plan执行已准备好的语句。 通用计划在所有执行中都是相同的,而自定义计划是为特定执行所生成的,使用调用中给出的参数值。使用通用计划可以避免计划开销,但在某些情况下,自定义计划的执行效率要高得多,因为规划器可以利用参数值的知识。(当然,如果准备好的语句没有参数,则这是没有意义的,并且始终应使用通用计划。)

默认情况下(也就是当 plan_cache_mode 设定为 auto时),对已经准备好的具有参数的语句,服务器将自动选择使用通用或自定义计划。当前的规则是,前五次执行都是使用自定义计划完成的,并且计算这些计划的平均估计成本。然后创建通用计划,并将其估计成本与自定义计划的平均成本相比较。如果通用计划的成本没有比平均自定义计划成本高太多,那么后续执行将使用通用计划,以使重复的再看起来更可取。

这种探索式方法可以重写,强迫服务器使用通用或自定义计划,通过将plan_cache_mode分别设置为force_generic_plan或 force_custom_plan 。 如果通用计划的成本估计由于某种原因很不理想,则此设置主要很有用,尽管其实际成本远高于自定义计划的实际成本,可以

选择此设置。

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

EXPLAIN EXECUTE name(parameter_values);

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

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

不过,如果某些其他更改造成了重解析,后续使用中都会引用新表。

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

例子

为一个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的环境中推知。

另见

DEALLOCATE, EXECUTE

PREPARE TRANSACTION​

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

大纲

PREPARE TRANSACTION transaction_id

描述

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

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

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

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

参数

transaction_id

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

注解

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

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

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

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

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

小心:让一个事务处于准备好状态太久是不明智的。这将会干扰 VACUUM回收存储的能力,并且在极限情况下可能导致数据库关闭以阻止事务 ID 回卷。 还要记住,该事务会继续持有它已经持有的锁。该特性的设计用法是,只要一个外部事务管理器已经验证其他数据库也准备好了要提交,一个准备好的事务将被正常地提交或者回滚。 如果没有建立一个外部事务管理器来跟踪准备好的事务并且确保它们被迅速地结束,最好禁用准备好事务特性(设置 max_prepared_transactions为零)。这将防止意外地创建准备好事务,不然该事务有可能被忘记并且最终导致问题。

例子

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

PREPARE TRANSACTION 'foobar';

另见

COMMIT PREPARED, ROLLBACK PREPARED

REASSIGN OWNED​

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

大纲

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

描述

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

参数

old_role

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

new_role

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

注解

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

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

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

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

另见

DROP OWNED, DROP ROLE, ALTER DATABASE

REFRESH MATERIALIZED VIEW​

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

大纲

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

描述

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

CONCURRENTLY和WITH NO DATA 不能被一起指定。

参数

CONCURRENTLY

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

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

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

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

name

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

注解

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

示例

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

REFRESH MATERIALIZED VIEW order_summary;

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

REFRESH MATERIALIZED VIEW annual_statistics_basis WITH NO DATA;

另见

CREATE MATERIALIZED VIEW, ALTER MATERIALIZED VIEW, DROP MATERIALIZED VIEW

REINDEX​

REINDEX --- 重建索引

大纲

REINDEX [ ( option [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM }
[ CONCURRENTLY ] name

其中选项可以是以下之一:

VERBOSE

描述

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

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

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

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

• 如果索引在用CONCURRENTLY选项创建失败,该索引保留为一个"invalid"。 这类索引是无用的,但是可以方便的用REINDEX来重建它们。注意,只有REINDEX INDEX可以在无效的索引上执行并发创建。

参数

INDEX

重新创建指定的索引。

TABLE

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

SCHEMA

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

DATABASE

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

SYSTEM

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

name

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

CONCURRENTLY

使用此选项时,Halo将重建索引,而不在表上采取任何阻止并发插入、更新或删除的锁; 标准的索引重建将会锁定表上的写操作(而不是读操作),直到它完成。使用此选项---时,有几个事项需要注意;请参阅下面的Rebuilding Indexes Concurrently。

对于临时表,REINDEX始终是非并发的,因为没有其他会话可以访问它们,并且非并发重新索引更便宜。

VERBOSE

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

注解

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

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

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

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

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

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

不支持重建分区表的索引或者分区索引。不过可以单独为每个分区重建索引。

Rebuilding Indexes Concurrently

重建索引可能会影响数据库的常规操作。通常Halo会锁定重建的表以防止写操作,并通过单次扫描表来执行整个索引构建。其他事务仍可以读取表,但如果它们尝试在表中插入、更新或删除行,它们将被阻止,直到索引重建完成。如果系统是实时生产数据库,这可能会产生严重影响。非常大的表可能需要几个小时才能编制索引,即使对于较小的表,索引重建也会锁定编写器,这些时间段对于生产系统来说是不可接受的。

Halo支持以最少的写入锁定来重建索引。此方法通过指定REINDEX的CONCURRENTLY选项来调用。使用此选项时,Halo必须对需要重新生成的每个索引执行两次表扫描,并等待可能使用索引的所有现有事务的终止。此方法需要比标准索引重建更大的工作量,并且需要相当长的时间才能完成,因为它需要等待可能修改索引的未完成的事务。但是,由于它允许在重建索引时继续正常操作,此方法可用于在生产环境中重建索引。当然,重建索引所需的额外 CPU、内存和 I/O 负载可能会减慢其他操作的速度。

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

1. 新的临时索引定义将添加到目录pg_index中。此定义将用于替换旧索引。 一个SHARE UPDATE EXCLUSIVE会话级别的锁将放在要重建的索引以及其关联的表上,以防止处理时的任何模式修改。

2. 为每个新索引完成生成索引的首个操作。生成索引后,其标志pg_index.indisready切换到"true"使其准备好插入,使其在执行生成的事务完成后对其他会话可见。此步骤在每个索引的单独事务中完成。

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

4. 引用索引的所有约束都已更改以引用新的索引定义,并且索引名称也已经更改。此时,pg_index.indisvalid会为新索引切换到"true",以及为旧索引切换到"false",并且缓存无效会导致引用旧索引的所有会话失效。

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

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

如果在重建索引时出现问题,例如唯一索引中的唯一性冲突,REINDEX命令将失败,但会留下一个"invalid"新索引,在已经存在的索引之外。出于查询目的此索引将被忽略,因为它可能不完整;但是它仍将消耗更新开销。psql \d命令将此类索引报告为 INVALID:

halo0root=# \\d tab
Table "public.tab"
Column | Type | Modifiers
--------+---------+-----------
col | integer |

Indexes:

"idx" btree (col)

"idx_ccnew" btree (col) INVALID

如果标记为INVALID的索引后缀为ccnew,那么它对应的是并发操作时创建的临时索引,推荐的恢复方法是使用DROP INDEX删除,然后再次尝试 REINDEX CONCURRENTLY。如果无效索引改为后缀ccold,则对应于无法删除的原始索引; 推荐的恢复方法是删除所述索引,因为正确的重建已经成功。

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

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

此外,排除约束的索引不能并发重新编制索引。如果此命令中直接命名了这样的索引,则会引发错误。如果并发重新编制具有排除约束索引的表或数据库,将跳过这些索引。(它可以不使用CONCURRENTLY选项来重新编制这样的索引)。

示例

重建单个索引:

REINDEX INDEX my_index;

重建表my_table上的所有索引:

REINDEX TABLE my_table;

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

$ export PGOPTIONS="-P"

$ psql broken_db

...

broken_db=> REINDEX DATABASE broken_db;
broken_db=> \\q

重建表的索引,在重建索引过程中不阻止对相关关系进行读写操作:

REINDEX TABLE CONCURRENTLY my_broken_table;

RELEASE SAVEPOINT​

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

大纲

RELEASE [ SAVEPOINT ] savepoint_name

描述

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

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

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

参数

savepoint_name

要销毁的保存点的名称。

注解

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

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

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

示例

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

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

上述事务将插入3和4。

另见

BEGIN, COMMIT, ROLLBACK, ROLLBACK TO SAVEPOINT, SAVEPOINT

RESET​

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

大纲

RESET configuration_parameter
RESET ALL

描述

RESET把运行时参数恢复到它们的默认值。RESET是SET configuration_parameter TO DEFAULT的另一种写法。详见SET。

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

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

参数

configuration_parameter

一个可设置的运行时参数名称。

ALL

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

示例

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

RESET timezone;

另见

SET, SHOW

REVOKE​

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 role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | REFERENCES } ( column_name [, ...] )
[, ...] | ALL [ PRIVILEGES ] ( column_name [, ...] ) }
ON [ TABLE ] table_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { USAGE | SELECT | UPDATE }
[, ...] | ALL [ PRIVILEGES ] }
ON { SEQUENCE sequence_name [, ...]
| ALL SEQUENCES IN SCHEMA schema_name [, ...] }
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
ON DATABASE database_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN domain_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER fdw_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN SERVER server_name [, ...]
FROM role_specification [, ...]
[ 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 role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE lang_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
ON LARGE OBJECT loid [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
ON SCHEMA schema_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE tablespace_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON TYPE type_name [, ...]
FROM role_specification [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ ADMIN OPTION FOR ]
role_name [, ...] FROM role_specification [, ...]
[ GRANTED BY role_specification ]
[ CASCADE | RESTRICT ]
where role_specification can be:
[ GROUP ] role_name
| PUBLIC
| CURRENT_USER
| SESSION_USER

描述

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

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

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

色仍有SELECT权利,该用户还是可以使用 SELECT。

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

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

在回收一个表上的特权时,也会在该表的每一个列上自动回收对应的列特权(如果有)。

在另一方面,如果一个角色已经被授予一个表上的特权,那么从个别的列上回收同一个特权将不会生效。

在回收一个角色中的成员关系时,GRANT OPTION被改 称为ADMIN OPTION,但行为是类似的。

这种形式的命令也允许使用 GRANTED BY 选项,但该选项当前被忽略(除了检查指定角色的存在)。也要注意这种形式的命令不允许在 role_specification 中使用噪声词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的特定角色。如果无法做到这一点可能会导致回收超过你预期的特权,或者根本回收不了任何东西。

示例

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

REVOKE INSERT ON films FROM PUBLIC;

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

REVOKE ALL PRIVILEGES ON kinds FROM manuel;

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

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

REVOKE admins FROM joe;

另见

GRANT, ALTER DEFAULT PRIVILEGES

ROLLBACK​

ROLLBACK --- 中止当前事务

大纲

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

描述

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

参数

WORK

TRANSACTION

可选关键词,没有效果。

AND CHAIN

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

注解

使用COMMIT可成功地终止一个事务。

在一个事务块之外发出ROLLBACK会发出一个警告并且不会有效果。事务块之外的ROLLBACK AND CHAIN 是一个错误.

示例

要中止所有更改:

ROLLBACK;

另见

BEGIN, COMMIT, ROLLBACK TO SAVEPOINT

ROLLBACK PREPARED​

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

大纲

ROLLBACK PREPARED transaction_id

描述

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

参数

transaction_id

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

注解

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

但是你必须处在执行该事务的同一个会话中。

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

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

例子

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

ROLLBACK PREPARED 'foobar';

另见

PREPARE TRANSACTION, COMMIT PREPARED

ROLLBACK TO SAVEPOINT​

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

大纲

ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] savepoint_name

描述

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

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

参数

savepoint_name

要回滚到的保存点。

注解

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

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

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

示例

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

ROLLBACK TO SAVEPOINT my_savepoint;

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

BEGIN;
DECLARE foo CURSOR FOR SELECT 1 UNION SELECT 2;
SAVEPOINT foo;
FETCH 1 FROM foo;
?column?
1646
ROLLBACK TO SAVEPOINT
----------
1
ROLLBACK TO SAVEPOINT foo;
FETCH 1 FROM foo;
?column?
----------
2
COMMIT;

另见

BEGIN, COMMIT, RELEASE SAVEPOINT, ROLLBACK, SAVEPOINT

SAVEPOINT​

SAVEPOINT --- 在当前事务中定义一个新的保存点

大纲

SAVEPOINT savepoint_name

描述

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

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

参数

savepoint_name

给新保存点的名字。

注解

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

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

示例

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

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。

另见

BEGIN, COMMIT, RELEASE SAVEPOINT, ROLLBACK, ROLLBACK TO SAVEPOINT

SECURITY LABEL​

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

大纲

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 |
PROCEDURE procedure_name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] |
PUBLICATION object_name |
ROLE object_name |
ROUTINE routine_name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] |
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 [ , ... ]

描述

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

注意

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

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

参数

object_name

table_name.column_name

aggregate_name

function_name

procedure_name

routine_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:sepgsql_table_t:s0';

另见

sepgsql, src/test/modules/dummy_seclabel

SELECT​

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

大纲

[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ 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 } [ 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 | WITH TIES } ]
[ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name
[, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]

其中 from_item 可以是以下之一:

[ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
[ 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_type 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 [ * ]

描述

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

1. WITH列表中的所有查询都会被计算。这些查询实际充当了在FROM列表中可以引用的临时表。在FROM中被引用多次的WITH查询只会被计算一次,除非另有说明,否则NOT MATERIALIZED。 (见下文的WITH Clause)。

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

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

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

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

6. SELECT DISTINCT从结果中消除重复的行。SELECT DISTINCT ON消除在所有指定表达式上匹 配的行。SELECT ALL(默认)将返回所有候选行, 包括重复的行(见下文的DISTINCT Clause)。

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

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

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

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

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

参数

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查询的结果。

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

当WITH子句中有多个查询时,RECURSIVE应只编写一次,紧跟在WITH之后。它适用于WITH子句中的所有查询,尽管它对不使用递归或前向引用的查询没有影响。

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

WITH查询的一个关键属性是,即使主查询多次引用它们,它们通常每次执行主查询只计算一次。特别是,数据修改语句确保执行一次而且只执行一次,而与主查询是否读取它们的全部或任何输出无关。

但是,WITH查询可以标记为NOT MATERIALIZED以移除此保证。在这种情况下,WITH查询可以折叠到主查询中,就好像它是主查询的FROM子句中的简单的sub-SELECT。如果主查询多次引用WITH查询,则会导致重复计算;但是,如果每次此类使用只需要WITH查询的总输出中的几行,NOT MATERIALIZED可以通过允许查询联合优化来节省开销。NOT MATERIALIZED被忽略,如果它被附加到一个递归的WITH查询,或者不是边际效应无关的(也就是说,不是包含非易失性函数的普通的SELECT)。

FROM 子句

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

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

table_name

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

alias

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

TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ] table_name之后的 TABLESAMPLE子句表示应该用指定的 sampling_method 来检索表中行的子集。这种采样优先于任何其他过滤器(例如 WHERE子句)。Halo包括两种采样方法: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查询会为主查询隐藏任何具有相同名称的真实表。如果必要,你可以使用带模式限定的方式以相同的名称来引用真实表)。可以像表一样,以同样的方式提供一个别名。

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_type

One of

• [ 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 list或 ORDER BY子句中的窗口函数的行为。这些函数可以在它们的 OVER子句中用名称引用WINDOW 子句项。不过,WINDOW子句项不是必须被引用。如果在查询中没有用到它,它会被简单地忽略。可以使用根本没有任何WINDOW子句的窗口函数,因为窗口函数调用可以直接在其OVER子句中指定它的窗口定

义。不过,当多个窗口函数都需要相同的窗口定义时, WINDOW子句能够减少输入。

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

SELECT 列表

SELECT列表(位于关键词 SELECT和FROM之间)指定构成 SELECT语句输出行的表达式。这些表达式 可以(并且通常确实会)引用FROM子句中计算得到的列。正如在表中一样,SELECT的每一个输出列都有一个名称。 在一个简单的SELECT中,这个名称只是被用来标记要显示的列,但是当SELECT是一个大型查询的一个子查询时,大型查询会把该名称看做子查询产生的虚表的列名。要指定用于输出列的名称,在该列的表达式后面写上 AS output_name( 当期望的输出名称不和Halo任何关键词冲突的情况下,可以省略AS。为了避免和未来增加的关键词冲突,推荐总是写上AS或者用双引号引用输出名称)。如果你不指定列名,Halo会自动选择一个名称。如果列的表达式是一个简单的列引用,那么被选择的名称就和该列的名称相同。在使用函数或者类型名称的更复杂的情况中,系统可能会生成诸如 ?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引用,Halo实际将在排序和限制行数之后计算输出表达式(作为一个反例,SELECT f(x) FROM tab ORDER BY 1显然必须在排序之前计算f(x))。包含有集合返回函数的输出表达式实际是在排序之后和限制行数之前被计算,这样LIMIT才能切断来自集合返回函数的输出。

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一起使用。

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的任何输入。

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 引入了一种不同的语法来达到相同的结果,Halo也支持它:

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

在这种语法中,标准要求start或count是一个文本常量、一个参数或者一个变量名。而作为Halo的一种的扩展,还允许其他的表达式,但通常需要被封闭在圆括号中以避免歧义。如果在一个 FETCH子句中省略 count,它的默认值为 1。 WITH TIES选项用于根据ORDER BY子句返回与结果集中最后一个位置相关的任何附加行;ORDER BY在这种情况下是强制性的。 ROW和ROWS以及 FIRST和NEXT是噪声,它们不影响这些子句的效果。根据标准,如果都存在,OFFSET子句 必须出现在FETCH子句之前。但是Halo更宽松,它允许两种顺序。在使用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 ]

其中lock_strength可以是

UPDATE

NO KEY UPDATE

SHARE

KEY SHARE

为了防止该操作等待其他事务提交,可使用NOWAIT或者 SKIP LOCKED选项。使用NOWAIT时,如果选中的行不能被立即锁定,该语句会报告错误而不是等待。使用 SKIP LOCKED时,无法被立即锁定的任何选中行都 会被跳过。跳过已锁定行会提供数据的一个不一致的视图,因此这不适合于一般目的的工作,但是可以被用来避免多个用户访问一个类似队列的表时出现锁竞争。注意NOWAIT和 SKIP LOCKED只适合行级锁 --- 所要求的

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 中已经修复这个问题。

小心:一个运行在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、 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;
1667
SELECT
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,然后是查询的递归部分。

要确保查询的递归部分最终将不返回任何行,否则该查询将无限循环

这个例子使用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 INTO​

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

大纲

[ 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 ] [...] ]

描述

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

参数

TEMPORARY or TEMP

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

UNLOGGED

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

new_table

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

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

注解

CREATE TABLE AS在功能上与 SELECT INTO相似。CREATE TABLE AS 是被推荐的语法,因为这种形式的SELECT INTO在ECPG 或PL/pgSQL中不可用,因为它们对 INTO子句的解释不同。此外,CREATE TABLE AS提供的功能是 SELECT INTO的超集。

与CREATE TABLE AS相比,SELECT INTO 不允许指定属性,就像带有USING method的表访问方法或者带有TABLESPACE tablespace_name的表的表空间。如果必要,使用CREATE TABLE AS。因此,为新表选择默认表访问方法。详细信息请参阅default_table_access_method。

示例

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

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

另见

CREATE TABLE AS

SET​

SET --- 更改一个运行时参数

大纲

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

描述

SET命令更改运行时配置参数。很多的参数可以用 SET即时更改(但是有些需要超级用户特权才能更改,并且还有一些在服务器或者会话启动之后不能被更改)。

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

如果在一个事务内发出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选项,除非回滚,它的效果将一直保持。

参数

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 之间的浮点数,它会被乘上 2 31 -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_config提供了等效的功能。此外,可以更新 pg_settings 系统视图来执行与SET等效的工作。

示例

设置模式搜索路径:

SET search_path TO my_schema, public;

设置时区为加州伯克利:

SET TIME ZONE 'PST8PDT';

设置时区为意大利:

SET TIME ZONE 'Europe/Rome';

另见

RESET, SHOW

SET CONSTRAINTS​

SET CONSTRAINTS --- 为当前事务设置约束检查时机

大纲

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

描述

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的唯一和排除约束也会被 立刻检查。

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

注解

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

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

SET ROLE​

SET ROLE --- 设置当前会话的当前用户标识符

大纲

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

描述

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

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

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

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

注解

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

示例

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

另见

SET SESSION AUTHORIZATION

SET SESSION AUTHORIZATION​

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

大纲

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

描述

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

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

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

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

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

注解

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

示例

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

另见

SET ROLE

SET TRANSACTION​

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

描述

SET TRANSACTION命令设置当前会话的特性。

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

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

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

READ COMMITTED

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

REPEATABLE READ

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

SERIALIZABLE

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

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

注解

如果执行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等方式设置默认值。

示例

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

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

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

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

SHOW​

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

大纲

SHOW name
SHOW ALL

描述

SHOW将显示运行时参数的当前设置。

参数

name

一个运行时参数的名称。

有一些可以显示但不能设置的参数:

SERVER_VERSION

显示服务器的版本号。

SERVER_ENCODING

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

LC_COLLATE

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

LC_CTYPE

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

IS_SUPERUSER

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

ALL

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

注解

函数current_setting产生等效的输出 。还有, pg_settings 系统事务产生同样的信息。

示例

显示参数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)

另见

SET, RESET

START TRANSACTION​

START TRANSACTION --- 开始一个事务块

大纲

START TRANSACTION [ transaction_mode [, ...] ]

其中 transaction_mode 是下列之一:

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

描述

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

参数

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

另见

BEGIN, COMMIT, ROLLBACK, SAVEPOINT, SET TRANSACTION

TRUNCATE​

TRUNCATE --- 清空一个表或者一组表

大纲

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

描述

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

参数

name

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

RESTART IDENTITY

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

CONTINUE IDENTITY

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

CASCADE

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

RESTRICT

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

注解

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

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

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

示例

截断表bigtable和 fattable:

TRUNCATE bigtable, fattable;

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

TRUNCATE bigtable, fattable RESTART IDENTITY;

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

TRUNCATE othertable CASCADE;

参见

DELETE

UNLISTEN​

UNLISTEN --- 停止监听一个通知

大纲

UNLISTEN { channel | * }

描述

UNLISTEN被用来移除一个已经存在的对NOTIFY事件的注册。 UNLISTEN取消任何已经存在的把当前会话作为名为 channel的通知频道的监听者的注册。特殊的通配符*取消当前会话的所有监听者注册。

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

参数

channel

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

*

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

注解

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

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

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

示例

做一次注册:

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

另见

LISTEN, NOTIFY

UPDATE​

UPDATE --- 更新一个表的行

大纲

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

描述

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

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

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

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

参数

with_query

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

table_name

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

alias

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

column_name

table_name 所指定的表的一列的名称。如果需要,该列名可以用一个子域名称或者数组下标限定。不要在目标列的说明中包括表的名称 --- 例如 UPDATE table_name SET

table_name.col = 1是非法的。

expression

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

DEFAULT

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

标识列将设置为关联序列生成的新值。对于生成的列,允许指定此项,但仅指定从其生成表达式计算列的正常行为。

sub-SELECT

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

from_item

表表达式允许来自其他表的列出现在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

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

输出

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

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

注解

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

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

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

在移动的行上的并发UPDATE或DELETE可能会收到序列化失败错误假设会话 1 正在分区键上执行UPDATE,同时,对可访问该行的并发会话 2 在此行上执行UPDATE或DELETE操作。 在这种情况下,会话 2 的UPDATE 或 DELETE将检测行移动并引发序列化失败错误(该错误始终返回 SQLSTATE 代码"40001")。 如果发生这种情况,应用程序可能希望重试事务。 在通常情况下,表没有分区或没有行移动,会话 2 将标识新更新的行,并执行UPDATE/DELETE在此新行版本中。

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

示例

把表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;

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 ]
PARALLEL integer

而table_and_columns是:

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

描述

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

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

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

简单的 VACUUM(不带FULL)简单地收回空间并使其可以被重用。这种形式的命令可以和表的普通读写操作并行,因为它不会获得一个排他锁。但是,这种形式中额外的空间并没有被还给操作系统(在大多数情况下),它仅仅被保留在同一个表中以备重用。它还允许我们利用多个 CPU来处理索引。 此功能称为parallel vacuum。要禁用此功能,可以使用PARALLEL选项并将并行工作程序指定为零。VACUUM FULL将表的整个内容重写到一个新的磁盘文件中,并且不包含额外的空间,这使得没有被使用的空间被还给操作系统。这种形式的命令更慢并且在其被处理时要求在每个表上保持一个排他锁。

当选项列表被包围在圆括号中时,选项可以被写成任何顺序。如果没有圆括号,选项必须严格按照上面所展示的顺序指定。

参数

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,对要被清空的表。如果需要尽快运行清空操作的话,将此选项设置为 false 可能很有用,例如,为了避免即将发生的事务ID 回绕[wraparound]。 但是,如果不定期执行索引清理,性能可能会受到影响,因为随着表的修改,索引将累积死元组,并且表本身将累积死行指针,在索引清理完成之前都无法删除。此选项对于没有索引的表无效,如果使用 FULL 选项,则忽略此选项。

TRUNCATE

指定VACUUM尝试截断表末尾的任何空页,并允许将截断页的磁盘空间返回到操作系统。

这通常是所需的行为,并且是默认行为,除非将vacuum_truncate选项设置为 false,对要被清空的表。将此选项设置为 false 可能有助于避免ACCESS EXCLUSIVE锁定需要截断的表。如果使用FULL选项,则忽略此选项。

PARALLEL

使用integer后台处理器并行执行VACUUM 的索引真空和索引清理阶段。用于执行操作的处理器数量等于关系上支持并行清理的索引数量,该数量受PARALLEL 选项指定的工人数量的限制,如果有的话,该数量还受到max_parallel_maintenance_workers限制。当且仅当索引的大小大于min_parallel_index_scan_size时,索引才能参与并行清理。请注意,不保证在执行期间会使用integer中指定的并行工作线程数。清理运行时可能需要比指定的更少的处理器,甚至根本没有处理器。每个索引只能使用一名处理器。所以只有当表中至少有2索引时才会启动并行工作程序。在每个阶段开始之前启动清理工作进程,并在阶段结束时退出。这些行为可能会在未来的版本中发生变化。此选项不能与FULL选项一起使用。

boolean

指定打开还是关闭所选选项。你可以写入TRUE、ON或1以启用该选项,以及FALSE、OFF或0来禁用它。 在TRUE被假定的情况下,boolean 值也可以被省略。

Integer

指定传递给所选选项的非负整数值。

table_name

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

column_name

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

输出

如果声明了VERBOSE,VACUUM会发出进度消息来表明当前正在处理哪个表。各种有关这些表的统计信息也会打印出来。

注意

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

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

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

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

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

PARALLEL选项仅用于清理目的。如果此选项与ANALYZE选项一起指定,则不会影响ANALYZE。

VACUUM会导致I/O流量的大幅度增加,这可能导致其他活动会话性能变差。因此,有时建议使用基于代价的清理延迟特性。对于并行清理,每个处理器的睡眠与该处理器完成的工作成比例。

Halo包括了一个"autovacuum"工具,它可以自动进行例行的清理维护。

例子

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

VACUUM (VERBOSE, ANALYZE) onek;

参见

vacuumdb,

VALUES​

VALUES --- 计算一个行集合

大纲

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

描述

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

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

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

参数

expression

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

sort_expression

一个指示如何排序结果行的表达式或者整型常量。这个表达式可以用column1、column2等来 引用该VALUES结果的列。有关详细信息,请参阅 SELECT文档中的ORDER BY Clause。

operator

一个排序操作符。详见 SELECT文档中的ORDER BY Clause。

count

要返回的最大行数。详见 SELECT文档中的LIMIT Clause。

start

开始返回行之前要跳过的行数。详见 SELECT文档中的LIMIT Clause。

注解

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

示例

一个纯粹的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子句指定名称,但是那样做是一种好习惯(在Halo中,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查询。标量列表方法的书写更少并且常常更加高效。

另见

INSERT, SELECT