本文介绍SELECT相关的查询语句。

语法

[ WITH with_query [, ...] ]
SELECT [ ALL | DISTINCT ] select_expr [, ...]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY [ ALL | DISTINCT ] grouping_element [, ...] ]
[ HAVING condition]
[ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
[ ORDER BY expression [ ASC | DESC ] [, ...] ]
[ LIMIT [ count | ALL ] ]

参数

  • from_item:有以下两种形式。
      table_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
      from_item join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]
  • join_type:表的连接类型。
      [ INNER ] JOIN
      LEFT [ OUTER ] JOIN
      RIGHT [ OUTER ] JOIN
      FULL [ OUTER ] JOIN
  • grouping_element
      ()
      expression

WITH从句

WITH从句定义了一个命名好的关系以供在一个查询里面使用。 它可以扁平化嵌套查询或者简化子查询。 例如,下面的查询是等价的。

SELECT a, b
FROM (
  SELECT a, MAX(b) AS b FROM t GROUP BY a
) AS x;

WITH x AS (SELECT a, MAX(b) AS b FROM t GROUP BY a)
SELECT a, b FROM x;

也同样适用于多子查询的情况。

WITH
  t1 AS (SELECT a, MAX(b) AS b FROM x GROUP BY a),
  t2 AS (SELECT a, AVG(d) AS d FROM y GROUP BY a)
SELECT t1.*, t2.*
FROM t1
JOIN t2 ON t1.a = t2.a;

另外,在WITH分句中定义的关系可以互相连接。

WITH
  x AS (SELECT a FROM t),
  y AS (SELECT a AS b FROM x),
  z AS (SELECT b AS c FROM y)
SELECT c FROM z;

GROUP BY从句

GROUP BY分句对SELECT语句的输出进行分组,分组是匹配值的数据行。一个简单的GROUP BY分句可以包含由输入列组成的任何表达式或者或列序号(从1开始)。

以下查询是等价的。 他们都对nationkey列进行分组, 第一个查询使用列序号, 第二个查询使用列名。

SELECT count(*), nationkey FROM customer GROUP BY 2;

SELECT count(*), nationkey FROM customer GROUP BY nationkey;

在查询语句中没有指定列名的情况下,GROUP BY子句也可以将输出进行分组。 例如,以下查询使用列mktsegment进行分组,统计出customer表的行数。

SELECT count(*) FROM customer GROUP BY mktsegment;
_col0
-------
 29968
 30142
 30189
 29949
 29752
(5 rows)

SELECT语句中使用GROUP BY子句时,所有输出的列要么是聚合函数,要么是GROUP BY子句中的列。

HAVING从句

HAVING子句与聚合函数以及GROUP BY子句共同使用,用来控制选择分组。HAVING子句去掉不满足条件的分组。在分组和聚合计算完成后,HAVING对分组进行过滤。以下示例查询customer表,并进行分组,查出账户余额大于指定值的记录。

SELECT count(*), mktsegment, nationkey,
       CAST(sum(acctbal) AS bigint) AS totalbal
FROM customer
GROUP BY mktsegment, nationkey
HAVING sum(acctbal) > 5700000
ORDER BY totalbal DESC;
_col0 | mktsegment | nationkey | totalbal
-------+------------+-----------+----------
  1272 | AUTOMOBILE |        19 |  5856939
  1253 | FURNITURE  |        14 |  5794887
  1248 | FURNITURE  |         9 |  5784628
  1243 | FURNITURE  |        12 |  5757371
  1231 | HOUSEHOLD  |         3 |  5753216
  1251 | MACHINERY  |         2 |  5719140
  1247 | FURNITURE  |         8 |  5701952
(7 rows)

UNION|INTERSECT|EXCEPT从句

UNION、INTERSECT和EXCEPT都是全集合操作符。这些分句被用来组合多于一个查询语句的结果,最终形成一个结果。

query UNION [ALL | DISTINCT] query

query INTERSECT query

query EXCEPT query

参数ALL或DISTINCT控制最终结果集包含哪些行。如果指定参数ALL,则包含全部行,即使行完全相同。如果指定参数DISTINCT,则合并结果集,结果集只有唯一不重复的行。如果不指定参数,执行时默认使用DISTINCT。

多个集合操作符会从做到有的被处理,除非顺序通过括弧被显示指定。另外,INTERSECT比EXCEPT and UNION有更高的优先级,意味着A UNION B INTERSECT C EXCEPT D和这个表达式是相同的A UNION (B INTERSECT C) EXCEPT D

UNION

UNION把所有结果集两个结果集合并起来。下面是一个最简单的可能使用UNION分句的例子。它选择了值13并且合并了第二个选择的值42,把他们结合起来。

SELECT 13
UNION
SELECT 42;
 _col0
-------
    13
    42
(2 rows)

INTERSECT

INTERSECT只返回那些同时在第一个和第二个查询里面都出现的行结合。下面的例子是一个最简单的可能使用INTERSECT分句的例子。它选择了值13和42并把他们和第二个查询选择的值13做合并。既然42值在第一个查询的结果集中,它并不会被包含在最终的结果集里面。

SELECT 13
INTERSECT
SELECT 13;
 _col0
-------
    13
(2 rows)

EXCEPT

EXCEPT返回那些行仅存在于第一个查询结果集不在第二个查询结果集中。下面是最简单的使用EXCEPT分句的例子。它选择了值42并把他们和第二个查询选择的值13做合并。既然13也同时存在在第二个查询结果集中,它不会被包含在最终的结果集中。

SELECT 42
EXCEPT
SELECT 13;
 _col0
-------
   42
(2 rows)

ORDER BY Clause

ORDER BY分句被用来排序一个结果集通过一个或者多个输出表达式。

ORDER BY expression [ ASC | DESC ] [, ...]

每个表达式由列名或列序号(从1开始)组成。ORDER BY子句作为查询的最后一步,在GROUP BYHAVING子句之后。

LIMIT Clause

LIMIT分句限制了最终结果集的行数。LIMIT ALL和略去LIMIT分句的结果一样。以下示例为查询一个大表,LIMIT子句限制它只输出5行(因为查询没有ORDER BY,所以随意返回几行)。

SELECT orderdate FROM orders LIMIT 5;

 o_orderdate
-------------
 1996-04-14
 1992-01-15
 1995-02-01
 1995-11-12
 1992-04-26
(5 rows)

Joins

它允许合并来自多个关联的数据。

交叉连接

SELECT *
FROM nation, region;

nation表包含了25行,region表包含了5行,所以结果两个表最终产生了125行。

子查询

一个子查询是一个包含了查询的表达式。子查询当它引用子查询之外的列时是相关的。逻辑上来说,子查询会被它的外围查询逐行评估。被引用的列将因此是固定的在子查询的评估过程中。

说明 对于向关联的子查询是受限的,并不是每一个形式都是支持的。

EXISTS

EXISTS断言决定是否一个子查询可以返回任何行。

SELECT name
FROM nation
WHERE EXISTS (SELECT * FROM region WHERE region.regionkey = nation.regionkey)

IN

IN断言决定一个子查询返回的值是否在一个被给定的结果集中。IN的结果依照对nulls的标准结果。子查询必须产生仅仅一列。

SELECT name
FROM nation
WHERE regionkey IN (SELECT regionkey FROM region)

标量子查询

标量子查询是一个非关联的子查询,返回零或者1行数据。如果这个子查询返回了多于一行的数据,那将是个错误。如果子查询没有返回任何行,则返回的结果是NULL

SELECT name
FROM nation
WHERE regionkey = (SELECT max(regionkey) FROM region)
说明 当前只支持单列可以用在标量子查询里。