选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0
历史版本PostgreSQL 9.1 已于 2016 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

SELECT

SELECT, TABLE, WITH — retrieve rows from a table or view

大纲

[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
    * | expression [ [ AS ] output_name ] [, ...]
    [ 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 ] [...] ]

where from_item can be one of:

    [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
    ( select ) [ AS ] alias [ ( column_alias [, ...] ) ]
    with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
    function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ]
    function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )
    from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]

and with_query is:

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

TABLE [ ONLY ] table_name [ * ]

描述

SELECT 从零个或多个表中检索行。SELECT 的一般处理流程如下:

  1. WITH列表中的所有查询都会被计算。 这些实际上充当临时表,可以在FROM列表中引用。 在FROM列表中多次引用的WITH查询只会计算一次。 (参见下面的WITH Clause。)

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

  3. 如果指定了WHERE子句,则不满足条件的所有行将从输出中删除。 (请参见下面的WHERE Clause。)

  4. 如果指定了GROUP BY子句, 或者存在聚合函数调用, 输出将被组合成在一个或多个值上匹配的行组, 并计算聚合函数的结果。 如果存在HAVING子句, 它将消除不满足给定条件的组。(参见 GROUP BY ClauseHAVING Clause。)

  5. 实际输出行是使用每个选定行或行组的SELECT输出表达式计算的。 (参见下面的SELECT List。)

  6. SELECT DISTINCT消除结果中的重复行。 SELECT DISTINCT ON会消除在所有指定表达式上匹配的行,只保留每组中的第一行。 SELECT ALL(默认)将返回所有候选行,包括重复行。 (参见下面的DISTINCT Clause。)

  7. 使用操作符UNIONINTERSECTEXCEPT, 可以将多个SELECT语句的输出合并成一个结果集。 UNION操作符返回在一个或两个结果集中的所有行。 INTERSECT操作符返回同时出现在两个结果集中的所有行。 EXCEPT操作符返回在第一个结果集中但不在第二个结果集中的行。 在这三种情况下,除非指定ALL,否则将消除重复行。 还可以添加噪声词DISTINCT,以明确指定去重。 请注意,这里的默认行为是DISTINCT,即使SELECT本身的默认行为是ALL。 (请参见下面的UNION ClauseINTERSECT ClauseEXCEPT Clause。)

  8. 如果指定了ORDER BY子句,则返回的行按指定顺序排序。 如果没有给出ORDER BY,则按系统认为最快的顺序返回行。 (参见下面的ORDER BY Clause。)

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

  10. 如果指定了 FOR UPDATEFOR SHARESELECT 语句将选定的行锁定,防止并发更新(参见下面的FOR UPDATE/FOR SHARE Clause)。

你必须拥有 SELECT 命令中使用到的每一列上的 SELECT 权限。使用 FOR UPDATEFOR SHARE 还要求 UPDATE 权限(对于每个这样选中的表,至少要有一列具有该权限)。

参数

WITH Clause

WITH 子句允许你指定一个或多个可在主查询中按名称引用的子查询。这些子查询在主查询执行期间实际上充当临时表或视图。每个子查询都可以是一条 SELECTINSERTUPDATEDELETE 语句。 在 WITH 中写数据修改语句(INSERTUPDATEDELETE)时,通常会带上 RETURNING 子句。构成主查询所读取临时表的,是 RETURNING 的输出,而不是语句所修改的底层表。如果省略 RETURNING,语句仍会执行,但不产生任何输出,因此主查询无法把它当作表来引用。

对于每个WITH查询,都必须指定一个名称(不带模式限定)。 还可以指定一个列名列表;如果省略,则列名将从子查询中推导出来。

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

non_recursive_term UNION [ ALL | DISTINCT ] recursive_term

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

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

WITH查询的一个关键特性是,每次执行主查询时,它们都只会求值一次,即使主查询多次引用它们。特别是,无论主查询是否读取了它们的全部输出或任何输出,数据修改语句都保证执行一次且仅执行一次。

主查询和WITH查询(概念上)都在同一时间执行。 这意味着,除了读取其RETURNING输出之外,查询的其 他部分都看不到WITH中数据修改语句的效果。如果两个这 样的数据修改语句试图修改同一行,结果未指定。

更多信息请见第 7.8 节

FROM Clause

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

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

table_name

要扫描的现有表或视图的名称(可选模式限定符)。如果在表名之前指定ONLY, 则仅扫描该表。如果未指定ONLY,则扫描该表及其所有后代表(如果有)。 可选地,可以在表名后指定*,以明确指示包括后代表。

alias

包含该别名的FROM项的替代名称。别名可用于简写, 或者消除自连接(同一张表被扫描多次)中的歧义。提供别名后,它会 完全隐藏表或函数的实际名称;例如给定FROM foo AS fSELECT的其余部分必须把这个FROM 项写成f而不是foo。如果写了别名, 还可以写列别名列表,为该表的一个或多个列提供替代名称。

select

SELECT可以出现在FROM子句中, 它的作用就像在这个SELECT命令的执行期间创建了一个 临时表。注意,子SELECT必须用圆括号括起来,并且 必须为其提供别名。这里也可以使用 VALUES命令。

with_query_name

WITH查询通过写出它的名称来引用,就像该查询名是表名 一样。(事实上,对于主查询而言,WITH查询会遮蔽任何同名的 真实表;如有必要,可以通过模式限定表名来引用该同名真实表。) 也可以像对待表一样为它提供别名。

function_name

函数调用可以出现在FROM子句中。(这对于返回结果集的函数尤其有用,但任何函数都可以使用。)其效果就像在这条SELECT命令执行期间,将函数的输出创建成了一张临时表。也可以使用别名。如果写了别名,还可以写一个列别名列表,为函数复合返回类型中的一个或多个属性提供替代名称。如果函数被定义为返回record数据类型,则必须给出别名或关键字AS,后面跟一个如下形式的列定义列表:( column_name data_type [, ... ] )。列定义列表必须与函数实际返回的列数和类型相匹配。

join_type

以下之一:

  • [ INNER ] JOIN

  • LEFT [ OUTER ] JOIN

  • RIGHT [ OUTER ] JOIN

  • FULL [ OUTER ] JOIN

  • CROSS JOIN

For the INNER and OUTER join types, a join condition must be specified, namely exactly one of NATURAL, ON join_condition, or USING (join_column [, ...]). See below for the meaning. For CROSS JOIN, none of these clauses can appear.

JOIN 子句组合两个 FROM 项。如有必要可用圆括号确定嵌套的顺序。在没有圆括号时,JOIN 从左到右嵌套。在任何情况下,JOIN 的结合都比分隔 FROM 项的逗号更紧。

CROSS JOININNER JOIN产生简单的笛卡尔积,与在FROM顶层列出这两个表得到的结果相同,但会受到连接条件(如果有)的限制。CROSS JOIN等价于INNER JOIN ON (TRUE),也就是说,没有行会被条件过滤掉。这些连接类型只是提供了一种方便的记法,因为它们所做的一切都可以用普通的FROMWHERE完成。

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 列表。

WHERE Clause

可选的WHERE子句的形式

WHERE condition

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

GROUP BY Clause

可选的 GROUP BY 子句的一般形式为

GROUP BY expression [, ...]

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

(相反,如果没有GROUP BY,聚集会对所有被选中的行计算产生单个值。)当存在GROUP BY子句时,SELECT列表表达式不能引用非分组列,除非是在聚合函数内部,或者该非分组列函数依赖于分组列,因为否则对于一个非分组列可能会有多个可返回的值。如果分组列(或其子集)是包含该非分组列的表的主键,则存在函数依赖。

HAVING Clause

可选的HAVING子句的形式

HAVING condition

其中conditionWHERE子句中指定的条件相同。

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

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

WINDOW Clause

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

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

可选的 frame_clause 定义窗口帧,供依赖于帧的窗口函数使用(并非所有窗口函数都依赖帧)。窗口帧是与查询中每一行相关联的一组行;查询中的这一行称为当前行frame_clause 可以是以下之一:

{ RANGE | ROWS } frame_start
{ RANGE | ROWS } BETWEEN frame_start AND frame_end

其中,frame_startframe_end 可以是以下之一:

UNBOUNDED PRECEDING
value PRECEDING
CURRENT ROW
value FOLLOWING
UNBOUNDED FOLLOWING

如果省略 frame_end,则默认为 CURRENT ROW。其限制是:frame_start 不能是 UNBOUNDED FOLLOWINGframe_end 不能是 UNBOUNDED PRECEDING,并且 frame_end 在上面列表中的位置不能早于 frame_start 的位置 — 例如,RANGE BETWEEN CURRENT ROW AND value PRECEDING 是不允许的。

默认的帧选项是RANGE UNBOUNDED PRECEDING,它等同于RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW;它将帧设置为从分区起点到当前行最后一个同等行的所有行(同等行是ORDER BY认为与当前行等价的行;如果没有ORDER BY,则所有行都属于同等行)。一般而言,UNBOUNDED PRECEDING表示帧从分区的第一行开始,而UNBOUNDED FOLLOWING同样表示帧在分区的最后一行结束(无论采用RANGE还是ROWS模式)。在ROWS模式下,CURRENT ROW表示帧从当前行开始或在当前行结束;但在RANGE模式下,它表示帧从ORDER BY排序中当前行的第一个同等行开始,或在最后一个同等行结束。目前,value PRECEDINGvalue FOLLOWING仅允许用于ROWS模式。它们表示帧从当前行之前或之后相应行数的那一行开始或结束。value必须是不包含任何变量、聚合函数或窗口函数的整数表达式。该值不能为空值或负数,但可以为零,此时选择当前行本身。

请注意,如果ORDER BY排序没有将行排成唯一顺序,ROWS选项可能产生不可预测的结果。RANGE选项旨在确保ORDER BY排序中的同等行得到相同处理;所有同等行都会位于同一帧中。

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

窗口函数的详细描述在 第 3.5 节第 4.2.8 节以及 第 7.2.4 节中。

SELECT List

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

正如在表中一样,SELECT 的每一个输出列都有一个名称。在一个简单的 SELECT 中,这个名称只是被用来标记要显示的列,但是当 SELECT 是一个大型查询的子查询时,大型查询会把该名称看做子查询产生的虚表的列名。 要指定输出列使用的名称,可在列的表达式后面写上 AS output_name。(可以省略 AS,但仅当期望的输出名不与任何 PostgreSQL 关键字(见 附录 C)冲突时。为了防止将来可能新增关键字,建议始终写上 AS,或者给输出名加上双引号。)如果没有指定列名,名称将由 PostgreSQL 自动选择:如果列的表达式是一个简单的列引用,所选名称就是该列的名称;在更复杂的情况下,通常会使用形如 ?columnN? 的生成名称。

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

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

DISTINCT Clause

如果指定了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分组内行的优先级。

UNION Clause

UNION 子句的一般形式如下:

select_statement UNION [ ALL | DISTINCT ] select_statement

select_statement 是 任何不带 ORDER BYLIMITFOR UPDATEFOR SHARE 子句的 SELECT 语句。 (如果用圆括号括起,ORDER BYLIMIT 可以附着到子表达式上。 如果没有圆括号,这些子句将被认为作用于 UNION 的结果, 而不是其右侧的输入表达式。)

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

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

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

当前,FOR UPDATEFOR SHARE 不能为 UNION 的结果或 UNION 的任何输入指定。

INTERSECT Clause

INTERSECT 子句的一般形式如下:

select_statement INTERSECT [ ALL | DISTINCT ] select_statement

select_statement is any SELECT statement without an ORDER BY, LIMIT, FOR UPDATE, or FOR SHARE clause.

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

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

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

当前,FOR UPDATEFOR SHARE 不能为 INTERSECT 的结果或 INTERSECT 的任何输入指定。

EXCEPT Clause

EXCEPT 子句的一般形式如下:

select_statement EXCEPT [ ALL | DISTINCT ] select_statement

select_statement is any SELECT statement without an ORDER BY, LIMIT, FOR UPDATE, or FOR SHARE clause.

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

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

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

当前,FOR UPDATEFOR SHARE 不能为 EXCEPT 的结果或 EXCEPT 的任何输入指定。

ORDER BY Clause

可选的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;

这种特性的一个限制是一个应用在UNIONINTERSECTEXCEPT子句结果上的 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 DESCORDER BY x DESC, y DESC是不同的。

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

LIMIT Clause

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

LIMIT { count | ALL }
OFFSET start

count 指定最多返回多少行,而 start 指定开始返回行之前要跳过的行数。如果两者都指定,则先跳过 start 行,然后开始计数并返回 count 行。

如果 count 表达式计算结果为 NULL,则视为 LIMIT ALL,即不限制。如果 start 计算结果为 NULL,则等同于 OFFSET 0

SQL:2008 引入了另一种实现相同结果的语法,PostgreSQL 也支持它。其形式如下:

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

在这种语法中,要为 startcount 写除简单整数常量以外的任何内容,必须给它加上圆括号。如果在 FETCH 子句中省略 count,它默认为 1。ROWROWS 以及 FIRSTNEXT 都是不影响这些子句效果的赘词。按照标准,如果两个子句同时出现,OFFSET 子句必须在 FETCH 子句之前;但 PostgreSQL 更宽松,允许任意顺序。

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

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

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

FOR UPDATE/FOR SHARE Clause

FOR UPDATE 子句的形式如下:

FOR UPDATE [ OF table_name [, ...] ] [ NOWAIT ]

与它密切相关的 FOR SHARE 子句的形式如下:

FOR SHARE [ OF table_name [, ...] ] [ NOWAIT ]

FOR UPDATE 导致由 SELECT 语句检索到的行被锁定,就像要更新它们一样。这可以防止它们被其他事务修改或删除,直到当前事务结束。也就是说,其他事务中试图对这些行执行 UPDATEDELETESELECT FOR UPDATE 的操作将被阻塞,直到当前事务结束。此外,如果来自另一个事务的 UPDATEDELETESELECT FOR UPDATE 已经锁定了某个被选中的行,SELECT FOR UPDATE 将等待该其他事务完成,然后锁定并返回更新后的行(如果该行已被删除,则不返回任何行)。而在 REPEATABLE READSERIALIZABLE 事务中,如果要锁定的行自事务开始以来已被更改,则会抛出一个错误。更多讨论见第 13 章

FOR SHARE 的行为类似,但它在每个被检索的行上获取共享锁而非排他锁。共享锁阻塞其他事务对这些行执行 UPDATEDELETESELECT FOR UPDATE,但不会阻止它们执行 SELECT FOR SHARE

为了防止该操作等待其他事务提交,可使用NOWAIT 选项。使用NOWAIT时,如果 选中的行不能被立即锁定,该语句会直接报错而不是等待。注意, NOWAIT只适用于行级锁; 所需的ROW SHARE表级锁仍会按常规方式取得(见第 13 章)。 如果想要不等待的表级锁,你可以先使用带NOWAITLOCK

如果在 FOR UPDATEFOR SHARE 中提到了特定的表,则只有来自那些表的行会被锁定;SELECT 中用到的任何其他表还是被简单地照常读取。一个没有表列表的 FOR UPDATEFOR SHARE 子句会影响该语句中用到的所有表。如果把 FOR UPDATEFOR SHARE 应用到一个视图或子查询,它会影响该视图或子查询中用到的所有表。 However, FOR UPDATE/FOR SHARE do not apply to WITH queries referenced by the primary query. If you want row locking to occur within a WITH query, specify FOR UPDATE or FOR SHARE within the WITH query.

如果有必要对不同的表指定不同的锁定行为,可以写多个 FOR UPDATEFOR SHARE 子句。如果同一个表同时被 FOR UPDATEFOR SHARE 子句提到(或被隐式地影响到),那么它会按 FOR UPDATE 处理。类似地,如果在任何影响一个表的子句中指定了 NOWAIT,就会按此行为处理该表。

在返回的行无法清楚地与各个表行对应起来的上下文中,不能使用 FOR UPDATEFOR SHARE;例如它们不能与聚合一起使用。

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

FOR UPDATEFOR SHARE 出现在一个子 SELECT 中时,被锁定的行是子查询返回给外层查询的行。这可能比只检查子查询本身所显示的要少,因为来自外层查询的条件可能被用来优化子查询的执行。例如,

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

将只锁定 col1 = 5 的行,即使该条件在文本上并不在子查询之内。

小心

避免锁定一行然后又在后面的保存点或 PL/pgSQL 异常块中修改它。后续的回滚会导致锁丢失。例如:

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

在执行 ROLLBACK 之后,该行实际上已被解锁,而不是回到保存点之前已锁定但未修改的状态。如果当前事务中锁定的行被更新或删除,或者共享锁被升级为排他锁,就会出现这种风险:在所有这些情况下,之前的锁状态都会被遗忘。如果事务随后回滚到原始锁定命令和后续更改之间的某个状态,该行将看起来完全没有被锁定。这是一个实现上的缺陷,将在 PostgreSQL 的未来版本中解决。

小心

一个运行在 READ COMMITTED 事务隔离级别并且使用 ORDER BYFOR UPDATE/SHARESELECT 命令有可能返回无序的行。这是因为 ORDER BY 会被首先应用。该命令对结果排序,但可能接着在尝试获得一行或多行上的锁时阻塞。一旦 SELECT 不再阻塞,某些排序列的值可能已经被修改,导致这些行看起来乱序(尽管按照原始列值来看它们是有序的)。如有需要,可以通过把 FOR UPDATE/SHARE 子句放在子查询中来绕过这个问题, 例如

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

注意,这样会锁定 mytable 的所有行, 而顶层的 FOR UPDATE 只会锁定实际返回的行。如果 ORDER BY 还与 LIMIT 或其他限制条件结合使用, 这可能带来显著的性能差异。因此,只有在预期排序列会并发更新且严格要求结果有序时,才建议使用这种技术。

REPEATABLE READSERIALIZABLE事务隔离级别下, 这将导致串行化失败(SQLSTATE'40001'), 因此在这些隔离级别下不可能接收到无序的行。

TABLE 命令

命令

TABLE name

等价于

SELECT * FROM name

它可以作为顶层命令使用,也可以作为复杂查询某些部分中一种节省空间的语法变体。

示例

连接表 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

接下来的示例展示了如何得到表distributorsactors的并集,把结果限制为那些在每个表中以 字母 W 开始的行。这里只需要不重复的行,因此省略了关键词 ALL

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

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

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

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

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

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

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

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

这个例子展示了如何使用一个简单的 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,然后是查询的递归部分。要确保 查询的递归部分最终将不返回任何行,否则该查询将无限循环( 更多示例见第 7.8 节)。

兼容性

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

省略的FROM子句

PostgreSQL 允许省略 FROM 子句。它可以直接用于计算简单表达式的结果:

SELECT 2+2;

 ?column?
----------
        4

其他一些 SQL 数据库必须引入一个只有一行的虚拟表,才能从该表执行 SELECT

请注意,如果未指定 FROM 子句,查询就不能引用任何数据库表。例如,以下查询是无效的:

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

PostgreSQL 在 8.1 之前的版本会接受这种形式的查询,并为查询引用的每个表在该查询的 FROM 子句中添加一个隐式项。现在不再允许这种做法。

省略AS关键词

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

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

ONLY与继承

SQL 标准要求在使用ONLY时用圆括号括起表名,例如SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...PostgreSQL认为这些圆括号是可选的。

PostgreSQL允许在末尾写上*,显式指定包含子表的非ONLY行为。标准不允许这种写法。

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

GROUP BYORDER BY可用的名字空间

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

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

函数依赖

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

WINDOW子句的限制

SQL 标准为窗口frame_clause提供了更多选项。PostgreSQL目前仅支持上面列出的选项。

LIMITOFFSET

LIMITOFFSET子句是PostgreSQL特有的语法,MySQL也使用这种语法。SQL:2008 标准引入了OFFSET ... FETCH {FIRST|NEXT} ...子句来实现相同功能,如上面的LIMIT Clause所示。IBM DB2也使用这种语法。(为Oracle编写的应用经常采用一种变通办法,通过自动生成的rownum列实现这些子句的效果,而 PostgreSQL 中没有这一列。)

FOR UPDATE and FOR SHARE

尽管 FOR UPDATE 出现在 SQL 标准中,但标准只允许它作为 DECLARE CURSOR 的一个选项。PostgreSQL 允许它出现在任何 SELECT 查询以及子 SELECT 中,但这是一个扩展。FOR SHARE 变体以及 NOWAIT 选项未出现在标准中。

WITH中的数据修改语句

PostgreSQL允许将INSERTUPDATEDELETE用作WITH查询。SQL 标准中没有这种用法。

非标准子句

DISTINCT ON子句未在 SQL 标准中定义。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。