Note

SELECT

SELECT,TABLE 和 WITH —从表或视图中检索行

Synopsis

[ 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 ]
    [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]

where from_item can be one of:

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

and grouping_element can be one of:

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

and with_query is:

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

TABLE [ ONLY ] table_name [ * ]

Description

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

  • 计算WITH列表中的所有查询。这些有效地用作可以在FROM列表中引用的临时表。在FROM中多次引用的WITH查询仅计算一次。 (请参见下面的WITH Clause。)

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

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

  • 如果指定了GROUP BY子句,或者有聚合函数调用,则将输出合并为与一个或多个值匹配的行组,并计算聚合函数的结果。如果存在HAVING子句,它将消除不满足给定条件的组。 (请参见下面的按条款分组HAVING Clause。)

  • 对于每个选定的行或行组,使用SELECT输出表达式来计算实际的输出行。 (请参见下面的SELECT List。)

  • SELECT DISTINCT从结果中消除重复的行。 SELECT DISTINCT ON消除与所有指定表达式匹配的行。 SELECT ALL(默认值)将返回所有候选行,包括重复项。 (请参见下面的DISTINCT Clause。)

  • 使用运算符UNIONINTERSECTEXCEPT,可以组合多个SELECT语句的输出以形成单个结果集。 UNION运算符返回一个或两个结果集中的所有行。 INTERSECT运算符返回严格位于两个结果集中的所有行。 EXCEPT运算符返回第一个结果集中的行,而不是第二个结果集中的行。在所有三种情况下,除非指定了ALL,否则消除了重复的行。可以添加噪声字DISTINCT以明确指定消除重复的行。请注意,尽管SELECT本身是默认值,但DISTINCT是此处的默认行为。 (请参见下面的UNION ClauseINTERSECT ClauseEXCEPT Clause。)

  • 如果指定了ORDER BY子句,则返回的行将以指定的 Sequences 排序。如果未提供ORDER BY,则以系统认为最快的 Sequences 返回行。 (请参见下面的按条款 Order。)

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

  • 如果指定了FOR UPDATEFOR NO KEY UPDATEFOR SHAREFOR KEY SHARE,则SELECT语句将锁定所选行以防止并发更新。 (请参见下面的锁定条款。)

您必须对SELECT命令中使用的每一列具有SELECT特权。 FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE的使用也需要UPDATE特权(对于这样选择的每个表的至少一列)。

Parameters

WITH Clause

WITH子句允许您指定一个或多个子查询,这些查询可以通过名称在主查询中进行引用。子查询在主查询期间有效地充当临时表或视图。每个子查询可以是SELECTTABLEVALUESINSERTUPDATEDELETE语句。在WITH中编写数据修改语句(INSERTUPDATEDELETE)时,通常包含RETURNING子句。它是RETURNING的输出,而不是语句所修改的基础表,形成了由主查询读取的临时表。如果省略RETURNING,则该语句仍将执行,但不会产生任何输出,因此主查询无法将其引用为表。

必须为每个WITH查询指定一个名称(无模式限定)。 (可选)可以指定列名列表;如果省略此选项,则从子查询中推断出列名。

如果指定了RECURSIVE,则它允许SELECT子查询按名称引用自身。这样的子查询必须具有以下形式

non_recursive_term UNION [ ALL | DISTINCT ] recursive_term

递归自引用必须出现在UNION的右侧。每个查询只允许一个递归自引用。不支持递归数据修改语句,但是您可以在数据修改语句中使用递归SELECT查询的结果。有关示例,请参见Section 7.8

RECURSIVE的另一个作用是不必对WITH个查询进行排序:查询可以引用列表中后面的另一个查询。 (但是,不会实现循环引用或相互递归.)如果没有RECURSIVE,则WITH查询只能引用WITH列表中较早的同级WITH查询。

WITH查询的一个关键属性是,即使主查询多次引用它们,一次执行主查询也只会对它们进行一次评估。特别是,无论主查询是读取全部输出还是输出任何内容,都保证数据修改语句仅执行一次。

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

主查询和WITH查询都(名义上)同时执行。这意味着在WITH中修改数据的语句的效果无法从查询的其他部分看到,除非读取其RETURNING输出。如果两个这样的数据修改语句试图修改同一行,则结果不确定。

有关其他信息,请参见Section 7.8

FROM Clause

FROM子句为SELECT指定一个或多个源表。如果指定了多个源,则结果为所有源的笛卡尔乘积(交叉联接)。但是通常会添加限定条件(通过WHERE),以将返回的行限制为笛卡尔乘积的一小部分。

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

  • table_name

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

    • 包含别名的FROM项的替代名称。别名是为了简洁起见或消除自联接的歧义(多次扫描同一张表)。提供别名后,它将完全隐藏表或函数的实际名称。例如FROM foo AS fSELECT的其余部分必须将此FROM项称为f而不是foo。如果写入了别名,则还可以写入列别名列表以为表的一个或多个列提供替代名称。
  • TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ]

      • table_name 后的TABLESAMPLE子句表示应使用指定的 sampling_method *检索该表中行的子集。该采样先于其他过滤器(例如WHERE子句)的应用。标准的 PostgreSQL 发行版包括BERNOULLISYSTEM两种采样方法,并且可以通过扩展将其他采样方法安装在数据库中。

BERNOULLISYSTEM采样方法每个都接受一个* argument *,这是要采样的表的分数,以 0 到 100 之间的百分比表示。此参数可以是任何real值的表达式。 (其他采样方法可能会接受更多或不同的参数.)这两种方法各自返回表的随机选择 samples,该 samples 将包含表行的指定百分比。 BERNOULLI方法扫描整个表,并以指定的概率独立选择或忽略单个行。 SYSTEM方法执行块级采样,每个块具有指定的被选择机会;返回每个选定块中的所有行。当指定较小的采样百分比时,SYSTEM方法比BERNOULLI方法要快得多,但是由于聚类的影响,它可能返回表中的随机性较低的 samples。

可选的REPEATABLE子句指定一个* seed 数字或表达式,用于在采样方法内生成随机数。种子值可以是任何非空浮点值。如果同时没有更改表,则两个指定相同种子和 argument *值的查询将选择表的相同 samples。但是,不同的种子值通常会产生不同的 samples。如果未提供REPEATABLE,则根据系统生成的种子为每个查询选择一个新的随机 samples。请注意,某些附加采样方法不接受REPEATABLE,并且每次使用时都会产生新的 samples。

  • 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

对于INNEROUTER连接类型,必须指定一个连接条件,即NATURALON join_conditionUSING (join_column [, ...])之一。含义见下文。对于CROSS JOIN,这些子句都不会出现。

JOIN子句组合了两个FROM项,为方便起见,我们将其称为“表”,尽管实际上它们可以是任何类型的FROM项。如有必要,请使用括号确定嵌套 Sequences。在没有括号的情况下,JOIN从左到右嵌套。无论如何,JOIN的绑定比分隔FROM -list 的逗号更紧密。

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

    • NATURALUSING列表的简写,该列表提到两个表中具有匹配名称的所有列。如果没有公共列名,则NATURAL等效于ON TRUE
  • LATERAL

    • LATERAL关键字可以位于子SELECT FROM项之前。这使子SELECT可以引用FROM项中出现在FROM列表中的FROM项的列。 (如果没有LATERAL,则每个子SELECT都会独立评估,因此不能交叉引用任何其他FROM项.)

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

LATERAL项可以出现在FROM列表的顶级或JOIN树中。在后一种情况下,它也可以引用位于JOIN左侧的任何项目。

FROM项包含LATERAL交叉引用时,评估将按以下步骤进行:对于提供交叉引用列的FROM项的每一行,或提供该列的多个FROM项的行集,将使用LATERAL项进行评估该行或行集的列值。像往常一样,将结果行与从中计算出的行连接在一起。对列源表中的每一行或每一行行重复此操作。

列源表必须与LATERAL项连接成INNERLEFT,否则将没有定义明确的行集可从其中计算LATERAL项的每组行。因此,尽管诸如X RIGHT JOIN LATERAL Y之类的构造在语法上是有效的,但实际上不允许* Y 引用 X *。

WHERE Clause

可选的WHERE子句具有常规形式

WHERE condition

其中* condition *是计算结果为boolean类型的任何表达式。任何不满足此条件的行将从输出中删除。如果用实际的行值代替任何变量引用,如果该行返回 true,则满足该条件。

GROUP BY 条款

可选的GROUP BY子句具有常规形式

GROUP BY grouping_element [, ...]

GROUP BY将所有共享相同表达式的分组表达式的所有选定行压缩为单行。在grouping_element内部使用的expression可以是 Importing 列名称,也可以是输出列的名称或序号(SELECT列表项),也可以是由 Importing 列值形成的任意表达式。如有歧义,GROUP BY名称将被解释为 Importing 列名称,而不是输出列名称。

如果GROUPING SETSROLLUPCUBE中的任何一个作为分组元素存在,则GROUP BY子句总体上定义了一些独立的* grouping sets *。这样的效果等效于在子查询之间构造UNION ALL,并将各个分组集作为其GROUP BY子句。有关处理分组集的更多详细信息,请参见Section 7.2.4

汇总函数(如果有的话)在组成每个组的所有行中进行计算,从而为每个组生成单独的值。 (如果有聚合函数但没有GROUP BY子句,则该查询被视为具有包含所有选定行的单个组.)可以通过在聚合函数调用上附加FILTER子句来进一步过滤馈给每个聚合函数的行集。 ;有关更多信息,请参见Section 4.2.7。当存在FILTER子句时,只有与之匹配的那些行才包含在该聚合函数的 Importing 中。

当存在GROUP BY或存在任何聚合函数时,除非聚合函数内或当非分组列在功能上取决于分组列时,否则SELECT列表表达式引用未分组列是无效的,因为否则对于未分组的列返回一个可能的值。如果分组的列(或其子集)是包含未分组的列的表的主键,则存在功能依赖性。

请记住,在评估HAVING子句或SELECT列表中的任何“标量”表达式之前,必须先评估所有聚合函数。这意味着,例如CASE表达式不能用于跳过对聚合函数的求值;参见Section 4.2.14

当前,无法用GROUP BY指定FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

HAVING Clause

可选的HAVING子句具有常规形式

HAVING condition

其中* condition *与为WHERE子句指定的相同。

HAVING消除不满足条件的组行。 HAVINGWHERE不同:WHERE在应用GROUP BY之前过滤单个行,而HAVING过滤由GROUP BY创建的组行。 * condition *中引用的每个列都必须明确引用一个分组列,除非该引用出现在聚合函数内或未分组的列在功能上取决于分组列。

即使没有GROUP BY子句,HAVING的存在也会将查询转换为分组查询。这与查询包含聚合函数但不包含GROUP BY子句时发生的情况相同。所有选定的行都被视为形成一个单一的组,并且SELECT列表和HAVING子句只能引用聚合函数中的表列。如果HAVING条件为 true,则此查询将发出单行,如果HAVING条件为 true,则将发出零行。

当前,无法用HAVING指定FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

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。新窗口始终使用其自己的 frame 子句;复制的窗口不得指定 frame 子句。

PARTITION BY列表的元素的解释方式与按条款分组的元素几乎相同,不同之处在于它们始终是简单表达式,而不是输出列的名称或编号。另一个区别是这些表达式可以包含聚合函数调用,这在常规GROUP BY子句中是不允许的。在此处允许使用它们,因为窗口在分组和聚合之后发生。

类似地,ORDER BY列表的元素的解释方式与按条款 Order的元素几乎相同,不同之处在于,表达式始终被视为简单表达式,而不是输出列的名称或编号。

可选的* 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 选项不能早于 frame_start frame_end 选项的列表中早于 frame_start *选项的出现-例如RANGE BETWEEN CURRENT ROW AND offset PRECEDING不被允许。

默认的取景选项为RANGE UNBOUNDED PRECEDING,与RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW相同;它将帧设置为从分区开始到当前行的最后一个* peer (该窗口的ORDER BY子句认为与当前行等效的行;如果没有ORDER BY,则所有行都是对等端)的所有行。通常,UNBOUNDED PRECEDING表示帧以分区的第一行开始,类似地,UNBOUNDED FOLLOWING表示帧以分区的最后一行结束,而不考虑RANGEROWSGROUPS模式。在ROWS模式下,CURRENT ROW表示帧以当前行开始或结束;但在RANGEGROUPS模式下,则表示帧以ORDER BYSequences 中当前行的第一个或最后一个对等点开始或结束。 * offset * PRECEDING offset * FOLLOWING选项的含义因帧模式而异。在ROWS模式下,* offset 是一个整数,指示帧在当前行之前或之后的许多行开始或结束。在GROUPS模式下, offset 是一个整数,指示帧开始或结束当前行的对等组之前或之后的许多对等组,其中 peer group 是根据窗口的ORDER BY等效的一组行。条款。在RANGE模式下,使用 offset 选项要求窗口定义中只有一列ORDER BY列。然后,框架包含那些其排序列值不大于 offset 小于(对于PRECEDING)或大于(对于FOLLOWING)当前行的排序列值的行。在这些情况下, offset 表达式的数据类型取决于排序列的数据类型。对于数字排序列,它通常与排序列具有相同的类型,但是对于日期时间排序列,它是interval。在所有这些情况下, offset 的值必须为非空且非负。同样,虽然 offset *不必是简单的常量,但它不能包含变量,聚合函数或窗口函数。

  • frame_exclusion *选项允许将当前行周围的行从帧中排除,即使根据帧开始和帧结束选项将其包括在内。 EXCLUDE CURRENT ROW从框架中排除当前行。 EXCLUDE GROUP从帧中排除当前行及其排序对等体。 EXCLUDE TIES从帧中排除当前行的任何同位体,但不排除当前行本身。 EXCLUDE NO OTHERS简单地明确指定不排除当前行或其对等行的默认行为。

请注意,如果ORDER BY排序不是唯一地对行进行排序,则ROWS模式可能会产生不可预测的结果。 RANGEGROUPS模式旨在确保按ORDER BYSequences 对等的行被相同地对待:给定对等组的所有行都将在该帧中或从该帧中排除。

WINDOW子句的目的是指定出现在查询SELECT List按条款 Order中的窗口功能的行为。这些函数可以在其OVER子句中按名称引用WINDOW子句条目。但是,不必在任何地方引用WINDOW子句条目。如果查询中未使用它,则将其忽略。可以根本不使用任何WINDOW子句来使用窗口函数,因为窗口函数调用可以直接在其OVER子句中指定其窗口定义。但是,当多个窗口函数需要相同的窗口定义时,WINDOW子句可以节省键入内容。

当前,无法用WINDOW指定FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

Section 3.5Section 4.2.8Section 7.2.5中详细描述了窗口功能。

SELECT List

SELECT列表(在关键字SELECTFROM之间)指定了构成SELECT语句的输出行的表达式。表达式可以(通常)引用FROM子句中计算的列。

就像在表中一样,SELECT的每个输出列都有一个名称。在简单的SELECT中,此名称仅用于标记要显示的列,但是当SELECT是较大查询的子查询时,该名称在较大查询中被视为由该子查询生成的虚拟表的列名。 -查询。要指定用于输出列的名称,请在该列的表达式后 ImportingAS * output_name *。 (您可以省略AS,但仅在所需的输出名称与任何 PostgreSQL 关键字不匹配时(请参见Appendix C)。为了防止将来可能再添加关键字,建议始终将AS或双引号引起来。)如果您未指定列名,则 PostgreSQL 将自动选择一个名称。如果列的表达式是简单的列引用,则所选名称与该列的名称相同。在更复杂的情况下,可以使用函数或类型名称,或者系统可以使用生成的名称(例如?column?)。

输出列的名称可用于在ORDER BYGROUP BY子句中引用该列的值,但不能在WHEREHAVING子句中引用;在那里,您必须写出表达式。

代替表达式,*可以作为所选行的所有列的速记形式写在输出列表中。另外,您可以写table_name.*作为该表的列的简写。在这些情况下,无法使用AS指定新名称;输出列名称将与表列名称相同。

根据 SQL 标准,应在应用DISTINCTORDER BYLIMIT之前计算输出列表中的表达式。当使用DISTINCT时,这显然是必要的,因为否则不清楚将哪些值区分。但是,在许多情况下,如果在ORDER BYLIMIT之后计算输出表达式是很方便的;特别是在输出列表包含任何易失性或昂贵函数的情况下。通过这种行为,函数求值的 Sequences 更加直观,并且不会有与从不出现在输出中的行相对应的求值。 PostgreSQL 将在排序和限制之后有效地评估输出表达式,只要DISTINCTORDER BYGROUP BY中未引用这些表达式即可。 (作为反例,SELECT f(x) FROM tab ORDER BY 1显然必须在排序之前对f(x)进行求值.)包含有 set-returning 函数的输出表达式在排序之后和限制之前都会得到有效求值,因此LIMIT会切断来自 set-returning 函数的输出。

Note

9.6 之前的 PostgreSQL 版本没有提供关于输出表达式求值与排序和限制的时间的任何保证;它取决于所选查询计划的形式。

DISTINCT Clause

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

SELECT DISTINCT ON ( expression [, ...] )仅保留给定表达式等于的每组行的第一行。使用与ORDER BY相同的规则来解释DISTINCT ON表达式(请参见上文)。请注意,除非使用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组中所需的行优先级。

当前,无法用DISTINCT指定FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

UNION Clause

UNION子句具有以下一般形式:

select_statement UNION [ ALL | DISTINCT ] select_statement
  • select_statement *是任何没有ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE子句的SELECT语句。 (如果将ORDER BYLIMIT括在括号中,则可以将其附加到子表达式.不带括号的话,这些子句将应用于UNION的结果,而不是其右侧 Importing 表达式.)

UNION运算符计算所涉及的SELECT语句返回的行的集合并集。如果行出现在至少一个结果集中,则该行位于两个结果集中的集合并集中。表示UNION的直接操作数的两个SELECT语句必须产生相同数量的列,并且对应的列必须具有兼容的数据类型。

除非指定了ALL选项,否则UNION的结果不包含任何重复的行。 ALL防止重复项的消除。 (因此,UNION ALL通常比UNION快得多;可以使用ALL.)可以编写DISTINCT来明确指定消除重复行的默认行为。

除非括号中另有说明,否则同一SELECT语句中的多个UNION运算符从左到右求值。

当前,不能为UNION结果或UNION的任何 Importing 指定FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

INTERSECT Clause

INTERSECT子句具有以下一般形式:

select_statement INTERSECT [ ALL | DISTINCT ] select_statement
  • select_statement *是任何没有ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE子句的SELECT语句。

INTERSECT运算符计算所涉及的SELECT语句返回的行的集合交集。如果一行出现在两个结果集中,则该行位于两个结果集中的交集。

除非指定了ALL选项,否则INTERSECT的结果不包含任何重复的行。使用ALL,在左表中具有* m 重复项和在右表中具有 n 重复项的行将在结果集中出现 min( m n *)次。可以编写DISTINCT来明确指定消除重复行的默认行为。

除非括号中另有规定,否则在同一SELECT语句中的多个INTERSECT运算符从左到右求值。 INTERSECT的绑定比UNION的绑定更紧密。也就是说,A UNION B INTERSECT C将被读取为A UNION (B INTERSECT C)

当前,不能为INTERSECT结果或INTERSECT的任何 Importing 指定FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

EXCEPT Clause

EXCEPT子句具有以下一般形式:

select_statement EXCEPT [ ALL | DISTINCT ] select_statement
  • select_statement *是任何没有ORDER BYLIMITFOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE子句的SELECT语句。

EXCEPT运算符将计算左SELECT语句的结果中的行集,而不计算右右语句的结果。

除非指定了ALL选项,否则EXCEPT的结果不包含任何重复的行。使用ALL,在左表中具有* m 重复项并且在右表中具有 n 重复项的行将在结果集中出现 max( m - n *,0)次。可以编写DISTINCT来明确指定消除重复行的默认行为。

除非括号中另有规定,否则在同一SELECT语句中的多个EXCEPT运算符从左到右求值。 EXCEPT的绑定级别与UNION相同。

当前,不能为EXCEPT结果或EXCEPT的任何 Importing 指定FOR NO KEY UPDATEFOR UPDATEFOR SHAREFOR KEY SHARE

ORDER BY 条款

可选的ORDER BY子句具有以下一般形式:

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

ORDER BY子句使结果行根据指定的表达式排序。如果根据最左边的表达式两行相等,则根据下一个表达式对它们进行比较,依此类推。如果根据所有指定的表达式它们相等,则将根据实现的 Sequences 返回它们。

每个* expression *可以是输出列(SELECT列表项)的名称或序号,也可以是由 Importing 列值组成的任意表达式。

序号是指输出列的序数位置(从左到右)。通过此功能,可以基于没有唯一名称的列来定义 Sequences。这绝对不是绝对必要的,因为始终可以使用AS子句为输出列分配名称。

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

SELECT name FROM distributors ORDER BY code;

此功能的局限性在于,应用于UNIONINTERSECTEXCEPT子句结果的ORDER BY子句只能指定输出列名称或数字,而不能指定表达式。

如果ORDER BY表达式是与输出列名和 Importing 列名都匹配的简单名称,则ORDER BY会将其解释为输出列名。这与GROUP BY在相同情况下所做的选择相反。使该不一致与 SQL 标准兼容。

可以选择在ORDER BY子句中的任何表达式之后添加关键字ASC(升序)或DESC(降序)。如果未指定,则默认为ASC。或者,可以在USING子句中指定特定的排序运算符名称。Order 运算符必须是小于或大于某些 B 树运算符系列的成员。 ASC通常等效于USING <,而DESC通常等效于USING >。 (但是,用户定义的数据类型的创建者可以准确定义默认的排序 Sequences,并且它可能与其他名称的运算符相对应.)

如果指定了NULLS LAST,则空值将在所有非空值之后排序;如果指定了NULLS FIRST,则空值将在所有非空值之前排序。如果两者均未指定,则默认行为是NULLS LAST(当指定或隐含ASC时)和NULLS FIRST(当指定或隐含DESC时)(因此,默认值的作用是空值大于非空值)。指定USING时,默认的空值排序取决于运算符是小于运算符还是大于运算符。

注意,排序选项仅适用于它们遵循的表达式。例如ORDER BY x, y DESCORDER BY x DESC, y DESC的含义不同。

字符串数据是根据应用于要排序的列的排序规则进行排序的。可以通过在* expression *中包含COLLATE子句(例如ORDER BY mycolumn COLLATE "en_US")来覆盖该值。有关更多信息,请参见Section 4.2.10Section 23.2

LIMIT Clause

LIMIT子句包含两个独立的子句:

LIMIT { count | ALL }
OFFSET start
  • count 指定要返回的最大行数,而 start 指定要开始返回的行之前要跳过的行数。如果同时指定了两者,则在开始对要返回的 count 行进行计数之前,将跳过 start *行。

如果* count 表达式的结果为 NULL,则将其视为LIMIT ALL,即无限制。如果 start *评估为 NULL,则将其与OFFSET 0相同。

SQL:2008 引入了不同的语法来实现相同的结果,PostgreSQL 也支持该语法。它是:

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

在这种语法中,标准要求* start count 值为 Literals 常量,参数或变量名;作为 PostgreSQL 扩展,允许使用其他表达式,但通常需要将其括在括号中以避免歧义。如果在FETCH子句中省略 count *,则默认值为 1.ROWROWS以及FIRSTNEXT是不影响这些子句效果的干扰词。根据标准,如果同时存在OFFSET子句,则必须在FETCH子句之前;但是 PostgreSQL 比较宽松,并且可以使用任何 Sequences。

使用LIMIT时,最好使用ORDER BY子句将结果行约束为唯一 Sequences。否则,您将获得查询行的不可预测的子集-您可能会要求 Importing 第十到第二十行,但是要求的 Sequences 是第十到第二十行?除非您指定ORDER BY,否则您不知道该如何排序。

查询计划程序在生成查询计划时会考虑LIMIT,因此根据LIMITOFFSET的用途,您很可能会获得不同的计划(产生不同的行 Sequences)。因此,除非使用ORDER BY强制执行可预测的结果排序,否则使用不同的LIMIT/OFFSET值来选择查询结果的不同子集会得出不一致的结果。这不是错误;除非使用ORDER BY约束该 Sequences,否则 SQL 不会保证以任何特定 Sequences 传递查询结果,这是一个固有的结果。

如果没有ORDER BY来强制执行确定性子集的选择,则甚至可以重复执行同一LIMIT查询以返回表行的不同子集。再次,这不是错误;在这种情况下,不能保证结果的确定性。

锁定条款

FOR UPDATEFOR NO KEY UPDATEFOR SHAREFOR KEY SHARE锁定子句;它们会影响SELECT锁定从表中获取的行的方式。

锁定子句具有一般形式

FOR lock_strength [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ]
  • lock_strength *可以是以下其中一个
UPDATE
NO KEY UPDATE
SHARE
KEY SHARE

有关每种行级锁定模式的更多信息,请参考Section 13.3.2

为防止该操作 await 其他事务提交,请使用NOWAITSKIP LOCKED选项。使用NOWAIT,如果不能立即锁定选定的行,则该语句报告错误,而不是 await。使用SKIP LOCKED,将跳过所有不能立即锁定的选定行。跳过锁定的行会提供不一致的数据视图,因此这不适用于一般用途的工作,但可用于避免多个使用者访问类似队列的表时发生的锁争用。请注意,NOWAITSKIP LOCKED仅适用于行级锁-所需的ROW SHARE表级锁仍以常规方式获取(请参见Chapter 13)。如果需要不 await 就获取表级锁,则可以先将LOCKNOWAIT选项一起使用。

如果在锁定子句中指定了特定的表,则仅锁定那些表中的行;照常读取SELECT中使用的任何其他表。没有表列表的锁定子句会影响该语句中使用的所有表。如果将锁定子句应用于视图或子查询,则它将影响该视图或子查询中使用的所有表。但是,这些子句不适用于主要查询引用的WITH查询。如果希望在WITH查询中发生行锁定,请在WITH查询中指定锁定子句。

如果有必要为不同的表指定不同的锁定行为,则可以编写多个锁定子句。如果同一表被多个锁定子句提及(或隐式影响),则将其视为仅由最强的子表指定。同样,如果在影响表的任何子句中指定了表,则表将被处理为NOWAIT。否则,如果在影响它的任何子句中指定了该参数,它将被处理为SKIP LOCKED

在无法用单独的表行清楚地标识返回的行的上下文中,不能使用锁定子句;例如,它们不能与聚合一起使用。

当锁定子句出现在SELECT查询的顶层时,锁定的行与查询返回的行完全相同。对于联接查询,锁定的行是那些有助于返回联接行的行。另外,满足查询条件的行将自查询快照起被锁定,尽管如果在快照后对其进行更新并且不再满足查询条件,则不会返回这些行。如果使用LIMIT,一旦返回了足够的行以满足限制,锁定就会停止(但请注意,被OFFSET跳过的行将被锁定)。同样,如果在游标的查询中使用了锁定子句,则仅锁定实际被游标读取或跳过的行。

当子句SELECT中出现锁定子句时,锁定的行是子查询返回给外部查询的行。这可能涉及比仅检查子查询建议的行少的行,因为来自外部查询的条件可能用于优化子查询的执行。例如,

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

将仅锁定具有col1 = 5的行,即使该条件在文本上不在子查询中。

以前的版本无法保留由以后的保存点升级的锁。例如,此代码:

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

将无法在ROLLBACK TO之后保留FOR UPDATE锁定。此问题已在 9.3 版中修复。

Caution

READ COMMITTED事务隔离级别运行并使用ORDER BY和锁定子句的SELECT命令有可能返回无序的行。这是因为先应用ORDER BY。该命令对结果进行排序,但随后可能会阻止尝试获得对一个或多个行的锁定。一旦SELECT解除阻止,某些排序列的值可能已被修改,从而导致这些行似乎是乱序的(尽管就原始列值而言,它们是有序的)。可以通过在子查询中放置FOR UPDATE/SHARE子句来解决此问题,例如

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

请注意,这将导致锁定mytable的所有行,而位于顶层的FOR UPDATE将仅锁定实际返回的行。这可能会导致明显的性能差异,特别是如果ORDER BYLIMIT或其他限制结合使用时。因此,仅当期望并发更新排序列并且需要严格排序的结果时,才建议使用此技术。

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

TABLE Command

The command

TABLE name

相当于

SELECT * FROM name

在部分复杂查询中,它可用作顶级命令或节省空间的语法变体。 TABLE只能使用WITHUNIONINTERSECTEXCEPTORDER BYLIMITOFFSETFETCHFOR锁定子句;不能使用WHERE子句和任何形式的聚合。

Examples

要将表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

这是添加了序数列的函数的示例:

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,后跟查询的递归部分。确保查询的递归部分最终不会返回任何 Tuples,否则查询将无限期地循环。 (有关更多示例,请参见Section 7.8。)

本示例使用LATERALmanufacturers表的每一行应用返回集合的函数get_product_names()

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

当前没有任何产品的制造商不会出现在结果中,因为它是内部联接。如果我们希望在结果中包括此类制造商的名称,则可以执行以下操作:

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

Compatibility

当然,SELECT语句与 SQL 标准兼容。但是有一些扩展和缺少的功能。

省略了 FROM 子句

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

SELECT 2+2;

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

其他一些 SQL 数据库无法做到这一点,除非引入一个虚拟的单行表来执行SELECT

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

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

PostgreSQL 在 8.1 之前的版本将接受这种形式的查询,并为查询所引用的每个表在查询的FROM子句中添加一个隐式条目。不再允许这样做。

空的 SELECT 列表

SELECT之后的输出表达式列表可以为空,从而生成零列结果表。根据 SQL 标准,这是无效的语法。 PostgreSQL 允许它与允许零列表保持一致。但是,使用DISTINCT时不允许使用空列表。

省略 AS 关键字

在 SQL 标准中,只要新列名是有效的列名(即与任何保留关键字不同),就可以在输出列名之前省略可选关键字AS。 PostgreSQL 的限制更严格:如果新的列名称完全匹配任何关键字(保留或不保留),则需要AS。推荐的做法是使用AS或双引号输出列名,以防止与将来添加关键字的任何可能的冲突。

FROM项中,标准和 PostgreSQL 都允许在作为未保留关键字的别名之前省略AS。但是由于语法上的歧义,这对于输出列名称是不切实际的。

仅与继承

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

PostgreSQL 允许写入尾随*以显式指定包括子表在内的非ONLY行为。该标准不允许这样做。

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

TABLESAMPLE 子句限制

当前仅在常规表和实例化视图上接受TABLESAMPLE子句。根据 SQL 标准,应该可以将其应用于任何FROM项。

来自 FROM 的函数调用

PostgreSQL 允许将函数调用直接编写为FROM列表的成员。在 SQL 标准中,有必要将此类函数调用包装在 sub_SELECT中。也就是说,语法FROM func(...) alias大约等于FROM LATERAL (SELECT func(...)) alias。注意LATERAL被认为是隐式的;这是因为该标准要求FROM中的UNNEST()项具有LATERAL语义。 PostgreSQL 与其他返回集合的函数一样对待UNNEST()

命名空间可用于 GROUP BY 和 ORDER BY

在 SQL-92 标准中,ORDER BY子句只能使用输出列名称或数字,而GROUP BY子句只能使用基于 Importing 列名称的表达式。 PostgreSQL 扩展了每个子句以允许其他选择(但是如果有歧义,它会使用标准的解释)。 PostgreSQL 还允许两个子句都指定任意表达式。请注意,出现在表达式中的名称将始终被视为 Importing 列名称,而不是输出列名称。

SQL:1999 和更高版本使用略有不同的定义,该定义并不完全向上兼容 SQL-92.但是,在大多数情况下,PostgreSQL 将以与 SQL:1999 相同的方式解释ORDER BYGROUP BY表达式。

Functional Dependencies

PostgreSQL 仅在表的主键包含在GROUP BY列表中时才识别功能依赖性(允许从GROUP BY省略列)。 SQL 标准指定了应识别的其他条件。

LIMIT 和 OFFSET

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

FOR NO KEY UPDATE,FOR UPDATE,FOR SHARE,FOR KEY SHARE

尽管FOR UPDATE出现在 SQL 标准中,但该标准仅允许将其作为DECLARE CURSOR的选项。 PostgreSQL 允许它在任何SELECT查询以及 subSELECT中使用,但这是一个扩展。 FOR NO KEY UPDATEFOR SHAREFOR KEY SHARE变体以及NOWAITSKIP LOCKED选项未出现在标准中。

WITH 中的数据修改语句

PostgreSQL 允许INSERTUPDATEDELETE用作WITH查询。在 SQL 标准中找不到。

Nonstandard Clauses

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

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