SELECT
SELECT — 从表或视图中检索行
大纲
SELECT [ ALL | DISTINCT [ ON (expression[, ...] ) ] ] * |expression[ ASoutput_name] [, ...] [ FROMfrom_item[, ...] ] [ WHEREcondition] [ GROUP BYexpression[, ...] ] [ HAVINGcondition[, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL ]select] [ ORDER BYexpression[ ASC | DESC | USINGoperator] [, ...] ] [ LIMIT {count| ALL } ] [ OFFSETstart] [ FOR UPDATE [ OFtable_name[, ...] ] ] wherefrom_itemcan be one of: [ ONLY ]table_name[ * ] [ [ AS ]alias[ (column_alias[, ...] ) ] ] (select) [ AS ]alias[ (column_alias[, ...] ) ]function_name( [argument[, ...] ] ) [ AS ]alias[ (column_alias[, ...] |column_definition[, ...] ) ]function_name( [argument[, ...] ] ) AS (column_definition[, ...] )from_item[ NATURAL ]join_typefrom_item[ ONjoin_condition| USING (join_column[, ...] ) ]
描述
SELECT 从一个或多个表中检索行。SELECT 的一般处理过程如下:
所有
FROM列表中的元素都会被计算。(FROM列表中的每个元素都是一个真实或虚拟表。)如果在FROM列表中指定了多个元素,则它们会被交叉连接在一起。(参见下面的FROM子句。)如果指定了
WHERE子句,则不满足条件的所有行将从输出中删除。(请参见下面的WHEREClause。)如果指定了
GROUP BY子句,或者存在聚合函数调用,输出将被组合成在一个或多个值上匹配的行组,并计算聚合函数的结果。如果存在HAVING子句,它将消除不满足给定条件的组。(参见GROUP BYClause和HAVINGClause。)使用操作符
UNION、INTERSECT和EXCEPT,可以把多条SELECT语句的输出合并成一个结果集。UNION操作符返回在一个或两个结果集中的所有行。INTERSECT操作符返回严格同时在两个结果集中的所有行。EXCEPT操作符返回在第一个结果集中但不在第二个结果集中的行。在这三种情况下,除非指定了ALL,否则重复行都会被消除。(见下面的UNIONClause、INTERSECTClause和EXCEPTClause。)实际输出行是使用每个选定行或行组的
SELECT输出表达式计算的。(参见下面的SELECT列表。)如果指定了
ORDER BY子句,则返回的行按指定顺序排序。如果没有给出ORDER BY,则按系统认为最快的顺序返回行。(参见下面的ORDER BY子句。)SELECT DISTINCT消除结果中的重复行。SELECT DISTINCT ON会消除在所有指定表达式上匹配的行,只保留每组中的第一行。SELECT ALL(默认)将返回所有候选行,包括重复行。(参见下面的DISTINCT子句。)如果指定了
LIMIT或OFFSET子句,SELECT语句只返回结果行的子集。(参见下面的LIMIT子句。)FOR UPDATE子句使SELECT语句把选定的行锁定,防止并发更新。(见下面的FOR UPDATE子句。)
你必须在一个表上拥有SELECT权限才能读取它的值。使用FOR UPDATE还要求UPDATE权限。
参数
FROM 子句
FROM 子句为 SELECT 指定一个或更多源表。如果指定了多个源表,结果将是所有源表的笛卡尔积(交叉连接)。但通常会增加限定条件,把返回的行限制为该笛卡尔积的一个小子集。
FROM 子句的元素可以是:
table_name一个现有表或视图的名称(可以选择带模式限定)。如果指定了 ONLY,则只扫描该表。如果未指定 ONLY,则扫描该表及其所有后代表(如果有)。
*可以附加到表名后面以指示要扫描后代表,但在当前版本中这是默认行为。(在 7.1 之前的版本中,ONLY 是默认行为。)默认行为可以通过更改 sql_inheritance 配置选项来修改。alias包含该别名的
FROM项的替代名称。别名可用于简写,或者消除自连接(同一张表被扫描多次)中的歧义。提供别名后,它会完全隐藏表或函数的实际名称;例如给定FROM foo AS f,SELECT的其余部分必须把这个FROM项写成f而不是foo。如果写了别名,还可以写列别名列表,为该表的一个或多个列提供替代名称。select子
SELECT可以出现在FROM子句中,它的作用就像在这个SELECT命令的执行期间创建了一个临时表。注意,子SELECT必须用圆括号括起来,并且必须为其提供别名。function_name函数调用可以出现在
FROM子句中。(这对于返回结果集的函数尤其有用,但任何函数都可以使用。)其效果就像在这条SELECT命令执行期间,将函数的输出创建成了一张临时表。也可以使用别名。如果写了别名,还可以写一个列别名列表,为函数复合返回类型中的一个或多个属性提供替代名称。如果函数被定义为返回record数据类型,则必须给出别名或关键字AS,后面跟一个如下形式的列定义列表:(。列定义列表必须与函数实际返回的列数和类型相匹配。column_namedata_type[, ... ] )join_type以下之一:
[ INNER ] JOINLEFT [ OUTER ] JOINRIGHT [ OUTER ] JOINFULL [ OUTER ] JOINCROSS JOIN
对于
INNER和OUTER连接类型,必须指定一个连接条件,即NATURAL、ON或join_conditionUSING (三者中恰好之一。其含义见下文。对于join_column[, ...])CROSS JOIN,这些子句都不能出现。JOIN子句组合两个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返回所有连接后的行,再加上每个未匹配的左侧行(右侧用空值扩展),以及每个未匹配的右侧行(左侧用空值扩展)。ONjoin_conditionjoin_condition是一个表达式,其结果类型为boolean(类似于WHERE子句),用于指定连接中哪些行被视为匹配。USING (join_column[, ...] )一个形如
USING ( a, b, ... )的子句是ON left_table.a = right_table.a AND left_table.b = right_table.b ...的简写。此外,USING意味着只有每对等价列中的一个会包含在连接输出中,而不是两者都包含。NATURALNATURAL是一个简写,表示一个列出两个表中所有同名列的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
其中condition与
WHERE子句中指定的条件相同。
HAVING消除不满足该条件的分组行。HAVING与WHERE不同:WHERE会在应用GROUP
BY之前过滤个体行,而HAVING过滤由
GROUP BY创建的分组行。condition中引用的每一列都必须无歧义地引用某个分组列,除非该引用出现在聚合函数中,或者该非分组列函数依赖于分组列。
UNION Clause
UNION 子句的一般形式是:
select_statementUNION [ ALL ]select_statement
select_statement 是不带 ORDER BY、LIMIT 或 FOR UPDATE 子句的任何 SELECT 语句。(如果用圆括号括起,ORDER BY 和 LIMIT 可以附加到子表达式上。不带圆括号时,这些子句将被认为应用于 UNION 的结果,而不是它的右侧输入表达式。)
UNION 操作符计算所涉及的 SELECT 语句返回的行的集合并集。如果一行出现在至少一个结果集中,它就在两个结果集的集合并集中。表示 UNION 的直接操作数的两个 SELECT 语句必须产生相同数量的列,并且对应的列必须是兼容的数据类型。
UNION 的结果不包含任何重复行,除非指定了 ALL 选项。ALL 阻止消除重复行。
同一 SELECT 语句中的多个 UNION 操作符从左到右求值,除非圆括号另有指示。
当前,FOR UPDATE不能为UNION的结果或UNION的任何输入指定。
INTERSECT Clause
INTERSECT 子句的一般形式是:
select_statementINTERSECT [ ALL ]select_statement
select_statement 是不带 ORDER BY、LIMIT 或 FOR UPDATE 子句的任何 SELECT 语句。
INTERSECT操作符计算相关
SELECT语句返回的行的交集。如果一行同时出现在两个结果集中,它就在交集中。
INTERSECT 的结果不包含任何重复行,除非指定了 ALL 选项。带 ALL 时,在左表中有 m 个重复且在右表中有 n 个重复的行将在结果集中出现 min(m,n) 次。
同一 SELECT 语句中的多个 INTERSECT 操作符从左到右求值,除非圆括号另有指示。INTERSECT 比 UNION 绑定得更紧。也就是说,A UNION B INTERSECT C 将被读作 A UNION (B INTERSECT C)。
EXCEPT Clause
EXCEPT 子句的一般形式是:
select_statementEXCEPT [ ALL ]select_statement
select_statement 是不带 ORDER BY、LIMIT 或 FOR UPDATE 子句的任何 SELECT 语句。
EXCEPT操作符计算位于左侧
SELECT语句的结果中但不在右侧语句结果中的行集合。
EXCEPT 的结果不包含任何重复行,除非指定了 ALL 选项。带 ALL 时,在左表中有 m 个重复且在右表中有 n 个重复的行将在结果集中出现 max(m-n,0) 次。
同一 SELECT 语句中的多个 EXCEPT 操作符从左到右求值,除非圆括号另有指示。EXCEPT 与 UNION 绑定在同一级别。
SELECT 列表
SELECT列表(位于关键词
SELECT和FROM之间)指定构成
SELECT语句输出行的表达式。这些表达式可以(并且通常确实会)引用FROM子句中计算得到的列。使用AS 子句可以为输出列指定另一个名称。这个名称主要用于给要显示的列做标记。它也可以用来在output_nameORDER BY和GROUP BY子句中引用该列的值,但不能用在WHERE或HAVING子句中;在那里必须写出表达式。
可以在输出列表中写*来取代表达式,它是被选中行的所有列的一种简写方式。还可以写
,它是只来自那个表的所有列的简写形式。
table_name.*
ORDER BY 子句
可选的 ORDER BY 子句的一般形式为:
ORDER BYexpression[ ASC | DESC | USINGoperator] [, ...]
expression 可以是输出列(SELECT 列表项)的名称或序号,也可以是由输入列值构成的任意表达式。
ORDER BY 子句使结果行按指定的表达式排序。如果两行按最左边的表达式相等,则按下一个表达式比较,依此类推。如果它们按所有指定的表达式都相等,则以依赖于实现顺序的顺序返回。
序号指的是输出列的顺序(从左至右)位置。这种特性可以为不具有唯一名称的列定义一个顺序。这不是绝对必要的,因为总是可以使用
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 >(但是一种用户定义数据类型的创建者可以准确地定义默认排序顺序是什么,并且它可能会对应于其他名称的操作符)。
空值的排序高于任何其他值。换句话说,在升序排序时,空值排在最后;在降序排序时,空值排在最前。
字符串数据按照数据库集簇初始化时建立的区域相关排序顺序来排序。
LIMIT 子句
该 LIMIT 子句由两个独立的子句组成:
LIMIT { count | ALL }
OFFSET start
count 指定最多返回多少行,而 start 指定开始返回行之前要跳过的行数。如果两者都指定,则先跳过 start 行,然后开始计数并返回 count 行。
使用 LIMIT 时,最好使用把结果行约束为唯一顺序的 ORDER BY 子句。否则你会得到查询行的一个不可预测的子集——你可能要的是第十到第二十行,但是按什么顺序的第十到第二十行?除非指定 ORDER BY,否则你不知道顺序。
查询规划器在生成一个查询计划时会考虑LIMIT,因此根据你使用的LIMIT和OFFSET,你很可能得到不同的计划(得到不同的行序)。所以,使用不同的
LIMIT/OFFSET值来选择一个查询结果的不同子集将会给出不一致的结果,除非你用ORDER BY强制一种可预测的结果顺序。这不是一个缺陷,它是 SQL 不承诺以任何特定顺序(除非使用
ORDER BY来约束顺序)给出一个查询结果这一事实造成的必然后果。
DISTINCT 子句
如果指定了SELECT DISTINCT,所有重复的行会被从结果集中移除(为每一组重复的行保留一行)。SELECT ALL则指定相反的行为:所有行都会被保留,这也是默认情况。
DISTINCT ON (
只保留给定表达式求值相等的每组行中的第一行。DISTINCT ON 表达式使用与 ORDER BY 相同的规则解释(见上文)。注意,除非用 expression [, ...] )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 UPDATE 子句
FOR UPDATE 子句的形式如下:
FOR UPDATE [ OF table_name [, ...] ]
FOR UPDATE使SELECT语句检索到的行像被更新一样被锁定。这防止其他事务在当前事务结束之前修改或删除它们。也就是说,其他事务对这些行尝试UPDATE、DELETE或SELECT FOR UPDATE时将被阻塞,直到当前事务结束。此外,如果来自另一个事务的UPDATE、DELETE或SELECT FOR UPDATE已经锁定了被选中的一行或多行,SELECT FOR UPDATE将等待那个事务完成,然后锁定并返回更新后的行(如果该行已被删除,则不返回行)。进一步的讨论见第 12 章。
如果在FOR UPDATE中命名了特定的表,那么只有来自那些表的行会被锁定;SELECT中用到的任何其他表都只是被照常读取。
在返回的行无法清楚地与各个表行对应起来的上下文中,不能使用FOR UPDATE;例如它不能与聚合一起使用。
FOR UPDATE 为了与 7.3 之前的 PostgreSQL 版本兼容,可以出现在 LIMIT 之前。但它实际上在 LIMIT 之后执行,所以推荐把它写在那里。
示例
连接表 films 和表
distributors:
SELECT f.title, f.did, d.name, f.date_prod, f.kind
FROM distributors d, films f
WHERE f.did = d.did
title | did | name | date_prod | kind
-------------------+-----+--------------+------------+----------
The Third Man | 101 | British Lion | 1949-12-23 | Drama
The African Queen | 101 | British Lion | 1951-08-11 | Romantic
...
要对所有电影的len列求和并且用
kind对结果分组:
SELECT kind, sum(len) AS total FROM films GROUP BY kind; kind | total ----------+------- Action | 07:34 Comedy | 02:58 Drama | 14:28 Musical | 06:42 Romantic | 04:38
对所有影片的 len 列求和,按 kind 分组,并显示少于 5 小时的组总计:
SELECT kind, sum(len) AS total
FROM films
GROUP BY kind
HAVING sum(len) < interval '5 hours';
kind | total
----------+-------
Comedy | 02:58
Romantic | 04:38
下面两个示例都是根据第二列(name)的内容来排序结果:
SELECT * FROM distributors ORDER BY name; SELECT * FROM distributors ORDER BY 2; did | name -----+------------------ 109 | 20th Century Fox 110 | Bavaria Atelier 101 | British Lion 107 | Columbia 102 | Jean Luc Godard 113 | Luso films 104 | Mosfilm 103 | Paramount 106 | Toho 105 | United Artists 111 | Walt Disney 112 | Warner Bros. 108 | Westward
接下来的示例展示了如何得到表distributors和
actors的并集,把结果限制为那些在每个表中以字母 W 开始的行。这里只需要不重复的行,因此省略了关键词
ALL。
distributors: actors:
did | name id | name
-----+-------------- ----+----------------
108 | Westward 1 | Woody Allen
111 | Walt Disney 2 | Warren Beatty
112 | Warner Bros. 3 | Walter Matthau
... ...
SELECT distributors.name
FROM distributors
WHERE distributors.name LIKE 'W%'
UNION
SELECT actors.name
FROM actors
WHERE actors.name LIKE 'W%';
name
----------------
Walt Disney
Walter Matthau
Warner Bros.
Warren Beatty
Westward
Woody Allen
这个例子展示如何在 FROM 子句中使用函数,包括带和不带列定义列表两种情况:
CREATE FUNCTION distributors(int) RETURNS SETOF distributors AS '
SELECT * FROM distributors WHERE did = $1;
' LANGUAGE SQL;
SELECT * FROM distributors(111);
did | name
-----+-------------
111 | Walt Disney
CREATE FUNCTION distributors_2(int) RETURNS SETOF record AS '
SELECT * FROM distributors WHERE did = $1;
' LANGUAGE SQL;
SELECT * FROM distributors_2(111) AS (f1 int, f2 text);
f1 | f2
-----+-------------
111 | Walt Disney
兼容性
当然,SELECT语句与 SQL 标准兼容。但它也有一些扩展和缺失的特性。
省略的 FROM 子句
PostgreSQL 允许省略 FROM 子句。它可以直接用于计算简单表达式的结果:
SELECT 2+2;
?column?
----------
4
其他一些 SQL 数据库必须引入一个只有一行的虚拟表,才能从该表执行 SELECT。
一个不太明显的用法是缩写对表的普通 SELECT:
SELECT distributors.* WHERE distributors.name = 'Westward'; did | name -----+---------- 108 | Westward
这之所以可行,是因为对在 SELECT 语句的其他部分中被引用但在 FROM 中未提及的每个表,都会添加一个隐式的 FROM 项。
虽然这是一个方便的缩写,但很容易误用。例如,命令
SELECT distributors.* FROM distributors d;
很可能是一个错误;用户很可能想要的是
SELECT d.* FROM distributors d;
而不是他将实际得到的无约束连接
SELECT distributors.* FROM distributors d, distributors distributors;
。为了帮助检测这类错误,如果在也包含显式 FROM 子句的 SELECT 语句中使用了隐式 FROM 特性,PostgreSQL 会发出警告。此外,可以通过把 ADD_MISSING_FROM 参数设置为 false 来禁用隐式 FROM 特性。
AS 关键字
在 SQL 标准中,可选关键词AS只是一个噪音词,可以省略它而不影响含义。PostgreSQL解析器在重命名输出列时要求这个关键词,因为类型可扩展性特性使得没有它就会出现解析歧义。不过,AS在FROM项中是可选的。
GROUP BY 和 ORDER BY 可用的命名空间
在 SQL92 标准中,ORDER BY 子句只能使用结果列名或编号,而 GROUP BY 子句只能使用基于输入列名的表达式。PostgreSQL 扩展了这两个子句,允许另一种选择(但在有歧义时使用标准的解释)。PostgreSQL 还允许两个子句指定任意表达式。注意,表达式中出现的名称总是被当作输入列名,而不是结果列名。
SQL99 使用一个略有不同的定义,它与 SQL92 不完全向上兼容。但在大多数情况下,PostgreSQL 对 ORDER BY 或 GROUP BY 表达式的解释与 SQL99 相同。
非标准子句
DISTINCT ON、LIMIT和OFFSET子句未在 SQL 标准中定义。