SELECT、TABLE、WITH — 从表或视图中检索行
[ WITH [ RECURSIVE ]with_query
[, ...] ] SELECT [ ALL | DISTINCT [ ON (expression
[, ...] ) ] ] [ { * |expression
[ [ AS ]output_name
] } [, ...] ] [ FROMfrom_item
[, ...] ] [ WHEREcondition
] [ GROUP BY [ ALL | DISTINCT ]grouping_element
[, ...] ] [ HAVINGcondition
] [ WINDOWwindow_name
AS (window_definition
) [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ]select
] [ ORDER BYexpression
[ ASC | DESC | USINGoperator
] [ NULLS { FIRST | LAST } ] [, ...] ] [ LIMIT {count
| ALL } ] [ OFFSETstart
[ ROW | ROWS ] ] [ FETCH { FIRST | NEXT } [count
] { ROW | ROWS } { ONLY | WITH TIES } ] [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OFfrom_reference
[, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ] wherefrom_item
can be one of: [ ONLY ]table_name
[ * ] [ [ AS ]alias
[ (column_alias
[, ...] ) ] ] [ TABLESAMPLEsampling_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
join_type
from_item
{ ONjoin_condition
| USING (join_column
[, ...] ) [ ASjoin_using_alias
] }from_item
NATURALjoin_type
from_item
from_item
CROSS JOINfrom_item
andgrouping_element
can be one of: ( )expression
(expression
[, ...] ) ROLLUP ( {expression
| (expression
[, ...] ) } [, ...] ) CUBE ( {expression
| (expression
[, ...] ) } [, ...] ) GROUPING SETS (grouping_element
[, ...] ) andwith_query
is:with_query_name
[ (column_name
[, ...] ) ] AS [ [ NOT ] MATERIALIZED ] (select
|values
|insert
|update
|delete
|merge
) [ SEARCH { BREADTH | DEPTH } FIRST BYcolumn_name
[, ...] SETsearch_seq_col_name
] [ CYCLEcolumn_name
[, ...] SETcycle_mark_col_name
[ TOcycle_mark_value
DEFAULTcycle_mark_default
] USINGcycle_path_col_name
] TABLE [ ONLY ]table_name
[ * ]
SELECT
检索零个或多个表中的行。对 SELECT
的常规处理如下
在 WITH
列表中的所有查询都会计算。它们实际上充当了临时表,可在 FROM
列表中引用。在 FROM
中多次引用的 WITH
查询仅计算一次,除非使用 NOT MATERIALIZED
另有指定。(参见下文的 WITH 子句。)
在 FROM
列表中的所有元素都会计算。(FROM
列表中的每个元素都是真实的或虚拟的表。)如果在 FROM
列表中指定了多个元素,它们将交叉联接在一起。(参见下文的 FROM 子句。)
如果指定了 WHERE
子句,则将从输出中消除所有不满足条件的行。(参见下文的 WHERE 子句。)
如果指定了 GROUP BY
子句,或者有聚合函数调用,则输出会合并到匹配一个或多个值的各个行组中,并计算聚合函数结果。如果存在 HAVING
子句,它将消除不满足给定条件的组。(参见下文的 GROUP BY 子句 和 HAVING 子句。)尽管名义上在下一步计算查询输出列,但在 GROUP BY
子句中也可以引用它们(通过名称或序数)。
实际输出行是使用每个选定行或行组的 SELECT
输出表达式计算的。(参见下文的 SELECT 列表。)
SELECT DISTINCT
从结果中消除重复行。SELECT DISTINCT ON
消除与所有指定表达式相匹配的行。SELECT ALL
(默认值)将返回所有候选行,包括重复行。(参见下文的 DISTINCT 子句。)
使用运算符 UNION
、INTERSECT
和 EXCEPT
可以将多个 SELECT
语句的输出组合起来,形成一个单一的结果集。运算符 UNION
返回一个或两个结果集中所有的行。运算符 INTERSECT
返回两个结果集中严格相同的行。运算符 EXCEPT
返回在第一个结果集中、但不包含在第二个结果集中的行。在这三种情况下,除非指定了 ALL
,否则将消除全部的重复行。可以添加干扰词 DISTINCT
来明确指定消除重复行。请注意,即使 ALL
是 SELECT
本身的默认值,但 DISTINCT
是这里面的默认行为。(请参见以下 UNION 子句、INTERSECT 子句 和 EXCEPT 子句)。
如果指定了 ORDER BY
子句,则返回的行会按照指定顺序排序。如果未指定 ORDER BY
,则以系统能够生产的最快速度返回行。(请参见以下 ORDER BY 子句)。
如果指定了 LIMIT
(或 FETCH FIRST
)或 OFFSET
子句,则 SELECT
语句只返回结果行的一个子集。(请参见以下 LIMIT 子句)。
如果指定了 FOR UPDATE
、FOR NO KEY UPDATE
、FOR SHARE
或 FOR KEY SHARE
,SELECT
语句会锁定选定的行以防止并发更新。(请参见以下 锁定子句
您必须具有对 SELECT
命令中使用的每列的 SELECT
权限。使用 FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
或 FOR KEY SHARE
还需要同时具有 UPDATE
权限(至少对于每个选定表的其中一列)。
WITH
子句使用 WITH
子句可以指定一个或多个子查询,主查询可以通过名称引用这些子查询。子查询在主查询持续期间有效地充当临时表或视图。每个子查询可以是 SELECT
、TABLE
、VALUES
、INSERT
、UPDATE
、DELETE
或 MERGE
语句。在 WITH
中编写数据修改语句(INSERT
、UPDATE
、DELETE
或 MERGE
)时,通常会包含 RETURNING
子句。是 RETURNING
的输出(而不是 语句修改的基础表)形成了主查询读取的临时表。如果省略 RETURNING
,语句仍会执行,但不会生成任何输出,因此主查询无法将其作为表引用。
必须为每个 WITH
查询指定一个名称(不带模式限定)。可以选择指定一个列名列表;如果省略,则从子查询推断出列名。
如果指定 RECURSIVE
,则它允许 SELECT
子查询以名称引用自身。此类子查询必须采用以下形式:
non_recursive_term
UNION [ ALL | DISTINCT ]recursive_term
其中,递归自引用必须出现在 UNION
的右侧。每个查询只允许有一个递归自引用。不支持递归数据修改语句,但是可以在数据修改语句中使用递归 SELECT
查询的结果。有关示例,请参阅第 7.8 节。
RECURSIVE
的另一个效果是 WITH
查询无需按顺序排列:一个查询可以引用列表中后面的另一个查询。(但是,循环引用或相互递归未实现。)如果没有 RECURSIVE
,WITH
查询只能引用 WITH
列表中较早的兄弟 WITH
查询。
如果 WITH
子句中有多个查询,则应在紧跟 WITH
之后只写一次 RECURSIVE
。它适用于 WITH
子句中的所有查询,尽管它对不使用递归或前向引用的查询没有影响。
可选 SEARCH
子句计算一个 搜索序列列,它可用于以广度优先或深度优先顺序对递归查询的结果进行排序。提供列名称列表,指定用来跟踪已访问行数的行关键字。名为 search_seq_col_name
的列将添加到 WITH
查询的结果列列表中。此列可由外部查询进行排序,以实现各自的排序。有关示例,请参阅 第 7.8.2.1 节。
可选的 CYCLE
子句用于检测递归查询中的循环。提供列名称列表,指定用来跟踪已访问行数的行关键字。名为 cycle_mark_col_name
的列将添加到 WITH
查询的结果列列表中。当检测到循环时,此列将设置为 cycle_mark_value
,否则设置为 cycle_mark_default
。此外,当检测到循环时,递归联合的处理将停止。 cycle_mark_value
和 cycle_mark_default
必须为常量,并且必须可强制转换为通用数据类型,且数据类型必须具有不等式运算符。(SQL 标准要求它们是布尔常量或字符串,但 PostgreSQL 并不做此要求。)默认情况下,使用 TRUE
和 FALSE
(类型为 boolean
)。此外,名为 cycle_path_col_name
的列将添加到 WITH
查询的结果列列表中。此列在内部用于跟踪已访问的行。有关示例,请参阅 第 7.8.2.2 节。
SEARCH
和 CYCLE
子句仅对递归 WITH
查询有效。 with_query
必须是两个 SELECT
(或等效)命令(没有嵌套 UNION
)的 UNION
(或 UNION ALL
)。如果同时使用两个子句,则 SEARCH
子句添加的列会显示在 CYCLE
子句添加的列之前。
主查询和 WITH
查询都在(概念上)同时执行。这意味着在 WITH
中的数据修改语句的效果无法从查询的其他部分看到,只能通过读取其 RETURNING
输出看到。如果两个此类数据修改语句尝试修改同一行,则结果是未指定的。
WITH
查询的一个关键属性是它们通常每个主查询执行一次,即便主查询引用它们多次。特别是,无论主查询是否读取所有或部分输出,数据修改语句都保证仅执行一次。
但是,可以将 WITH
查询标记为 NOT MATERIALIZED
来取消此保证。在这种情况下,WITH
查询可以折叠到主查询中,就像它们是主查询 FROM
子句中的一个简单的子 SELECT
一样。如果主查询引用该 WITH
查询多次,则会导致重复计算;但是,如果每次使用仅需要 WITH
查询总输出的几行,那么 NOT MATERIALIZED
可以通过允许联合优化查询来提供净节约。如果 NOT MATERIALIZED
附加到递归或非副作用(即不是不包含不稳定函数的纯 SELECT
)的 WITH
查询上,则将忽略它。
默认情况下,如果在主查询的 FROM
子句中仅使用一次,则将副作用为 WITH
的查询折叠到主查询中。这允许在语义上不可见的情况下对两个查询级别进行联合优化。然而,可以通过将 WITH
查询标记为 MATERIALIZED
来防止这种折叠。例如,如果 WITH
查询被用作优化围栏以防止计划程序选择错误的计划,这可能很有用。PostgreSQL v12 之前的版本从未进行过此类折叠,因此为较旧版本编写的查询可能依赖于 WITH
作为优化围栏。
有关更多信息,请参阅第 7.8 节。
FROM
子句FROM
子句为 SELECT
指定一个或多个源表。如果指定了多个源,结果便是所有源的笛卡尔积(交叉联接)。但通常会添加限定条件(通过 WHERE
)将返回的行限制为笛卡尔积的一小部分。
FROM
子句可以包含以下元素
table_name
现有表或视图的名称(可选择限定模式)。如果在表名前指定了 ONLY
,则只扫描该表。如果未指定 ONLY
,则扫描该表及其所有后代表(如果存在)。还可以选择在表名后指定 *
,以明确表示包括后代表。
alias
包含别名的 FROM
项的替代名称。别名用于简短起见或消除自联接(同一张表被多次扫描)的歧义。当提供别名时,它会完全隐藏表名或函数的实际名称;例如,给定 FROM foo AS f
,剩下的 SELECT
必须将此 FROM
项引用为 f
,而不是 foo
。如果编写了别名,还可以编写一个列别名字段,为表的其中一列或多列提供替代名称。
TABLESAMPLE sampling_method
( argument
[, ...] ) [ REPEATABLE ( seed
) ]
table_name
后面的 TABLESAMPLE
子句指示应使用指定的 sampling_method
检索该表中的一行子集。此采样先于任何其他筛选器的应用,如 WHERE
子句。标准的 PostgreSQL 发行版包含两种抽样方法,即 BERNOULLI
和 SYSTEM
,此外可通过扩展程序将其他抽样方法安装到数据库中。
BERNOULLI
和 SYSTEM
抽样方法分别接受单个 参数
,它是表格抽样部分,表示为介于 0 和 100 之间的百分比。此参数可以是任何 real
值表达式。(其他抽样方法可能会接受更多或不同的参数。)这两个方法分别返回表格的随机选定样本,该样本将包含大约指定百分比的表格行。BERNOULLI
方法扫描整个表格,并按照指定概率独立选择或忽略各个行。SYSTEM
方法进行块级抽样,每个块都被指定概率选择;将返回每个选定块中的所有行。SYSTEM
方法显著快于 BERNOULLI
方法(在指定的小抽样百分比时),但由于集群效应,它可能会返回表格的随机程度较低的样本。
可选的 REPEATABLE
子句指定一个 种子
号码或表达式,用于在抽样方法中生成随机数。种子值可以是任何非空浮点值。如果表格在 meantime 未发生更改,则指定相同种子和 参数
值的两个查询将选择表格的相同样本。但是,不同的种子值通常会产生不同的样本。如果不给出 REPEATABLE
,那么将为每个查询选择新的随机样本,该样本基于系统生成的种子。请注意,某些附加抽样方法不接受 REPEATABLE
,并且每次使用时总会产生新的样本。
选择
子 SELECT
可以出现在 FROM
子句中。这会起到如下作用,就好像其输出被创建为临时表格一样,且仅在这一单一 SELECT
命令的持续时间内。请注意,子 SELECT
必须用括号括起来,并且可以像表格一样提供别名。此处还可以使用 VALUES
命令。
with_query_name
通过编写 WITH
查询的名称来引用它,就好像查询的名称是表格名称一样。(实际上,对于主查询的目的而言,WITH
查询将隐藏同名的任何真实表格。如有必要,可以通过表格的名称进行模式限定来引用同名的真实表格。)可以像表格一样提供别名。
function_name
函数调用可以在 FROM
子句中出现。(对于返回结果集的函数,这特别有用,但任何函数都可以使用。)这相当于函数的输出被当作临时的表在此 SELECT
命令的持续时间内创建。如果函数的结果类型是复合类型(包括函数有多个 OUT
参数的情况),每个属性都会在隐式表中成为一列。
当可选的 WITH ORDINALITY
子句添加到函数调用时,一个类型为 bigint
的附加列会追加到该函数的结果列。此列顺序编号函数的结果集行,从 1 开始。默认情况下,此列命名为 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
以下之一
[ INNER ] JOIN
LEFT [ OUTER ] JOIN
RIGHT [ OUTER ] JOIN
FULL [ OUTER ] JOIN
对于 INNER
和 OUTER
连接类型,必须指定连接条件,即 ON
、join_condition
USING (
或 join_column
[, ...])NATURAL
之间的条件。见下文。
JOIN
子句组合了两个 FROM
项,为了方便,我们将它们称为 “tables”,尽管实际上它们可以是任意类型的 FROM
项。如有必要,请使用括号来确定嵌套顺序。如果没有括号,则 JOIN
将从左到右嵌套。无论如何,JOIN
的绑定比分隔 FROM
-list 项的逗号更紧密。所有 JOIN
选项仅仅是符号便利,因为它们不会通过简单的 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
[, ...] ) [ AS join_using_alias
]
形式为 USING ( a, b, ... )
的子句是 ON left_table.a = right_table.a AND left_table.b = right_table.b ...
的简写形式。此外,USING
暗示每一对等效列中只有一列将被包含在连接输出中,而不是两列。
如果指定了join_using_alias
名称,它将为联接列提供表别名。此名称只能寻址USING
子句中列出的联接列。与常规alias
不同,它不会对查询的其余部分隐藏已联接表的名称。此外,与常规alias
不同,您无法编写列别名字段 — 联接列的输出名称与它们在USING
列表中显示的相同。
NATURAL
NATURAL
是USING
列表的一个简写,该列表提到了两个表中所有具有匹配名称的列。如果没有公共列名称,NATURAL
等同于ON TRUE
。
CROSS JOIN
CROSS JOIN
等同于INNER JOIN ON (TRUE)
,也就是说,没有行被资格删除。它们生成一个简单的笛卡尔积,与您从在FROM
的高级别处列出两个表中获得的结果相同,但受联接条件(如果有)的限制。
LATERAL
LATERAL
关键字可以出现在子SELECT
FROM
项之前。这允许子SELECT
引用FROM
列表中其之前的FROM
项的列。(如果没有LATERAL
,每个子SELECT
将独立评估,因此无法交叉引用任何其他FROM
项。)
LATERAL
还可以出现在函数调用FROM
项之前,但在这种情况下它是一个噪音词,因为函数表达式在任何情况下都可以引用早期的FROM
项。
LATERAL
项可以出现在FROM
列表的高级别,或JOIN
树内。在后一种情况下,它还可以引用JOIN
左侧的任何项,即它位于JOIN
的右侧。
如果 FROM
项包含 LATERAL
交叉引用,则计算过程如下:对于提供交叉引用列或者提供多列 FROM
项的列集的 FROM
项的每一行,LATERAL
项计算为使用那些行的列值或者行集。结果行按通常方式与从其计算的行连接起来。对于列源表的每一行或行集,重复此过程。
列源表必须与 LATERAL
项 INNER
或 LEFT
连接,否则就没有定义明确的行集来计算 LATERAL
项的每一行集。因此,即使语法上允许类似于
的结构,实际上也不允许 X
RIGHT JOIN LATERAL Y
Y
引用 X
。
WHERE
子句可选 WHERE
子句的常规格式为
WHERE condition
其中 condition
是任何计算为 boolean
类型结果的表达式。任何不满足此条件的行都将从输出中消除。如果用实际行值替换任何变量引用时返回 true,则该行满足此条件。
GROUP BY
子句可选 GROUP BY
子句的常规格式为
GROUP BY [ ALL | DISTINCT ] grouping_element
[, ...]
GROUP BY
将所有对分组表达式具有相同值的选中行浓缩为一行。在 grouping_element
中使用的 expression
可以是输入列名称,或者输出列(SELECT
列表项)的名称或序号,或者由输入列值形成的任意表达式。当模棱两可时,GROUP BY
名称会被解释为输入列名称而非输出列名称。
如果 GROUPING SETS
、ROLLUP
或 CUBE
作为分组元素出现,则整个 GROUP BY
子句定义一些独立的 grouping sets
。其效果等同于在子查询之间构造一个 UNION ALL
,子查询的 GROUP BY
子句作为其单个分组集使用。可选的 DISTINCT
子句删除重复的集,然后才进行处理;它不会将 UNION ALL
转换为 UNION DISTINCT
。有关分组集处理的详细信息,请参阅7.2.4 节。
如果有聚合函数参与运算的话,这些函数作用于组成每个分组的所有行,针对每个分组产生一个独立的值。(如果存在聚合函数但没有 GROUP BY
从句,则查询被视为只有一个,包含所有所选行的分组。)可以通过在聚合函数调用上附加一个 FILTER
从句来进一步筛选提供给每个聚合函数的行集;有关更多信息,请参见 第 4.2.7 节。如果存在 FILTER
从句,只有与之匹配的行才包含在提供给该聚合函数的输入中。
如果存在 GROUP BY
或者任何聚合函数,那么 SELECT
列表表达式引用未分组的列是不允许的(聚合函数内或未分组的列在分组列上函数相关的情况下除外),因为这会导致必须返回多个针对未分组列可能的列值。如果表中包含未分组列的分组列(或其子集)为主键,那么就会存在函数相关性。
请注意,在计算 HAVING
从句或 SELECT
列表中的任何 “标量” 表达式之前,都会计算所有聚合函数。这意味着例如无法使用 CASE
表达式来跳过聚合函数的计算;请参见 第 4.2.14 节。
目前,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
中的每列都必须明确地引用分组列,除非该引用出现在聚合函数内,或者未分组的列在分组列上是函数相关的。
存在 HAVING
会让查询变成分组查询,即使没有 GROUP BY
子句。这与当查询含有聚合函数但没有 GROUP BY
子句时一样。所有选定的行都被当作形成一个单一组,并且 SELECT
列表和 HAVING
子句只能在聚合函数中引用表列。如果 HAVING
条件为真,这样的查询会发出单行;如果它不为真,则发出 0 行。
目前,FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
和 FOR KEY SHARE
无法和 HAVING
一起指定。
WINDOW
子句可选的 WINDOW
子句有以下通式
WINDOWwindow_name
AS (window_definition
) [, ...]
其中 window_name
是可以从 OVER
子句或后续窗口定义中引用的名称,window_definition
是
[existing_window_name
] [ PARTITION BYexpression
[, ...] ] [ ORDER BYexpression
[ ASC | DESC | USINGoperator
] [ 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 } BETWEENframe_start
ANDframe_end
[frame_exclusion
]
其中 frame_start
和 frame_end
可以是以下之一
UNBOUNDED PRECEDINGoffset
PRECEDING CURRENT ROWoffset
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
相同;它将框架设置为从分区开始到当前行的最后一个 对等行(窗口的 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
)或大 offset
(对于 FOLLOWING
)的行。在这些情况下,offset
表达式的类型取决于排序列的类型。对于数字排序列,它通常与排序列的类型相同,但对于日期时间排序列,它是一个 interval
。在所有这些情况下,offset
的值必须为非空和非负。另外,虽然 offset
不必是一个简单的常量,但它不能包含变量、聚合函数或窗口函数。
frame_exclusion
选项允许将当前行周围的行从框架中排除,即使它们会根据框架起始和框架结束选项而被包含。EXCLUDE CURRENT ROW
将当前行从框架中排除。EXCLUDE GROUP
将当前行及其排序对等行从框架中排除。EXCLUDE TIES
将当前行所有对等行从框架中排除,但不排除当前行本身。EXCLUDE NO OTHERS
只是明确指定了默认行为,即不排除当前行或其对等行。
请注意,如果 ORDER BY
排序并未对行进行唯一排序,ROWS
模式可能产生不可预测的结果。RANGE
和 GROUPS
模式旨在确保在 ORDER BY
排序中为对等的行提供一致对待:给定对等组的所有行都将在框架中或从框架中排除。
WINDOW
子句的目的是指定查询的 SELECT
列表 或 ORDER BY
子句中出现的 窗口函数 的行为。这些函数可以在 OVER
子句中按名称引用 WINDOW
子句条目。但是,不必在任何地方引用 WINDOW
子句条目;如果它未在查询中使用,则将简单地忽略它。可以使用窗口函数,而完全不使用任何 WINDOW
子句,因为窗口函数调用可以在其 OVER
子句中直接指定窗口定义。然而,当同一窗口定义对多个窗口函数都是必需时,WINDOW
子句可以节省输入。
目前,无法使用带有 WINDOW
的 FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
和 FOR KEY SHARE
。
SELECT
列表SELECT
列表(关键字 SELECT
和 FROM
之间)指定形成 SELECT
语句输出行的表达式。这些表达式可以引用(而且通常也引用) FROM
子句中计算的列。
正如在表中一样, SELECT
的每个输出列都有一个名称。在简单的 SELECT
中,此名称仅用于给列贴标签以显示,但当 SELECT
是更大查询的子查询时,该名称由更大的查询视为子查询生成的虚拟表的列名称。要指定用于输出列的名称,请在列的表达式后面写 AS
output_name
。(您可以省略 AS
,但仅当所需的输出名称与任何 PostgreSQL 关键字不匹配时(请参阅 附录 C)。为了防止未来可能添加的关键字,建议您始终编写 AS
或给输出名称加引号。)如果您未指定列名称,PostgreSQL 会自动选择一个名称。如果该列的表达式是一个简单的列引用,则选取的名称与该列的名称相同。在更复杂的情况下,可以使用函数或类型名称,或者系统可能会使用生成名称,如 ?column?
。
输出列的名称可用于在 ORDER BY
和 GROUP BY
子句中引用该列的值,但不能在 WHERE
或 HAVING
子句中引用;在那里您必须改为写出表达式。
在输出列表中可以写 *
替代一个表达式,它表示所有所选行的列的速写。此外,您可以使用
表示只来自该表的列的速写。在这些情况下,无法使用 table_name
.*AS
指定新的名称;输出列名称将与表列的名称相同。
根据 SQL 标准,在应用 DISTINCT
、ORDER BY
或 LIMIT
之前,应计算出输出列表中的表达式。在使用 DISTINCT
时,此操作显然很有必要,因为否则不明确区分了哪些值。但是,在许多情况下,如果在 ORDER BY
和 LIMIT
之后计算输出表达式会很方便;特别是如果输出列表包含任何不稳定或开销大的函数时。如果采用这种行为,函数评估的顺序会更直观,而且不会对从未出现在输出中的行进行评估。PostgreSQL 将有效地在排序和限定之后评估输出表达式,前提是这些表达式未在 DISTINCT
、ORDER BY
或 GROUP BY
中引用。(反例:SELECT f(x) FROM tab ORDER BY 1
在排序之前显然必须评估 f(x)
。)包含集返回函数的输出表达式会在排序之后和限定之前有效地计算,这样 LIMIT
将起作用,从集返回函数中截断输出。
PostgreSQL 9.6 之前的版本不保证输出表达式的评估时间与排序和限定的时间相同;这取决于所选查询计划的形式。
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
以明确指定消除重复行的默认行为。
同一 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
语句结果中但不存在右侧结果中的行集。
EXCEPT
的结果不包含任何重复行,除非指定了 ALL
选项。使用 ALL
时,左表中有 m
个重复行,右表中有 n
个重复行的行将在结果集中显示 max(m
-n
,0) 次。可以编写 DISTINCT
来明确指定消除重复行的默认行为。
同一 SELECT
语句中多个 EXCEPT
运算符从左向右求值,除非括号另有指示。 EXCEPT
的绑定级别与 UNION
相同。
目前,FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
和 FOR KEY SHARE
既不能针对 EXCEPT
结果指定,也不能针对 EXCEPT
的任何输入指定。
ORDER BY
子句可选的 ORDER BY
子句具有以下常规格式
ORDER BYexpression
[ ASC | DESC | USINGoperator
] [ 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"
。有关详细信息,请参阅 第 4.2.10 节 和 第 23.2 节。
LIMIT
子句LIMIT
子句由两个独立的子句组成
LIMIT {count
| ALL } OFFSETstart
参数 count
指定要返回的最大行数,而 start
指定在开始返回行之前要跳过的行数。当两个参数都指定时,在开始计算要返回的 count
行之前跳过了 start
行。
如果 count
表达式求值为 NULL,则其被视为 LIMIT ALL
,即没有限制。如果 start
求值为 NULL,则其被视为与 OFFSET 0
相同。
SQL:2008 引入了不同的语法来获得相同的结果,PostgreSQL 也支持该语法。它为
OFFSETstart
{ ROW | ROWS } FETCH { FIRST | NEXT } [count
] { ROW | ROWS } { ONLY | WITH TIES }
在此语法中,start
或 count
值在标准中要求是常量、参数或变量名称;作为 PostgreSQL 扩展,允许其他表达式,但通常需要将其括在括号中以避免歧义。如果在 FETCH
子句中省略 count
,则其默认值为 1。 WITH TIES
选项用于返回根据 ORDER BY
子句与结果集中最后一行持平的任何其他行;在此情况下,ORDER BY
为强制性的,且不允许 SKIP LOCKED
。 ROW
和 ROWS
以及 FIRST
和 NEXT
是不会影响这些子句效果的噪声词。根据标准,如果 OFFSET
子句和 FETCH
子句同时出现,则 OFFSET
子句必须出现在 FETCH
子句之前;但 PostgreSQL 较宽松,允许任何顺序。
使用 LIMIT
时,建议使用 ORDER BY
子句,对结果行按唯一顺序进行约束。否则,您将获得查询行的一个不可预测的子集——您可能请求查询第 10 至第 20 行,但按什么顺序排列的第 10 至第 20 行?除非您指定 ORDER BY
,否则您不知道采用什么顺序。
查询计划器在生成查询计划时会将 LIMIT
考虑在内,因此,您很有可能根据用于 LIMIT
和 OFFSET
的内容得到不同的计划(产生不同的行顺序)。因此,如果不用 ORDER BY
强制执行可预测的结果排序,则使用不同的 LIMIT
/OFFSET
值来选择查询结果的不同子集将产生不一致的结果。这不是缺陷,这是 SQL 不会承诺按任何特定顺序交付查询结果的事实所导致的固有结果,除非使用 ORDER BY
来约束顺序。
如果没有 ORDER BY
来强制选择确定性子集,甚至有可能重复执行同一 LIMIT
查询会返回表中行的一组不同子集。同样,这也不是缺陷,在这种情况中,结果的确定性只是没有得到保证。
FOR UPDATE
、FOR NO KEY UPDATE
、FOR SHARE
和 FOR KEY SHARE
是锁定子句;它们影响 SELECT
锁定从表中获取的行的方式。
锁定子句具有以下常规形式:
FORlock_strength
[ OFfrom_reference
[, ...] ] [ NOWAIT | SKIP LOCKED ]
其中 lock_strength
可以为以下一项:
UPDATE NO KEY UPDATE SHARE KEY SHARE
from_reference
必须是 FROM
子句中引用的表别名
或非隐藏的表_名称
。若要了解更多有关每个行级锁定模式的信息,请参阅第 13.3.2 节。
若要防止操作等待其他事务提交,请使用 NOWAIT
或 SKIP LOCKED
选项。对于 NOWAIT
,如果所选行无法立即锁定,则语句会报告错误,而不是等待。对于 SKIP LOCKED
,将跳过任何无法立即锁定的所选行。跳过锁定的行会提供数据的不一致视图,因此不适合进行一般用途的工作,但可以用来避免多个使用者访问类似队列的表时的锁竞争。请注意,NOWAIT
和 SKIP LOCKED
仅适用于行级锁,仍按照普通方式获取必需的 ROW SHARE
表级锁(请参阅 章节 13)。如果您需要获取表级锁而不等待,可以先将 LOCK
与 NOWAIT
选项结合使用。
如果在锁定子句中指定了特定表,那么只锁定来自这些表的行;在 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;
将无法保留 FOR UPDATE
锁,在 ROLLBACK TO
之后。此问题在第 9.3 版中已得到修复。
在 READ COMMITTED
事务隔离级别运行的 SELECT
命令,且使用 ORDER BY
和锁定从句,可能会导致返回行的顺序不一致。这是因为 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
可将它用作顶级命令,也可将其用作复杂查询部分中的空间节省语法变体。通过 TABLE
只能使用 WITH
、UNION
、INTERSECT
、EXCEPT
、ORDER BY
、LIMIT
、OFFSET
、FETCH
和 FOR
锁定子句;不能使用 WHERE
子句和任何聚合形式。
将表 films
与表 distributors
联接
SELECT f.title, f.did, d.name, f.date_prod, f.kind FROM distributors d JOIN films f USING (did); title | did | name | date_prod | kind -------------------+-----+--------------+------------+---------- The Third Man | 101 | British Lion | 1949-12-23 | Drama The African Queen | 101 | British Lion | 1951-08-11 | Romantic ...
对所有影片的列 len
求和,按 kind
对结果进行分组
SELECT kind, sum(len) AS total FROM films GROUP BY kind; kind | total ----------+------- Action | 07:34 Comedy | 02:58 Drama | 14:28 Musical | 06:42 Romantic | 04:38
对所有影片的列 len
求和,按 kind
对结果进行分组,并显示短于 5 小时的那些组的总计
SELECT kind, sum(len) AS total FROM films GROUP BY kind HAVING sum(len) < interval '5 hours'; kind | total ----------+------- Comedy | 02:58 Romantic | 04:38
以下两个示例是按第二列(name
)的内容对各个结果进行排序的相同方式
SELECT * FROM distributors ORDER BY name; SELECT * FROM distributors ORDER BY 2; did | name -----+------------------ 109 | 20th Century Fox 110 | Bavaria Atelier 101 | British Lion 107 | Columbia 102 | Jean Luc Godard 113 | Luso films 104 | Mosfilm 103 | Paramount 106 | Toho 105 | United Artists 111 | Walt Disney 112 | Warner Bros. 108 | Westward
在下一个示例中,展示如何使用 distributors
和 actors
表的并集,将结果限制在每一张表中以字母 W 开头的结果。只希望得到不重复的行,因此省略了关键字 ALL
。
distributors: actors: did | name id | name -----+-------------- ----+---------------- 108 | Westward 1 | Woody Allen 111 | Walt Disney 2 | Warren Beatty 112 | Warner Bros. 3 | Walter Matthau ... ... SELECT distributors.name FROM distributors WHERE distributors.name LIKE 'W%' UNION SELECT actors.name FROM actors WHERE actors.name LIKE 'W%'; name ---------------- Walt Disney Walter Matthau Warner Bros. Warren Beatty Westward Woody Allen
在本示例中展示了如何在 FROM
子句中使用函数,既可以有也可以没有列定义列表
CREATE FUNCTION distributors(int) RETURNS SETOF distributors AS $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE SQL; SELECT * FROM distributors(111); did | name -----+------------- 111 | Walt Disney CREATE FUNCTION distributors_2(int) RETURNS SETOF record AS $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE SQL; SELECT * FROM distributors_2(111) AS (f1 int, f2 text); f1 | f2 -----+------------- 111 | Walt Disney
以下是一个添加了序号列的函数示例
SELECT * FROM unnest(ARRAY['a','b','c','d','e','f']) WITH ORDINALITY; unnest | ordinality --------+---------- a | 1 b | 2 c | 3 d | 4 e | 5 f | 6 (6 rows)
本示例展示了如何使用简单的 WITH
子句
WITH t AS ( SELECT random() as x FROM generate_series(1, 3) ) SELECT * FROM t UNION ALL SELECT * FROM t; x -------------------- 0.534150459803641 0.520092216785997 0.0735620250925422 0.534150459803641 0.520092216785997 0.0735620250925422
请注意,WITH
查询仅评估一次,因此我们会得到两组相同的三组随机值。
本示例使用 WITH RECURSIVE
来查找员工 Mary 的所有下属(直属或间接下属)及其间接层级,方法是从仅显示直接下属的表中查找
WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS ( SELECT 1, employee_name, manager_name FROM employee WHERE manager_name = 'Mary' UNION ALL SELECT er.distance + 1, e.employee_name, e.manager_name FROM employee_recursive er, employee e WHERE er.employee_name = e.manager_name ) SELECT distance, employee_name FROM employee_recursive;
请注意递归查询的典型形式:初始化条件,后跟 UNION
,再后跟查询的递归部分。确保查询的递归部分最终不会返回任何元组,否则查询会无限循环。(请参阅 7.8 节 了解更多示例。)
在本示例中使用 LATERAL
来应用适用于 manufacturers
表的每一行的集合返回函数 get_product_names()
SELECT m.name AS mname, pname FROM manufacturers m, LATERAL get_product_names(m.id) pname;
由于这是内部联接,因此目前没有任何产品的制造商不会出现在结果中。如果希望在结果中包含此类制造商的名称,我们可以执行
SELECT m.name AS mname, pname FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true;
当然,SELECT
语句与 SQL 标准兼容。但是有一些扩展和一些缺失功能。
FROM
子句PostgreSQL 允许省略 FROM
子句。它可以用直接的方式计算简单表达式的结果
SELECT 2+2; ?column? ---------- 4
其他一些SQL数据库无法做到这一点,除非引入伪单行表,再从中执行 SELECT
。
SELECT
列表SELECT
之后的输出表达式列表可以为空,产生零列结果表。根据 SQL 标准,这不是有效的语法。 PostgreSQL 允许该语法,以保持与允许零列表的兼容性。但是,当使用 DISTINCT
时,不允许空列表。
AS
关键字在 SQL 标准中,当新列名称是有效列名称(即,与任何保留关键字不同)时,可以在输出列名称之前省略可选关键字 AS
。 PostgreSQL 略微严格一些:如果新列名称与任何关键字(保留关键字或非保留关键字)匹配,则需要 AS
。建议使用 AS
或双引号输出列名称,以避免与未来添加的关键字发生任何可能的冲突。
在 FROM
项中,标准和 PostgreSQL 都允许在别名(非保留关键字)之前省略 AS
。但是,由于语法歧义,对于输出列名称来说,这是不切实际的。
FROM
中省略子-SELECT
别名根据 SQL 标准,FROM
列表中的子-SELECT
必须具有别名。在 PostgreSQL 中,可以省略此别名。
ONLY
和继承编写 ONLY
时,SQL 标准要求用括号括起表名称,例如 SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...
。 PostgreSQL 认为这些括号是可选的。
PostgreSQL 允许编写尾随 *
来明确指定非-ONLY
行为(包括子表)。标准不允许这样做。
(这些要点同样适用于支持 ONLY
选项的所有 SQL 命令。)
TABLESAMPLE
子句限制目前 TABLESAMPLE
子句仅适用于常规表和物化视图。根据 SQL standard,它应该能够应用于任何 FROM
项。
FROM
中调用函数PostgreSQL 允许直接在 FROM
列表中将函数调用写做成员。在 SQL standard 中需要将这样的函数调用包装在一个子 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
子句只能使用基于输入列名的表达式。PostgreSQL 对这两个子句进行了扩展,也允许以另一种选择作为选取标准(但是如果出现歧义,PostgreSQL 会使用标准的诠释)。PostgreSQL 还允许这两个子句指定任意的表达式。注意出现在表达式中的名称始终作为输入列名处理,而不是作为输出列名处理。
SQL:1999 及更高版本使用略有不同的定义,与 SQL-92 并非完全向后兼容。但在大多数情况下,PostgreSQL 对 ORDER BY
或 GROUP BY
表达式的诠释与 SQL:1999 相同。
PostgreSQL 仅在表的主键包含在 GROUP BY
列表中时才识别出函数相关性(允许从 GROUP BY
中省略列)。SQL standard 规定了应当识别出的其他条件。
LIMIT
和 OFFSET
子句 LIMIT
和 OFFSET
是 PostgreSQL 的特定语法,MySQL 也使用。SQL:2008 标准引入了子句 OFFSET ... FETCH {FIRST|NEXT} ...
用于与上述 LIMIT 子句 相同的功能。该语法也由 IBM DB2 使用。(针对 Oracle 编写的应用程序经常使用涉及自动生成的 rownum
列的解决方法,PostgreSQL 中没有该列,以实现这些子句的效果。)
FOR NO KEY UPDATE
、FOR UPDATE
、FOR SHARE
、FOR KEY SHARE
虽然 FOR UPDATE
在 SQL 标准中出现,但该标准仅将其允许为 DECLARE CURSOR
的一个选项。PostgreSQL 在任何 SELECT
查询以及子 SELECT
中也允许使用,但这是个扩展。该 FOR NO KEY UPDATE
、FOR SHARE
和 FOR KEY SHARE
变体以及 NOWAIT
和 SKIP LOCKED
选项不会出现在该标准中。
WITH
中的数据修改语句PostgreSQL 允许 INSERT
、UPDATE
、DELETE
和 MERGE
被用作 WITH
查询。这在 SQL 标准中找不到。
DISTINCT ON ( ... )
是 SQL 标准的一个扩展。
ROWS FROM( ... )
是 SQL 标准的一个扩展。
该 MATERIALIZED
和 NOT MATERIALIZED
选项的 WITH
是 SQL 标准的一个扩展。