SELECT

摘要

  1. [ WITH with_query [, ...] ]
  2. SELECT [ ALL | DISTINCT ] select_expression [, ...]
  3. [ FROM from_item [, ...] ]
  4. [ WHERE condition ]
  5. [ GROUP BY [ ALL | DISTINCT ] grouping_element [, ...] ]
  6. [ HAVING condition]
  7. [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
  8. [ ORDER BY expression [ ASC | DESC ] [, ...] ]
  9. [ OFFSET count [ ROW | ROWS ] ]
  10. [ LIMIT { count | ALL } | FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES } ]

其中,from_item有如下两种形式:

  1. table_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
  1. from_item join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]

join_type是如下之一:

  1. [ INNER ] JOIN
  2. LEFT [ OUTER ] JOIN
  3. RIGHT [ OUTER ] JOIN
  4. FULL [ OUTER ] JOIN
  5. CROSS JOIN

grouping_element是如下之一:

  1. ()
  2. expression
  3. GROUPING SETS ( ( column [, ...] ) [, ...] )
  4. CUBE ( column [, ...] )
  5. ROLLUP ( column [, ...] )

说明

从零个或多个表中检索行。

WITH子句

WITH子句定义在查询中使用的命名关系。该子句可以实现扁平化嵌套查询或简化子查询。例如,以下两个查询是等价的:

  1. SELECT a, b
  2. FROM (
  3. SELECT a, MAX(b) AS b FROM t GROUP BY a
  4. ) AS x;
  5. WITH x AS (SELECT a, MAX(b) AS b FROM t GROUP BY a)
  6. SELECT a, b FROM x;

这也适用于多个子查询:

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

此外,WITH子句内的关系可以组成链式结构:

  1. WITH
  2. x AS (SELECT a FROM t),
  3. y AS (SELECT a AS b FROM x),
  4. z AS (SELECT b AS c FROM y)
  5. SELECT c FROM z;

警告

目前,WITH子句的SQL将在使用命名关系的任何位置内联。这意味着,如果关系被多次使用,并且查询是非确定性的,那么每次的结果都可能不同。

SELECT子句

SELECT子句指定查询的输出。每个select_expression定义结果中要包含的一个或多个列。

  1. SELECT [ ALL | DISTINCT ] select_expression [, ...]

ALLDISTINCT量词确定结果集中是否包含重复行。如果指定了参数ALL,则包含所有行。如果指定了参数DISTINCT,则结果集中只包含唯一的行。在这种情况下,每个输出列必须具有允许比较的类型。如果两个参数都没有指定,则行为默认为ALL

选择表达式

每个select_expression必须采用下列其中一种形式:

  1. expression [ [ AS ] column_alias ]
  1. relation.*
  1. *

对于expression [ [ AS ] column_alias ],定义了单个输出列。

对于relation.*relation的所有列都包含在结果集中。

对于*,由查询定义的关系的所有列都包含在结果集中。

在结果集中,列的顺序与通过选择表达式指定列的顺序相同。如果选择表达式返回多个列,则这些列将按照源关系中的排序方式进行排序。

GROUP BY子句

GROUP BY子句将SELECT语句的输出分组成包含匹配值的行。一个简单的GROUP BY子句可以包含任何由输入列组成的表达式,也可以是按位置选择输出列的序数(从1开始)。

以下查询是等价的。它们都通过nationkey输入列对输出进行分组,第一个查询使用输出列的顺序位置,第二个查询使用输入列名称:

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

GROUP BY子句可以按不在select语句的输出中显示的输入列名对输出进行分组。例如,以下查询使用输入列mktsegment来生成customer表的行数:

  1. SELECT count(*) FROM customer GROUP BY mktsegment;
  1. _col0
  2. -------
  3. 29968
  4. 30142
  5. 30189
  6. 29949
  7. 29752
  8. (5 rows)

SELECT语句中使用GROUP BY子句时,所有输出表达式必须是GROUP BY子句中出现的聚合函数或列。

复杂分组操作

openLooKeng还支持使用GROUPING SETSCUBEROLLUP语法的复杂聚合。此语法允许用户在单个查询中执行需要对多组列进行聚合的分析。复杂分组操作不支持对由输入列组成的表达式进行分组。只支持列名或序号。

复杂分组操作通常与对简单GROUP BY表达式的UNION ALL操作等价,如下面的示例所示。但是,当聚合的数据源是非确定性的时,这种等价性不适用。

GROUPING SETS

GROUPING SETS允许用户指定要进行分组的多个列列表。不属于给定分组列子列表的列设置为NULL。如下所示:

  1. SELECT * FROM shipping;
  1. origin_state | origin_zip | destination_state | destination_zip | package_weight
  2. --------------+------------+-------------------+-----------------+----------------
  3. California | 94131 | New Jersey | 8648 | 13
  4. California | 94131 | New Jersey | 8540 | 42
  5. New Jersey | 7081 | Connecticut | 6708 | 225
  6. California | 90210 | Connecticut | 6927 | 1337
  7. California | 94131 | Colorado | 80302 | 5
  8. New York | 10002 | New Jersey | 8540 | 3
  9. (6 rows)

这个示例查询演示了GROUPING SETS语义:

  1. SELECT origin_state, origin_zip, destination_state, sum(package_weight)
  2. FROM shipping
  3. GROUP BY GROUPING SETS (
  4. (origin_state),
  5. (origin_state, origin_zip),
  6. (destination_state));
  1. origin_state | origin_zip | destination_state | _col0
  2. --------------+------------+-------------------+-------
  3. New Jersey | NULL | NULL | 225
  4. California | NULL | NULL | 1397
  5. New York | NULL | NULL | 3
  6. California | 90210 | NULL | 1337
  7. California | 94131 | NULL | 60
  8. New Jersey | 7081 | NULL | 225
  9. New York | 10002 | NULL | 3
  10. NULL | NULL | Colorado | 5
  11. NULL | NULL | New Jersey | 58
  12. NULL | NULL | Connecticut | 1562
  13. (10 rows)

上述查询在逻辑上可以等价于对多个GROUP BY查询的UNION ALL操作:

  1. SELECT origin_state, NULL, NULL, sum(package_weight)
  2. FROM shipping GROUP BY origin_state
  3. UNION ALL
  4. SELECT origin_state, origin_zip, NULL, sum(package_weight)
  5. FROM shipping GROUP BY origin_state, origin_zip
  6. UNION ALL
  7. SELECT NULL, NULL, destination_state, sum(package_weight)
  8. FROM shipping GROUP BY destination_state;

但是,使用复杂分组语法(GROUPING SETSCUBEROLLUP)的查询将只从基础数据源读取一次,而使用UNION ALL的查询会读取基础数据三次。因此,当数据源不确定时,带有UNION ALL的查询可能产生不一致的结果。

CUBE

CUBE运算符生成所有可能的分组集(即幂集)的给定列集。例如,以下查询:

  1. SELECT origin_state, destination_state, sum(package_weight)
  2. FROM shipping
  3. GROUP BY CUBE (origin_state, destination_state);

等价于:

  1. SELECT origin_state, destination_state, sum(package_weight)
  2. FROM shipping
  3. GROUP BY GROUPING SETS (
  4. (origin_state, destination_state),
  5. (origin_state),
  6. (destination_state),
  7. ());
  1. origin_state | destination_state | _col0
  2. --------------+-------------------+-------
  3. California | New Jersey | 55
  4. California | Colorado | 5
  5. New York | New Jersey | 3
  6. New Jersey | Connecticut | 225
  7. California | Connecticut | 1337
  8. California | NULL | 1397
  9. New York | NULL | 3
  10. New Jersey | NULL | 225
  11. NULL | New Jersey | 58
  12. NULL | Connecticut | 1562
  13. NULL | Colorado | 5
  14. NULL | NULL | 1625
  15. (12 rows)

ROLLUP

ROLLUP运算符为给定的列集生成所有可能的小记。例如,以下查询:

  1. SELECT origin_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY ROLLUP (origin_state, origin_zip);
  1. origin_state | origin_zip | _col2
  2. --------------+------------+-------
  3. California | 94131 | 60
  4. California | 90210 | 1337
  5. New Jersey | 7081 | 225
  6. New York | 10002 | 3
  7. California | NULL | 1397
  8. New York | NULL | 3
  9. New Jersey | NULL | 225
  10. NULL | NULL | 1625
  11. (8 rows)

等价于:

  1. SELECT origin_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY GROUPING SETS ((origin_state, origin_zip), (origin_state), ());

组合多个分组表达式

同一查询中的多个分组表达式被解释为具有叉积语义。例如,以下查询:

  1. SELECT origin_state, destination_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY
  4. GROUPING SETS ((origin_state, destination_state)),
  5. ROLLUP (origin_zip);

可以改写为:

  1. SELECT origin_state, destination_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY
  4. GROUPING SETS ((origin_state, destination_state)),
  5. GROUPING SETS ((origin_zip), ());

逻辑上等价于:

  1. SELECT origin_state, destination_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY GROUPING SETS (
  4. (origin_state, destination_state, origin_zip),
  5. (origin_state, destination_state));
  1. origin_state | destination_state | origin_zip | _col3
  2. --------------+-------------------+------------+-------
  3. New York | New Jersey | 10002 | 3
  4. California | New Jersey | 94131 | 55
  5. New Jersey | Connecticut | 7081 | 225
  6. California | Connecticut | 90210 | 1337
  7. California | Colorado | 94131 | 5
  8. New York | New Jersey | NULL | 3
  9. New Jersey | Connecticut | NULL | 225
  10. California | Colorado | NULL | 5
  11. California | Connecticut | NULL | 1337
  12. California | New Jersey | NULL | 55
  13. (10 rows)

ALLDISTINCT量词确定重复分组集是否各自生成不同的输出行。这在多个复杂分组集组合在同一个查询中时尤其有用。例如,以下查询:

  1. SELECT origin_state, destination_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY ALL
  4. CUBE (origin_state, destination_state),
  5. ROLLUP (origin_state, origin_zip);

等价于:

  1. SELECT origin_state, destination_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY GROUPING SETS (
  4. (origin_state, destination_state, origin_zip),
  5. (origin_state, origin_zip),
  6. (origin_state, destination_state, origin_zip),
  7. (origin_state, origin_zip),
  8. (origin_state, destination_state),
  9. (origin_state),
  10. (origin_state, destination_state),
  11. (origin_state),
  12. (origin_state, destination_state),
  13. (origin_state),
  14. (destination_state),
  15. ());

但是,如果查询对GROUP BY使用DISTINCT量词:

  1. SELECT origin_state, destination_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY DISTINCT
  4. CUBE (origin_state, destination_state),
  5. ROLLUP (origin_state, origin_zip);

只生成唯一的分组集合:

  1. SELECT origin_state, destination_state, origin_zip, sum(package_weight)
  2. FROM shipping
  3. GROUP BY GROUPING SETS (
  4. (origin_state, destination_state, origin_zip),
  5. (origin_state, origin_zip),
  6. (origin_state, destination_state),
  7. (origin_state),
  8. (destination_state),
  9. ());

默认的组量词是ALL

GROUPING操作

grouping(col1, ..., colN) -> bigint

GROUPING操作返回转换为十进制的位集,指示分组中存在哪些列。它必须与GROUPING SETSROLLUPCUBEGROUP BY一起使用,并且其参数必须与相应的GROUPING SETSROLLUPCUBEGROUP BY子句中引用的列完全匹配。

要计算特定行的结果位集,将位分配给参数列,其中最右边的列是最低有效位。对于给定的分组,如果相应的列包含在分组中,则位设置为0,否则设置为1。例如,考虑以下查询:

  1. SELECT origin_state, origin_zip, destination_state, sum(package_weight),
  2. grouping(origin_state, origin_zip, destination_state)
  3. FROM shipping
  4. GROUP BY GROUPING SETS (
  5. (origin_state),
  6. (origin_state, origin_zip),
  7. (destination_state));
  1. origin_state | origin_zip | destination_state | _col3 | _col4
  2. --------------+------------+-------------------+-------+-------
  3. California | NULL | NULL | 1397 | 3
  4. New Jersey | NULL | NULL | 225 | 3
  5. New York | NULL | NULL | 3 | 3
  6. California | 94131 | NULL | 60 | 1
  7. New Jersey | 7081 | NULL | 225 | 1
  8. California | 90210 | NULL | 1337 | 1
  9. New York | 10002 | NULL | 3 | 1
  10. NULL | NULL | New Jersey | 58 | 6
  11. NULL | NULL | Connecticut | 1562 | 6
  12. NULL | NULL | Colorado | 5 | 6
  13. (10 rows)

上述结果中的第一个分组只包括origin_state列,不包括origin_zip列和destination_state列。为该分组构造的位集是011,最高有效位表示origin_state

HAVING子句

HAVING子句与聚合函数和GROUP BY子句一起使用,以控制选择哪些组。HAVING子句排除不满足给定条件的组。分组和聚合计算完成后,HAVING对分组进行过滤。

以下示例查询customer表,选择余额大于指定金额的组。

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

UNION | INTERSECT | EXCEPT子句

UNIONINTERSECTEXCEPT都是集合运算。这些子句用于将多个SELECT语句的结果组合成单个结果集:

  1. query UNION [ALL | DISTINCT] query
  1. query INTERSECT [DISTINCT] query
  1. query EXCEPT [DISTINCT] query

参数ALLDISTINCT控制最终结果集中包括哪些行。如果指定了参数ALL,则包含所有行,即使这些行是相同的。如果指定了参数DISTINCT,则合并的结果集中只包含唯一的行。如果两个参数都没有指定,则行为默认为DISTINCTINTERSECTEXCEPT不支持ALL参数。

除非通过括号显式指定顺序,否则多个集合操作从左到右处理。另外,INTERSECT运算优先级高于EXCEPTUNIONA UNION B INTERSECT C EXCEPT D意思和A UNION (B INTERSECT C) EXCEPT D一样。

UNION

UNION将第一个查询的结果集中的所有行与第二个查询的结果集中的所有行合并。下面是最简单的UNION子句之一的示例。该查询选择值13,并将这个结果集与选择值42的第二个查询组合在一起:

  1. SELECT 13
  2. UNION
  3. SELECT 42;
  1. _col0
  2. -------
  3. 13
  4. 42
  5. (2 rows)

下面的查询演示了UNIONUNION ALL之间的区别。该查询选择值13,并将这个结果集与选择值4213的第二个查询组合在一起:

  1. SELECT 13
  2. UNION
  3. SELECT * FROM (VALUES 42, 13);
  1. _col0
  2. -------
  3. 13
  4. 42
  5. (2 rows)
  1. SELECT 13
  2. UNION ALL
  3. SELECT * FROM (VALUES 42, 13);
  1. _col0
  2. -------
  3. 13
  4. 42
  5. 13
  6. (2 rows)

INTERSECT

INTERSECT只返回同时存在于第一个和第二个查询的结果集中的行。下面是最简单的INTERSECT子句之一的示例。该查询选择值1342,并将这个结果集与选择值13的第二个查询组合在一起:由于42只在第一个查询的结果集中,所以它不会包含在最终结果中。

  1. SELECT * FROM (VALUES 13, 42)
  2. INTERSECT
  3. SELECT 13;
  1. _col0
  2. -------
  3. 13
  4. (2 rows)

EXCEPT

EXCEPT返回在第一个查询结果集中但不在第二个查询结果集中的行。下面是最简单的EXCEPT子句之一的示例。该查询选择值1342,并将这个结果集与选择值13的第二个查询组合在一起:由于13也在第二个查询的结果集中,所以它不会包含在最终结果中。

  1. SELECT * FROM (VALUES 13, 42)
  2. EXCEPT
  3. SELECT 13;
  1. _col0
  2. -------
  3. 42
  4. (2 rows)

ORDER BY子句

ORDER BY子句用于按一个或多个输出表达式对结果集进行排序:

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

每个表达式可以由输出列组成,也可以是按位置选择输出列的序数(从1开始)。ORDER BY子句在任何GROUP BYHAVING子句之后,任何OFFSETLIMITFETCH FIRST子句之前执行。默认的NULL排序是NULLS LAST,无论排序方向如何都是如此。

OFFSET子句

OFFSET子句用于从结果集中丢弃一些前导行:

  1. OFFSET count [ ROW | ROWS ]

如果ORDER BY子句存在,则OFFSET子句对已排序的结果集执行,并且该结果集在丢弃前导行之后仍保持排序:

  1. SELECT name FROM nation ORDER BY name OFFSET 22;
  1. name
  2. ----------------
  3. UNITED KINGDOM
  4. UNITED STATES
  5. VIETNAM
  6. (3 rows)

否则将任意丢弃一些行。如果OFFSET子句中指定的计数等于或超过结果集的大小,则最终结果为空。

LIMIT或FETCH FIRST子句

LIMITFETCH FIRST子句限制结果集中的行数。

  1. LIMIT { count | ALL }
  1. FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }

以下示例查询一个大表,但LIMIT子句将输出限制为只有五行(因为查询缺少ORDER BY,所以将返回任意行):

  1. SELECT orderdate FROM orders LIMIT 5;
  1. orderdate
  2. ------------
  3. 1994-07-25
  4. 1993-11-12
  5. 1992-10-06
  6. 1994-01-04
  7. 1997-12-28
  8. (5 rows)

LIMIT ALL等于省略了LIMIT子句。

FETCH FIRST子句支持FIRSTNEXT关键字,也支持ROWROWS关键字。这些关键字是等价的,关键字的选择对查询执行没有影响。

如果FETCH FIRST子句中没有指定计数,则默认为1

  1. SELECT orderdate FROM orders FETCH FIRST ROW ONLY;
  1. orderdate
  2. ------------
  3. 1994-02-12
  4. (1 row)

如果存在OFFSET子句,则LIMITFETCH FIRST子句在OFFSET子句之后执行:

  1. SELECT * FROM (VALUES 5, 2, 4, 1, 3) t(x) ORDER BY x OFFSET 2 LIMIT 2;
  1. x
  2. ---
  3. 3
  4. 4
  5. (2 rows)

对于FETCH FIRST子句,参数ONLYWITH TIES控制哪些行包括在结果集中。

如果指定了参数ONLY,结果集将限制为由计数确定的前导行的确切数目。

如果指定了参数WITH TIES,则要求存在ORDER BY子句。结果集由相同的前导行集和与之相同的对等组中的所有行组成。它们(“结”)是由ORDER BY子句中的顺序确定的。结果集被排序:

  1. SELECT name, regionkey FROM nation ORDER BY regionkey FETCH FIRST ROW WITH TIES;
  1. name | regionkey
  2. ------------+-----------
  3. ETHIOPIA | 0
  4. MOROCCO | 0
  5. KENYA | 0
  6. ALGERIA | 0
  7. MOZAMBIQUE | 0
  8. (5 rows)

TABLESAMPLE

有多种采样方法:

BERNOULLI

每一行都以样本百分比的概率被选择到表样本中。当使用Bernoulli方法对表进行采样时,将扫描该表的所有物理块,并基于样本百分比与运行时计算的随机值之间的比较结果跳过某些行。

结果中包含某一行的概率与任何其他行无关。这不会减少从磁盘读取采样表所需的时间。如果进一步处理采样输出,则可能会影响总查询时间。

SYSTEM

这种采样方法将表划分为数据的逻辑段,并以此粒度对表进行采样。这种抽样方法要么从特定数据段中选择所有行,要么基于样本百分比与运行时计算的随机值之间的比较结果跳过该数据段。

在系统采样中选定的行将取决于所使用的连接器。例如,当与Hive一起使用时,取决于数据在HDFS上的分布。这种方法不保证独立的采样概率。

注意

这两种方法都不允许对返回的行数进行确定性限制。

示例:

  1. SELECT *
  2. FROM users TABLESAMPLE BERNOULLI (50);
  3. SELECT *
  4. FROM users TABLESAMPLE SYSTEM (75);

采样过程中使用JOIN:

  1. SELECT o.*, i.*
  2. FROM orders o TABLESAMPLE SYSTEM (10)
  3. JOIN lineitem i TABLESAMPLE BERNOULLI (40)
  4. ON o.orderkey = i.orderkey;

UNNEST

UNNEST可用于将数组映射展开为关系。数组被扩展为单列,而映射被扩展为两列(键值)。UNNEST也可以与多个参数一起使用,在这种情况下,它们会扩展为多列,行数为最高基数参数(其他列用NULL填充)。UNNEST也可以带WITH ORDINALITY子句,在这种情况下,一个额外的普通列被添加到末尾。UNNEST通常与JOIN一起使用,并且可以引JOIN左侧的关系中的列。

使用单列:

  1. SELECT student, score
  2. FROM tests
  3. CROSS JOIN UNNEST(scores) AS t (score);

使用多列:

  1. SELECT numbers, animals, n, a
  2. FROM (
  3. VALUES
  4. (ARRAY[2, 5], ARRAY['dog', 'cat', 'bird']),
  5. (ARRAY[7, 8, 9], ARRAY['cow', 'pig'])
  6. ) AS x (numbers, animals)
  7. CROSS JOIN UNNEST(numbers, animals) AS t (n, a);
  1. numbers | animals | n | a
  2. -----------+------------------+------+------
  3. [2, 5] | [dog, cat, bird] | 2 | dog
  4. [2, 5] | [dog, cat, bird] | 5 | cat
  5. [2, 5] | [dog, cat, bird] | NULL | bird
  6. [7, 8, 9] | [cow, pig] | 7 | cow
  7. [7, 8, 9] | [cow, pig] | 8 | pig
  8. [7, 8, 9] | [cow, pig] | 9 | NULL
  9. (6 rows)

WITH ORDINALITY子句:

  1. SELECT numbers, n, a
  2. FROM (
  3. VALUES
  4. (ARRAY[2, 5]),
  5. (ARRAY[7, 8, 9])
  6. ) AS x (numbers)
  7. CROSS JOIN UNNEST(numbers) WITH ORDINALITY AS t (n, a);
  1. numbers | n | a
  2. -----------+---+---
  3. [2, 5] | 2 | 1
  4. [2, 5] | 5 | 2
  5. [7, 8, 9] | 7 | 1
  6. [7, 8, 9] | 8 | 2
  7. [7, 8, 9] | 9 | 3
  8. (5 rows)

JOIN

JOIN允许组合来自多个关系的数据。

CROSS JOIN

CROSS JOIN返回两个关系的笛卡尔积(所有组合)。可以使用显式CROSS JOIN语法或通过在FROM子句中指定多个关系来指定交叉联接。

以下两个查询是等价的:

  1. SELECT *
  2. FROM nation
  3. CROSS JOIN region;
  4. SELECT *
  5. FROM nation, region;

nation表包含25行,region表包含5行,因此两个表之间的交叉联接将生成125行:

  1. SELECT n.name AS nation, r.name AS region
  2. FROM nation AS n
  3. CROSS JOIN region AS r
  4. ORDER BY 1, 2;
  1. nation | region
  2. ----------------+-------------
  3. ALGERIA | AFRICA
  4. ALGERIA | AMERICA
  5. ALGERIA | ASIA
  6. ALGERIA | EUROPE
  7. ALGERIA | MIDDLE EAST
  8. ARGENTINA | AFRICA
  9. ARGENTINA | AMERICA
  10. ...
  11. (125 rows)

LATERAL

出现在FROM子句中的子查询前面可以加关键字LATERAL。这允许子查询引用前面FROM项提供的列。

LATERAL联接可以出现在FROM列表的顶层,或者括号括起来的联接树中的任何地方。在后一种情况下,对于联接在右侧的项目,联接也可以引用位于JOIN左侧的任何项目。

FROM项包含LATERAL交叉引用时,计算过程如下:对于提供交叉引用列的FROM项的每一行,将使用该行集的列值对LATERAL项进行计算。所得行正常与它们从中计算出来的行连接在一起。对于列源表中的行集重复此过程。

LATERAL主要用于需要使用交叉引用的列来计算要连接的行的情形:

  1. SELECT name, x, y
  2. FROM nation
  3. CROSS JOIN LATERAL (SELECT name || ' :-' AS x)
  4. CROSS JOIN LATERAL (SELECT x || ')' AS y)

限定列名

当联接中的两个关系具有同名的列时,必须使用关系别名(如果关系具有别名)或使用关系名称对列引用进行限定:

  1. SELECT nation.name, region.name
  2. FROM nation
  3. CROSS JOIN region;
  4. SELECT n.name, r.name
  5. FROM nation AS n
  6. CROSS JOIN region AS r;
  7. SELECT n.name, r.name
  8. FROM nation n
  9. CROSS JOIN region r;

以下查询将失败,并返回错误Column 'name' is ambiguous

  1. SELECT name
  2. FROM nation
  3. CROSS JOIN region;

子查询

子查询是由查询组成的表达式。当某个子查询引用该子查询外层的列时,该子查询称为相关子查询。逻辑上,会针对父查询中的每一行计算子查询。因此,在对子查询进行任何单个计算时,所引用的列将保持不变。

说明

对相关子查询的支持有限。并不是每个标准表单都受支持。

EXISTS

EXISTS谓词确定子查询是否返回任何行:

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

IN

IN谓词确定子查询产生的任何值是否等于提供的表达式。IN的结果遵循NULL的标准规则。子查询必须生成一列:

  1. SELECT name
  2. FROM nation
  3. WHERE regionkey IN (SELECT regionkey FROM region)

标量子查询

标量子查询是返回零行或一行的不相关子查询。子查询生成多行时即出错。如果子查询没有输出行,则返回值为NULL

  1. SELECT name
  2. FROM nation
  3. WHERE regionkey = (SELECT max(regionkey) FROM region)

说明

目前标量子查询只能返回单列。