SELECT

名称

SELECT — 从表或视图中取出若干行.

语法

SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
    expression [ AS name ] [, ...]
    [ INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table ]
    [ FROM table [ alias ] [, ...] ]
    [ WHERE condition ]
    [ GROUP BY column [, ...] ]
    [ HAVING condition [, ...] ]
    [ { UNION [ ALL ] | INTERSECT | EXCEPT } select ]
    [ ORDER BY column [ ASC | DESC | USING operator ] [, ...] ]
    [ FOR UPDATE [ OF class_name [, ...] ] ]
    LIMIT { count | ALL } [ { OFFSET | , } start ]

输入

expression
表的列/字段名或一个表达式.
name
使用 AS 子句为一个列/字段或一个表达式声明另一个名称.这个名称主要用于标记输出列用于显示。它可以在 ORDER BY 和 GROUP BY 子句里代表列/字段的值.但是 name 不能用于 WHERE 或 HAVING 子句;用表达式代替.
TEMPORARY, TEMP
如果声明了 TEMPORARY 或 TEMP,该表是在这次会话中唯一的,并且将在会话结束后自动删除。
new_table
如果声明了 INTO TABLE 子句,查询的结果将存储在指出名称的另一个表中.目标表(new_table)将被自动创建并且在此命令执行之前不应该存在。请参考 SELECT INTO 获取更多信息.
注意: CREATE TABLE AS 语句也将从选择查询中创建新表.
table
FORM 子句引用的一个现存的表的名称.
alias
正在处理的表 table 的别名,用于缩写或消除一个表内部联合时的含混.
condition
一个结果为真或假布尔表达式.参阅 WHERE 子句获取更多信息.
column
表的列/字段的名称.
select
除了 ORDER BY 和 LIMIT 子句外的所有特性的选择语句.

输出

Rows
查询返回的所有结果集的行.
count
查询返回的行的记数.


描述SELECT 将从一个或更多表中返回记录行。选择的侯选行是满足 WHERE 条件的所有行。或者如果省略了 WHERE 语句则选择表中的所有行.(参阅WHERE Clause.

DISTINCT 将从选择出来的结果集中删除所有的重复的行。ALL (缺省)将返回所有侯选行,包括重复的行。

DISTINCT ON 删除匹配所有表达式的行,只保留每个重复集的第一行。注意这里每个重复集的"第一行"是不可预料的,除非我们用 ORDER BY 来保证我们希望的行最先出现。例如,

        SELECT DISTINCT ON (location) location, time, report
        FROM weatherReports
        ORDER BY location, time DESC;
检索出每个地区的最近的天气预报。但是如果我们没有使用 ORDER BY 来强制每个地区按时间值降续排列,我们得到的将是每个地区的不可预料的时间的报告。

检索出每个地区的最近的天气预报。但是如果我们没有使用 ORDER BY 来强制每个地区按时间值降续排列,我们得到的将是每个地区的不可预料的时间的报告。( GROUP BY 子句.)

HAVING 允许只选择那些满足声明条件的行组(参阅 HAVING 子句.)

ORDER BY 导致返回的行按照声明的顺序排列.如果没有给出 ORDER BY,输出的行的顺序将以系统认为开销最小的顺序产生.(参阅 ORDER BY 子句.)

UNION 操作符允许结果集是那些涉及到的查询所返回的行的集合。(参阅 UNION 子句。)

INTERSECT 给出两个查询公共的行。(参阅  INTERSECT 子句。)

EXCEPT 给出存在于第一个查询而不存在于第二个查询的行。(参阅 EXCEPT 子句。)

FOR UPDATE 子句允许 SELECT 语句对选出的行执行排他锁。

LIMIT 子句允许给用户返回一个查询生成的结果的子集。(参阅 LIMIT 子句。)
 

你必须有 SELECT 权限用来从表中读取数值 (参阅 GRANT/REVOKE 语句).

WHERE 子句

可选的 WHERE 条件有如下常见的形式:
WHERE boolean_expr
boolean_expr 可以包含任意个得出布尔值的表达式。通常表达式会是
     expr cond_op expr
     log_op expr
这里 cond_op 可以是下面之一:=,<,<=,>,>=,<> 或条件操作符象 ALL,ANY,IN,LIKE等,或者用户定义的操作符,而 log_op 可以为: AND,OR,NOT.SELECT 将忽略所有 WHERE 条件不为 TRUE 的行.

GROUP BY 子句

GROUP BY 声明一个分了组的表,该表源于应用使用下面的子句:
GROUP BY column [, ...]
GROUP BY 将把所有在组合了的列上共享同样的值的行压缩成一行。如果存在聚集函数,这些聚集函数将计算每个组的所有行,并且为每个组计算一个独立的值(如果没有 GROUP BY,聚集函数对选出的所有行计算出一个数值)。存在 GROUP BY 时,除了在聚集函数里面,SELECT 输出表达式对任何非组合列的引用都是非法的,因为对一个非组合列会有多于一个可能的返回值。

一个在 GROUP BY 里面的条目还可以是输出列的名称或者序号(SELECT 表达式),或者是一个从输入列的数值形成的任意表达式.当存在语义模糊时,一个 GROUP BY 名称将被解释成一个输入列/字段名称而不是一个输出列/字段名称.

HAVING 子句

可选的 HAVING 条件有如下形式:
HAVING cond_expr
这里 cond_expr 与为 WHERE 子句里声明的相同.

HAVING 子句声明一个从前面的子句的结果集中去除了一些不符合 cond_expr 组后分组的表.HAVING 与 WHERE 不同:WHERE 在应用 GROUP BY 之前过滤出单独的行,而 HAVING 过滤由 GROUP BY 创建的行.

cond_expr 里引用的每个列/字段应该清晰地指明一个组的列/字段,除非引用在一个聚集函数里。
 

ORDER BY 子句

ORDER BY column [ ASC | DESC ] [, ...]
column 既可以是一个列/字段名也可以是一个序数。

序数指的是列/字段按顺序(从左到右)的位置.这个特性可以使得对没有一个合适名称的列/字段的排序成为可能.这一点可能永远没有用,因为总是可以通过AS 子句给一个要计算的列/字段赋予一个名称,例如:

SELECT title, date_prod + 1 AS newlen FROM films ORDER BY newlen;
还可以 ORDER BY 任意表达式(一个对 SQL92 的扩展),包括那些没有出现在 SELECT 结果列表里面的域。因此下面的语句现在是合法的:
SELECT name FROM distributors ORDER BY code;
请注意如果一个 ORDER BY 条目是一个匹配结果列和输入列的简单名称,ORDER BY 将把它解释成结果列名称.这和 GROUP BY 在同样情况下做的选择正相反.这样的不一致是由 SQL92 标准强制的.

我们可以给ORDER BY 子句里每个列/字段加一个关键字 DESC (降序)或 ASC(升序).如果不声明,ASC 是缺省.我们还可以声明一个排序操作符来实现排序。ASC 等效于使用 '<' 而 DESC 等效于使用 '>'。

UNION 子句

table_query UNION [ ALL ] table_query
    [ ORDER BY column [ ASC | DESC ] [, ...] ]
这里 table_query 表明任何没有 ORDER BY 或者 LIMIT 子句的选择表达式.

UNION 操作符允许结果集是那些涉及到的查询所返回的结果的集合。两个做为 UNION 直接操作数的 SELECT 必须生成相同数目的字段,并且对应的字段必须有兼容的数据类型。

缺省地,UNION 的结果不包含任何重复的行,除非声明了 ALL 子句.

同一 SELECT 语句中的多个 UNION 操作符是从左向右计算的.注意 ALL 关键字不一定是全局的,只是应用在当前一对表的结果上.

INTERSECT 子句

table_query INTERSECT table_query
    [ ORDER BY column [ ASC | DESC ] [, ...] ]
这里 table_query 声明任何没有 ORDER BY 或者 LIMIT 子句的选择表达式。

INTERSECT 给出两个查询公共的行。 两个做为 INTERSECT 直接操作数的 SELECT 的结果必须有相同数目的字段,并且对应的字段必须有兼容的数据类型。

除非用圆括号指明顺序,同一 SELECT 语句中的多个 INTERSECT 操作符是从左向右计算的。

EXCEPT 子句

table_query EXCEPT table_query
     [ ORDER BY column [ ASC | DESC ] [, ...] ]
这里 table_query 声明任何没有 ORDER BY 或者 LIMIT 子句的选择表达式。

EXCEPT 给出存在于第一个查询而不存在于第二个查询的行。(参阅 EXCEPT 子句)。两个做为 EXCEPT 直接操作数的 SELECT 的结果必须有相同数目的字段,并且对应的字段必须有兼容的数据类型。

除非用圆括号指明顺序,同一 SELECT 语句中的多个 EXCEPT 操作符是从左向右计算的。

LIMIT 子句

    LIMIT { count | ALL } [ { OFFSET | , } start ]
    OFFSET start
这里 count 声明返回的最大行数,而 start 声明开始返回行之前忽略的行数。

LIMIT 允许你检索有查询其他部分生成的行的某一部分。如果给出了限制计数,那么返回的行数不会超过哪个限制。如果给出了一个偏移量,那么开始返回行之前会忽略那个数量的行。

在使用 LIMIT 时,一个好习惯是使用一个 ORDER BY 子句把结果行限制成一个唯一的顺序。否则你会得到无法预料的查询返回的子集 --- 你可能想要第十行到第二十行,但以什么顺序?除非你声明 ORDER BY,否则你不知道什么顺序。

在 Postgres 7.0,查询优化器在生成查询规划时把 LIMIT 考虑进去了,所以你很有可能因给出的 LIMIT 和 OFFSET 值不同而得到不同的规划(生成不同的行序)。因此用不同的 LIMIT/OFFSET 值选择不同的查询结果的子集将不会产生一致的结果,除非你用 ORDER BY 强制生成一个可预计的结果顺序。这可不是毛病;这是 SQL 生来的特点,因为除非用了 ORDER BYE 约束顺序,SQL 不保证查询生成的结果有任何特定的顺序。

用法

将表 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
 Une Femme est une Femme   | 102 | Jean Luc Godard  | 1961-03-12 | Romantic
 Vertigo                   | 103 | Paramount        | 1958-11-14 | Action
 Becket                    | 103 | Paramount        | 1964-02-03 | Drama
 48 Hrs                    | 103 | Paramount        | 1982-10-22 | Action
 War and Peace             | 104 | Mosfilm          | 1967-02-12 | Drama
 West Side Story           | 105 | United Artists   | 1961-01-03 | Musical
 Bananas                   | 105 | United Artists   | 1971-07-13 | Comedy
 Yojimbo                   | 106 | Toho             | 1961-06-16 | Drama
 There's a Girl in my Soup | 107 | Columbia         | 1970-06-11 | Comedy
 Taxi Driver               | 107 | Columbia         | 1975-05-15 | Action
 Absence of Malice         | 107 | Columbia         | 1981-11-15 | Action
 Storia di una donna       | 108 | Westward         | 1970-08-15 | Romantic
 The King and I            | 109 | 20th Century Fox | 1956-08-11 | Musical
 Das Boot                  | 110 | Bavaria Atelier  | 1981-11-11 | Drama
 Bed Knobs and Broomsticks | 111 | Walt Disney      |            | Musical
(17 rows)
统计用 kind 分组的所有电影和组的列/字段的 len (长度)的和:
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
(5 rows)
统计所有电影(films),组的列/字段 len (长度)的和,用 kind 分组并且显示小于5小时的组总和:
SELECT kind, SUM(len) AS total
    FROM films
    GROUP BY kind
    HAVING SUM(len) < INTERVAL '5 hour';

 kind     | total
----------+-------
 Comedy   | 02:58
 Romantic | 04:38
(2 rows)
下面两个例子是根据第二列 (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
(13 rows)
这个例子演示如何获得表 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

兼容性

扩展

Postgres 允许我们在一个查询里省略 FROM 子句。这个特性是从最初的 PostQuel 查询语言里保留下来的:
SELECT distributors.* WHERE name = 'Westwood';

 did | name
-----+----------
 108 | Westward

SQL92

SELECT 子句

SQL92 规范里,可选的关键字 "AS" 是多余的,可以忽略掉而不对语句产生任何影响.Postgres 分析器在重命名列/字段时需要这个关键字,因为类型扩展的特性会导致上下文语意不清.

DISTINCT ON 语法不是 SQL92 的标准。LIMIT 和 OFFSET 也不是。

在 SQL92 里,一个 ORDER BY 子句只可以使用在结果列名称或者序号上,而 GROUP BY 子句只能用于输入列/字段上.Postgres 把这两个子句都扩展为允许另一种选择(但是如果出现冲突则使用标准的解释).Postgres 还允许两个子句声明任意的表达式.请注意,在表达式里出现的名称将总是被当做输入列/字段的名称,而不是结果列/字段名称.

UNION 子句

SQL92 的 UNION 语法允许一个附加的 CORRESPONDING BY 子句:
 
table_query UNION [ALL]
    [CORRESPONDING [BY (column [,...])]]
    table_query