SELECT

从表或视图中检索行。

概要

  1. [ WITH [ RECURSIVE1 ] with_query [, ...] ]
  2. SELECT [ALL | DISTINCT [ON (expression [, ...])]]
  3. * | expression[[AS] output_name] [, ...]
  4. [FROM from_item [, ...]]
  5. [WHERE condition]
  6. [GROUP BY grouping_element [, ...]]
  7. [HAVING condition [, ...]]
  8. [WINDOW window_name AS (window_definition) [, ...] ]
  9. [{UNION | INTERSECT | EXCEPT} [ALL | DISTINCT] select]
  10. [ORDER BY expression [ASC | DESC | USING operator] [NULLS {FIRST | LAST}] [, ...]]
  11. [LIMIT {count | ALL}]
  12. [OFFSET start [ ROW | ROWS ] ]
  13. [FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY]
  14. [FOR {UPDATE | NO KEY UPDATE | SHARE | KEY SHARE} [OF table_name [, ...]] [NOWAIT] [...]]
  15. TABLE { [ ONLY ] table_name [ * ] | with_query_name }

其中with_query:是:

  1. with_query_name [( column_name [, ...] )] AS ( select | values | insert | update | delete )

其中from_item可以是以下之一:

  1. [ONLY] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
  2. ( select ) [ AS ] alias [( column_alias [, ...] ) ]
  3. with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
  4. function_name ( [ argument [, ...] ] )
  5. [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
  6. function_name ( [ argument [, ...] ] ) [ AS ] alias ( column_definition [, ...] )
  7. function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )
  8. ROWS FROM( function_name ( [ argument [, ...] ] ) [ AS ( column_definition [, ...] ) ] [, ...] )
  9. [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
  10. from_item [ NATURAL ] join_type from_item
  11. [ ON join_condition | USING ( join_column [, ...] ) ]

其中grouping_element可以是以下之一:

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

其中window_definition是:

  1. [existing_window_name]
  2. [PARTITION BY expression [, ...]]
  3. [ORDER BY expression [ASC | DESC | USING operator]
  4. [NULLS {FIRST | LAST}] [, ...]]
  5. [{ RANGE | ROWS} frame_start
  6. | {RANGE | ROWS} BETWEEN frame_start AND frame_end

其中frame_start和frame_end可以是以下之一:

  1. UNBOUNDED PRECEDING
  2. value
  3. PRECEDING
  4. CURRENT ROW
  5. value
  6. FOLLOWING
  7. UNBOUNDED FOLLOWING

注解: 1RECURSIVE关键字是一个Beta功能。

描述

SELECT从零个或多个表中检索行。 SELECT的一般处理如下:

  1. WITH子句中的所有查询均被计算。 这些可以有效地用作可以在FROM列表中引用的临时表。
  2. 将计算FROM列表中的所有元素。 (FROM列表中的每个元素都是真实表或虚拟表。) 如果FROM列表中指定了多个元素,则它们将交叉连接在一起。
  3. 如果指定了WHERE子句,则从输出中排除所有不满足该条件的行。
  4. 如果指定了GROUP BY子句,或者存在聚合函数调用, 则将输出组合为与一个或多个值匹配的行组,并计算聚合函数的结果。 如果存在HAVING子句,它将排除不满足给定条件的组。
  5. 实际的输出行是使用SELECT输出表达式为每个选定的行或行组计算的。
  6. SELECT DISTINCT从结果中消除重复的行。 SELECT DISTINCT ON消除与所有指定表达式匹配的行。 SELECT ALL(默认)将返回所有候选行,包括重复项。
  7. 如果指定了窗口表达式(和可选的WINDOW子句), 则根据位置(行)或基于值的(范围)窗口框架来组织输出。
  8. 使用每个选定行的SELECT输出表达式来计算实际的输出行。
  9. 使用运算符UNION,INTERSECT和EXCEPT,可以组合多个SELECT语句的输出以形成单个结果集。 UNION运算符返回一个或两个结果集中的所有行。 INTERSECT运算符返回完全位于两个结果集中的所有行。 EXCEPT运算符返回第一个结果集中的行,而不是第二个结果集中的行。 在所有三种情况下,除非指定了ALL,否则将消除重复的行。 可以添加噪声字DISTINCT来明确指定消除重复行。 请注意,DISTINCT是此处的默认行为,即使ALL是SELECT本身的默认行为。
  10. 如果指定了ORDER BY子句,则返回的行将以指定的顺序排序。 如果未给出ORDER BY,则以系统最先找到的顺序返回行。
  11. 如果指定了LIMIT(或FETCH FIRST)或OFFSET子句, 则SELECT语句仅返回结果行的子集。
  12. 如果指定了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,INSERT,UPDATE或DELETE语句。 在用WITH编写数据修改语句(INSERT,UPDATE或DELETE)时,通常会包含RETURNING子句。 它是RETURNING的输出,而不是该语句修改的基础表,形成了由主查询读取的临时表。 如果省略RETURNING,则该语句仍将执行,但是不会产生任何输出,因此主查询无法将其引用为表。

对于包含WITH子句的SELECT命令, 该子句最多可以包含一个用于修改表数据的子句(INSERT,UPDATE或DELETE命令)。

必须为WITH子句中的每个查询指定一个无schema限定的with_query_name。 (可选)可以指定列名列表;如果省略列名列表,则从子查询中推断出名称。 主查询和WITH查询都(理论上)同时执行。

如果指定了RECURSIVE,则它允许SELECT子查询按名称引用自己。 这样的子查询具有一般形式

  1. non_recursive_term UNION [ALL | DISTINCT] recursive_term

递归自引用出现在UNION的右侧。 每个查询仅允许一个递归自引用。 不支持递归数据修改语句,但是您可以在数据修改语句中使用递归SELECT查询的结果。

如果指定了RECURSIVE关键字,则无需对WITH查询进行排序:一个查询可以引用列表中后面的另一个查询。 但是,不支持循环引用或相互递归。

如果没有RECURSIVE关键字, 则WITH查询只能引用WITH列表中较早的同级WITH查询。

WITH RECURSIVE限制。不支持这些项目:

  • 一个递归WITH子句,在recursive_term中包含以下内容。
    • 具有自引用的子查询
    • DISTINCT 子句
    • GROUP BY 子句
    • 窗口函数
  • 递归WITH子句,其中with_query_name是集合操作的一部分。

以下是集合操作限制的示例。 该查询返回错误,因为集合操作UNION包含对表foo的引用。

  1. WITH RECURSIVE foo(i) AS (
  2. SELECT 1
  3. UNION ALL
  4. SELECT i+1 FROM (SELECT * FROM foo UNION SELECT 0) bar
  5. )
  6. SELECT * FROM foo LIMIT 5;

由于集合操作UNION没有对CTE foo的引用,因此允许此递归CTE。

  1. WITH RECURSIVE foo(i) AS (
  2. SELECT 1
  3. UNION ALL
  4. SELECT i+1 FROM (SELECT * FROM bar UNION SELECT 0) bar, foo
  5. WHERE foo.i = bar.a
  6. )
  7. SELECT * FROM foo LIMIT 5;

WITH查询的一个关键属性是,即使主查询多次引用它们,一次执行主查询也只会对它们进行一次评估。 特别是,无论主查询是读取全部输出还是输出任何内容,都保证数据修改语句仅执行一次。

主查询和WITH查询都(理论上)同时执行。 这意味着,除了通过读取其RETURNING输出之外,不能从查询的其他部分看到WITH中的数据修改语句的效果。 如果两个这样的数据修改语句试图修改同一行,则结果不确定。

有关更多信息,请参见WITH查询(公用表表达式)WITH查询(公用表表达式)

SELECT列表

SELECT列表(在关键字SELECT和FROM之间)指定用于形成SELECT语句输出行的表达式。 表达式可以(通常)引用FROM子句中计算的列。

SELECT列表中的expression可以是常量值,列引用,运算符调用,函数调用,聚合表达式,窗口表达式,标量子查询等。 可以将许多结构体归类为表达式,但不遵循任何常规语法规则。 这些通常具有函数或运算符的语义。 有关SQL值表达式和函数调用的信息,请参阅Greenplum数据库管理员指南中的“查询数据”。

就像在表中一样,SELECT的每个输出列都有一个名称。 在简单的SELECT中,此名称仅用于标记要显示的列, 但是当SELECT是较大查询的子查询时,该名称在较大查询中被视为由该子查询生成的虚拟表的列名。 要指定用于输出列的名称,请在该列的表达式之后写入AS output_name。 (您可以省略AS,但只有在所需的输出名称与任何SQL关键字都不匹配时才可以使用。 为防止将来可能再添加关键字,您始终可以写AS或在输出名称中用双引号。) 如果不指定列名称,Greenplum数据库自动选择一个名称。 如果列的表达式是简单的列引用,则所选名称与该列的名称相同。 在更复杂的情况下,可以使用函数或类型名称,或者系统可能会依赖生成的名称(例如?column?或columnN)。

输出列的名称可用于引用ORDER BY和GROUP BY子句中的列的值, 但不能用于WHERE或HAVING子句中。 在那里,您必须写出表达式。

可以将*而不是表达式写到输出列表,作为所选行的所有列的简写。 另外,您可以编写table_name.*作为仅来自该表的列的简写。 在这种情况下,无法使用AS指定新名称。 输出列名称将与表列名称相同。

DISTINCT子句

如果指定了SELECT DISTINCT,则将从结果集中删除所有重复的行(每组重复项中保留一行)。 SELECT ALL则相反:所有行都保留;这是默认值。

SELECT DISTINCT ON ( expression [, …] )仅保留给定表达式等于的每组行的第一行。 使用与ORDER BY相同的规则来解释DISTINCT ON表达式(请参见上文)。 请注意,除非使用ORDER BY来确保所需的行最先出现,否则每个集合的“第一行”都是不可预测的。 例如:

  1. SELECT DISTINCT ON (location) location, time, report
  2. FROM weather_reports
  3. ORDER BY location, time DESC;

检索每个位置的最新天气报告。 但是,如果我们没有使用ORDER BY强制每个位置的时间值按降序排列,那么我们将从每个位置不可预测的时间获得报告。

DISTINCT ON表达式必须与最左边的ORDER BY表达式匹配。 ORDER BY子句通常将包含附加表达式,这些表达式确定每个DISTINCT ON组中所需的行优先级。

FROM子句

FROM子句为SELECT指定一个或多个源表。 如果指定了多个源,则结果为所有源的笛卡尔乘积(交叉连接)。 但通常会添加限定条件(通过WHERE),以将返回的行限制为笛卡尔乘积的一小部分。 FROM子句可以包含以下元素:

table_name

现有表或视图的名称(可以有schema修饰)。 如果指定ONLY,则仅扫描该表。 如果未指定ONLY,则扫描该表及其所有子表(如果有)。

alias

包含别名的FROM项目的替代名称。 别名用于简洁起见或用于消除自连接的歧义(多次扫描同一张表)。 提供别名后,它将完全隐藏表或函数的实际名称。 例如,在给定FROM foo AS f的情况下, SELECT的其余部分必须将此FROM项目引用为f而不是foo。 如果写入了别名,则还可以写入列别名列表以为表的一个或多个列提供替代名称。

select

子SELECT可以出现在FROM子句中。 这就像在单个SELECT命令期间将其输出创建为临时表一样。 请注意,子SELECT必须用括号括起来,并且必须为其提供别名。 VALUES命令也可以在这里使用。 有关在Greenplum数据库中使用相关子选择的限制,请参阅兼容性部分中的“非标准子句”。

with_query_name

通过指定其with_query_name在FROM子句中引用with_query,就像该名称是表名一样。 with_query_name不能包含schema限定符。 可以使用与表相同的方式提供别名。

with_query隐藏用于主查询目的的同名表。 如有必要,可以通过使用schema限定表名来引用相同名称的表。

function_name

函数调用可以出现在FROM子句中。 (这对于返回结果集的函数特别有用,但是可以使用任何函数。) 这就像在单个SELECT命令期间将其输出创建为临时表一样。 也可以使用别名。 如果编写了别名,则还可以编写列别名列表,以为函数的复合返回类型的一个或多个属性提供替代名称。 如果已将函数定义为返回记录数据类型,则必须存在别名或关键字AS, 然后是形式为(column_name data_type [, … ] )的列定义列表。 列定义列表必须匹配该函数返回的实际列数和类型。

join_type

以下之一:

  • [INNER] JOIN
  • LEFT [OUTER] JOIN
  • RIGHT [OUTER] JOIN
  • FULL [OUTER] JOIN
  • CROSS JOIN

对于INNER和OUTER连接类型,必须指定一个连接条件, 即恰好是NATURAL,ON join_condition或USING (join_column[, …])之一。 含义如下。 对于CROSS JOIN,这些子句都不会出现。

JOIN子句结合了两个FROM项,为方便起见,我们将其称为“表”, 尽管实际上它们可以是任何类型的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返回所有连接的行,再加上一行, 用于每行不匹配的左表行(在右边扩展为空),再加上每行不匹配的右表行(扩展在左边为空)。

ON join_condition

join_condition是一个表达式, 其结果为boolean类型的值(类似于WHERE子句),该值指定连接中的哪些行被视为匹配。

USING (join_column [, …])

USING ( a, b, … )形式的子句是ON left_table.a = right_table.a AND left_table.b = right_table.b …的简写。 同样,USING意味着连接输出中将仅包括每对等效列中的一对,而不是两者。

NATURAL

NATURAL是USING列表的简写形式,该列表提到两个表中具有相同名称的所有列。 如果没有公用的列名,则NATURAL等效于ON TRUE。

WHERE子句

可选的WHERE子句具有一般形式:

  1. WHERE condition

condition是任何计算结果为boolean型结果的表达式。 任何不满足此条件的行将从输出中删除。 如果用一行的实际值替换其中的变量引用后,该表达式返回真,则该行符合条件。

GROUP BY子句

可选的GROUP BY子句具有一般形式:

  1. GROUP BY grouping_element[, ...]

其中grouping_element可以是以下之一:

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

GROUP BY将所有共享有相同值的分组表达式的所有选定行压缩为单行。 expression可以是输入列名称,也可以是输出列(SELECT列表项)的名称或序号,或者是由输入列值组成的任意表达式。 如有歧义,GROUP BY名称将被解释为输入列名称,而不是输出列名称。

汇总函数(如果有的话)在组成每个组的所有行中进行计算,从而为每个组生成单独的值。 (如果有聚合函数但没有GROUP BY子句,则该查询被视为具有包含所有选定行的单个组。) 可以通过将FILTER子句附加到聚合函数调用来进一步过滤提供给每个聚合函数的行集。 如果存在FILTER子句,则只有与之匹配的那些行才包含在该聚合函数的输入中。

如果存在GROUP BY或任何聚合函数,则SELECT列表表达式不能引用未分组的列, 除非是在聚合函数内,或者当未分组的列在函数上依赖于分组的列时,否则对于未分组的列将会返回不止一个的可能的值。 如果分组的列(或其子集)是包含未分组的列的表的主键,则存在函数依赖。

请记住,在评估HAVING子句或SELECT列表中的任何“标量”表达式之前,将评估所有聚合函数。 这意味着,例如,CASE表达式不能用于跳过对聚合函数的求值;见表达式计算规则

Greenplum数据库具有以下附加的OLAP分组扩展(通常称为supergroups):

ROLLUP

ROLLUP分组是对GROUP BY子句的扩展,该子句创建聚合部分和, 该部分和从最详细的级别汇总到总计,并遵循分组列(或表达式)的列表。 ROLLUP提取分组列的有序列表,计算在GROUP BY子句中指定的标准聚合值, 然后逐步创建更高级别的部分和,从列表的右向左移动。 最后,它创建了一个总计。 可以将ROLLUP分组视为一系列分组集。 例如:

  1. GROUP BY ROLLUP (a,b,c)

等效于:

  1. GROUP BY GROUPING SETS( (a,b,c), (a,b), (a), () )

请注意,ROLLUP的n个元素转换为n+1个分组集。 同样,在ROLLUP中指定分组表达式的顺序也很重要。

CUBE

CUBE分组是对GROUP BY子句的扩展,它为分组列(或表达式)的给定列表的所有可能组合创建部分和。 在多维分析方面,CUBE生成可以为具有指定维的多维数据集计算的所有部分和。 例如:

  1. GROUP BY CUBE (a,b,c)

等效于:

  1. GROUP BY GROUPING SETS( (a,b,c), (a,b), (a,c), (b,c), (a),
  2. (b), (c), () )

注意,CUBE的n个元素转换为2n个分组集。 考虑在需要交叉表报告的任何情况下使用CUBE。 CUBE通常最适合使用多个维度列而不是表示单个维度不同级别的列的查询。 例如,通常要求的交叉列表可能需要月份,州和产品的所有组合的部分和。

GROUPING SETS

您可以使用GROUP BY子句中的GROUPING SETS表达式有选择地指定要创建的组集。 这样就可以在多个维度上进行精确指定,而无需计算整个ROLLUP或CUBE。 例如:

  1. GROUP BY GROUPING SETS( (a,c), (a,b) )

如果使用分组扩展子句ROLLUP,CUBE或GROUPING SETS,则要面临两个问题。 首先,如何确定哪些结果行是部分和,然后确定给定部分和的确切聚合级别。 或者,如何区分包含存储的NULL值和由ROLLUP或CUBE创建的“NULL”值的结果行。 其次,当在GROUP BY子句中指定重复的分组集时,如何确定哪些结果行是重复的? 您可以在SELECT列表中使用两个附加的分组函数来帮助解决此问题:

  • grouping(column [, …]) — 可以将grouping函数应用于一个或多个分组属性,以将超聚合的行与常规的分组的行区分开。 这有助于将代表超级汇总行中所有值的集合的“NULL”与常规行中的NULL值区分开。 此函数中的每个参数都产生一个位 - 1或0, 其中1表示结果行是超级聚合的,而0表示结果行来自常规分组。 grouping函数通过将这些位视为二进制数然后将其转换为以10为基的整数来返回整数。
  • group_id() — 对于包含重复分组集的分组扩展查询,group_id函数用于标识输出中的重复行。 所有唯一分组集输出的唯一行的group_id值为0。 对于每个检测到的重复分组集,group_id函数分配的group_id编号大于0。 特定重复分组集中的所有输出行均由相同的group_id编号标识。

WINDOW子句

可选的WINDOW子句指定出现在查询的SELECT列表或ORDER BY子句中的窗口函数的行为。 这些函数可以在其OVER子句中按名称引用WINDOW子句条目。 但是,WINDOW子句条目不必在任何地方引用。 如果查询中未使用它,则将其忽略。 可以根本不使用任何WINDOW子句来使用窗口函数,因为窗口函数调用可以直接在其OVER子句中指定其窗口定义。 但是,当多个窗口函数需要相同的窗口定义时,WINDOW子句将保存键入内容。

例如:

  1. SELECT vendor, rank() OVER (mywindow) FROM sale
  2. GROUP BY vendor
  3. WINDOW mywindow AS (ORDER BY sum(prc*qty));

WINDOW子句具有以下一般形式:

  1. WINDOW window_name AS (window_definition)

其中window_name是可以从OVER子句或后续窗口定义中引用的名称, 而window_definition为:

  1. [existing_window_name]
  2. [PARTITION BY expression [, ...]]
  3. [ORDER BY expression [ASC | DESC | USING operator] [NULLS {FIRST | LAST}] [, ...] ]
  4. [frame_clause]

existing_window_name

如果指定了existing_window_name,则它必须引用WINDOW列表中的较早条目; 新窗口将复制该条目的分区子句以及其排序子句(如果有)。 新窗口不能指定自己的PARTITION BY子句,只有复制的窗口没有该子句时,它才能指定ORDER BY。 新窗口始终使用其自己的frame子句;复制的窗口不得指定frame子句。

PARTITION BY

PARTITION BY子句根据指定表达式的唯一值将结果集组织为逻辑组。 PARTITION BY子句的元素的解释方式与GROUP BY子句的元素几乎相同, 不同之处在于它们始终是简单表达式,而不是输出列的名称或编号。 另一个区别是这些表达式可以包含聚合函数调用,这在常规GROUP BY子句中是不允许的。 在此处允许使用它们,因为窗口在分组和聚合之后发生。 与窗口函数一起使用时,这些函数将分别应用于每个分区。 例如,如果在PARTITION BY之后加上列名,则结果集将按该列的不同值进行分区。 如果省略,则将整个结果集视为一个分区。

同样,ORDER BY列表中的元素的解释方式与ORDER BY子句中的元素几乎相同, 不同之处在于,始终将表达式视为简单表达式,而不使用输出列的名称或编号。

ORDER BY

ORDER BY子句的元素定义如何对结果集的每个分区中的行进行排序。 如果省略,则以最有效的顺序返回行,并且行可能会有所不同。 注意:缺少一致顺序(例如time)的数据类型的列不是在窗口规范的ORDER BY子句中使用的良好候选对象。 带有或不带有时区的时间缺乏连贯的排序,因为加法和减法没有预期的效果。 例如,以下条件通常不成立:x::time < x::time + ‘2 hour’::interval

frame_clause

可选的frame_clause定义依赖于框架的窗口函数的窗口框架(并非全部如此)。 窗口框架是查询的每一行(称为当前行)的一组相关行。 frame_clause可以是以下之一

  1. { RANGE | ROWS } frame_start
  2. { RANGE | ROWS } BETWEEN frame_start AND frame_end

其中frame_start和frame_end可以是以下之一

  • UNBOUNDED PRECEDING
  • value PRECEDING
  • CURRENT ROW
  • value FOLLOWING
  • UNBOUNDED FOLLOWING

如果省略frame_end,则默认为CURRENT ROW。 限制条件是frame_start不能为UNBOUNDED FOLLOWING, frame_end不能为UNBOUNDED PRECEDING, 并且frame_end选择不能在上述列表中出现在frame_start选择之前 — 例如,RANGE BETWEEN CURRENT ROW AND value PRECEDING是不允许的。

默认的框架选项是RANGE UNBOUNDED PRECEDING,与RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW之间的范围相同; 它将框架设置为从分区开始到当前行的最后一个对等方的所有行(ORDER BY的行认为与当前行等效,如果没有ORDER BY则为所有行)。 通常,UNBOUNDED PRECEDING表示框架以分区的第一行开始, 类似地UNBOUNDED FOLLOWING表示框架以分区的最后一行结束(与RANGE或ROWS模式无关)。 在ROWS模式下,CURRENT ROW表示框架以当前行开始或结束; 但是在RANGE模式下,这意味着框架以ORDER BY顺序中当前行的第一个或最后一个对等点开始或结束。 当前仅在ROWS模式下允许value PRECEDING和value FOLLOWING情况。 它们指示框架以当前行之前或之后许多行的行开始或结束。 value必须是不包含任何变量,聚合函数或窗口函数的整数表达式。 该值不能为null或负数;但它可以为零,从而选择当前行本身。

请注意,如果ORDER BY排序不能唯一地对行进行排序,则ROWS选项可能会产生不可预测的结果。 RANGE选项旨在确保以相同的方式对待在ORDER BY顺序中为对等的行; 所有对等行将在同一框架中。

使用ROWS或RANGE子句来表示窗口的边界。 窗口边界可以是一个分区的一行,多行或所有行。 您可以用偏移当前行值的数据值范围(RANGE)或偏移当前行的行数(ROWS)来表示窗口的边界。 使用RANGE子句时,还必须使用ORDER BY子句。 这是因为为生成窗口而执行的计算需要对值进行排序。 此外,ORDER BY子句不能包含多个表达式,并且该表达式必须导致日期或数字值。 使用ROWS或RANGE子句时,如果仅指定起始行,则当前行将用作窗口中的最后一行。

PRECEDING — PRECEDING子句使用当前行作为参考点定义窗口的第一行。 起始行以当前行之前的行数表示。 例如,对于ROWS框架,5 PRECEDING设置窗口从当前行之前的第五行开始。 对于RANGE框架,它将窗口设置为从第一行开始,其排序列值在给定顺序比当前行的顺序高5。 如果指定的顺序按日期升序,则它将是当前行之前5天内的第一行。 UNBOUNDED PRECEDING将窗口中的第一行设置为分区中的第一行。

BETWEEN — BETWEEN子句使用当前行作为参考点定义窗口的第一行和最后一行。 第一行和最后一行分别用当前行之前和之后的行数表示。 例如,BETWEEN 3 PRECEDING AND 5 FOLLOWING将窗口设置为从当前行之前的第三行开始,到当前行之后的第五行结束。 使用BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING, 可以将窗口中的第一行和最后一行分别设置为分区的第一行和最后一行。 如果未指定ROW或RANGE子句,则等效于默认行为。

FOLLOWING — FOLLOWING子句使用当前行作为参考点定义窗口的最后一行。 最后一行以当前行之后的行数表示。 例如,对于ROWS框架,5 FOLLOWING将窗口设置为在当前行之后的第五行结束。 在RANGE框架的情况下,它将窗口设置为最后一行的末尾,其排序列值在给定顺序的当前行后5个。 如果指定的顺序按日期升序,则它将是当前行之后5天内的最后一行。 使用UNBOUNDED FOLLOWING将窗口中的最后一行设置为分区中的最后一行。

如果未指定ROW或RANGE子句,并且使用ORDER BY, 则窗口绑定从分区的第一行(UNBOUNDED PRECEDING)开始,到当前行(CURRENT ROW)结束。 如果未指定ORDER BY,则窗口从分区的第一行开始(UNBOUNDED PRECEDING), 然后从分区的最后一行结束(UNBOUNDED FOLLOWING)。

HAVING子句

可选的HAVING子句具有以下一般形式:

  1. HAVING condition

其中condition与为WHERE子句指定的条件相同。 HAVING去除不满足条件的组行。 HAVING与WHERE不同:WHERE在应用GROUP BY之前过滤单个行, 而HAVING过滤GROUP BY创建的组行。 condition中引用的每个列都必须明确引用一个分组列,除非该引用出现在聚合函数中或未分组的列在函数上依赖于分组列。

即使没有GROUP BY子句,HAVING的存在也会将查询转换为分组查询。 这与查询包含聚合函数但不包含GROUP BY子句的情况相同。 所有选定的行都被视为形成一个单一的组,并且SELECT列表和HAVING子句只能引用聚合函数中的表列。 如果HAVING条件为true,则此类查询将返回单行;如果条件不是true,则将返回零行。

UNION子句

UNION子句具有以下一般形式:

  1. 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语句必须产生相同数量的列,并且对应的列必须具有兼容的数据类型。

除非指定了ALL选项,否则UNION的结果不包含任何重复的行。 ALL防止重复项的消除。 (因此,UNION ALL通常比UNION快得多;请尽可能使用ALL。) 可以编写DISTINCT来明确指定消除重复行的默认行为。

除非括号中另有说明,否则同一SELECT语句中的多个UNION运算符从左到右求值。

当前,不能为UNION结果或UNION的任何输入指定FOR NO KEY UPDATE, FOR UPDATE,FOR SHARE和FOR KEY SHARE。

INTERSECT子句

INTERSECT子句具有以下一般形式:

  1. 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语句返回的行的交集。 如果一行出现在两个结果集中,则该行位于两个结果集中的交集。

除非指定ALL选项,否则INTERSECT的结果不包含任何重复的行。 使用ALL,在左表中具有m个重复项且在右表中具有n个重复项的行将在结果集中出现min(m,n)次。 可以编写DISTINCT来明确指定消除重复行的默认行为。

除非括号中另有规定,否则同一SELECT语句中的多个INTERSECT运算符从左到右求值。 INTERSECT的优先级比UNION高。 即,A UNION B INTERSECT C等同于A UNION (B INTERSECT C)。

当前,不能为INTERSECT结果或INTERSECT的任何输入指定FOR NO KEY UPDATE, FOR UPDATE,FOR SHARE和FOR KEY SHARE。

EXCEPT子句

EXCEPT子句具有以下一般形式:

  1. 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语句的结果但不在右SELECT的结果的行集。

除非指定了ALL选项,否则EXCEPT的结果将不包含任何重复的行。 使用ALL,在左表中具有m个重复项且在右表中具有n个重复项的行将在结果集中出现max(m-n,0)次。 可以编写DISTINCT来明确指定消除重复行的默认行为。

除非括号中另有规定,否则同一SELECT语句中的多个EXCEPT运算符从左到右求值。 EXCEPT与UNION优先级相同。

当前,不能为EXCEPT结果或EXCEPT的任何输入指定FOR NO KEY UPDATE, FOR UPDATE,FOR SHARE和FOR KEY SHARE。

ORDER BY子句

可选的ORDER BY子句具有以下一般形式:

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

其中expression可以是输出列(SELECT列表项)的名称或序号, 也可以是由输入列值组成的任意表达式。

ORDER BY子句使结果行根据指定的表达式排序。 如果两行最左边的表达式相等,则根据下一个表达式对它们进行比较,依此类推。 如果所有指定的表达式相等,则将根据实现的顺序返回它们。

序号是指输出列的序数位置(从左到右)。 通过此特性,可以基于没有唯一名称的列来定义顺序。 这绝对不是必须的,因为始终可以使用AS子句为输出列分配名称。

还可以在ORDER BY子句中使用任意表达式,包括未出现在SELECT输出列表中的列。 因此,以下语句是有效的:

  1. 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子句中指定特定的排序运算符名称。 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”。 有关定义排序规则的信息,请参见CREATE COLLATION

LIMIT子句

LIMIT子句包含两个独立的子句:

  1. LIMIT {count | ALL}
  2. OFFSET start

其中count指定要返回的最大行数,而start指定在开始返回行之前要跳过的行数。 如果同时指定了两者,则在开始对要返回的count行进行计数之前,将跳过起始行。

如果count表达式的计算结果为NULL,则将其视为LIMIT ALL,即无限制。 如果start计算为NULL,则将其与OFFSET 0相同。

SQL:2008引入了不同的语法来实现相同的结果,Greenplum数据库也支持该语法。 它是:

  1. OFFSET start [ ROW | ROWS ]
  2. FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY

在这种语法中,标准要求start或count值是文字常量,参数或变量名; 作为Greenplum数据库扩展,可以使用其他表达式,但通常需要将其括在括号中以避免歧义。 如果在FETCH子句中省略了count,则其默认值为1。 ROW和ROWS以及FIRST和NEXT是不影响这些子句效果的干扰词。 根据标准,如果两者都存在,则OFFSET子句必须位于FETCH子句之前。 但Greenplum数据库允许使用任何顺序。

使用LIMIT时,最好使用ORDER BY子句将结果行强制为唯一的顺序。 否则,您将获得查询行的不可预测的子集 - 您可能会要求以第十到第二十行,但以什么顺序要求第十到第二十行? 除非您指定ORDER BY,否则您不知道该如何排序。

查询优化器在生成查询计划时会考虑LIMIT,因此根据LIMIT和OFFSET的使用方式,您很可能会获得不同的计划(产生不同的行顺序)。 因此,除非使用ORDER BY强制执行可预测的结果顺序,否则使用不同的LIMIT/OFFSET值选择查询结果的不同子集将产生不一致的结果。 这不是缺陷;这是一个正常的结果,即除非使用ORDER BY强制该顺序,否则SQL不会保证以任何特定顺序传递查询结果。

Locking子句

FOR UPDATE,FOR NO KEY UPDATE,FOR SHARE和FOR KEY SHARE是锁定子句; 它们会影响SELECT如何锁定从表中获取的行。

锁定子句具有一般形式

  1. FOR lock_strength [OF table_name [ , ... ] ] [ NOWAIT ]

其中lock_strength可以是以下之一

  1. UPDATE
  2. NO KEY UPDATE
  3. SHARE
  4. KEY SHARE

Note: 默认情况下,Greenplum数据库获取对表的EXCLUSIVE锁,以对堆表进行DELETE和UPDATE操作。 启用全局死锁检测器后,堆表上DELETE和UPDATE操作的锁定模式为ROW EXCLUSIVE。 通过将gp_enable_global_deadlock_detector配置参数设置为true来启用全局死锁检测器。 有关全局死锁检测器的信息,请参见Greenplum数据库管理员指南中的全局死锁检测器

有关每种行级锁定模式的更多信息,请参见PostgreSQL文档中的显式锁定

为防止该操作等待其他事务提交,请使用NOWAIT选项。 使用NOWAIT,如果无法立即锁定选定的行,该语句将报告错误,而不是等待。 请注意,NOWAIT仅适用于行级锁 - 所需的ROW SHARE表级锁仍以常规方式获取。 如果需要不等待就获取表级锁,则可以先将LOCK与NOWAIT选项一起使用。

如果在锁定子句中命名了特定的表,则仅锁定来自那些表的行;其他使用SELECT的表则像往常一样简单地读取。 没有表列表的锁定子句会影响该语句中使用的所有表。 如果将锁定子句应用于视图或子查询,则它将影响视图或子查询中使用的所有表。 但是,这些子句不适用于主查询引用的WITH查询。 如果希望在WITH查询中发生行锁定,请在WITH查询中指定一个锁定子句。

如果有必要为不同的表指定不同的锁定行为,则可以编写多个锁定子句。 如果同一表被两个以上的锁定子句提及(或隐式影响),则将其视为仅由最强的一个子表指定。 同样,如果在影响该表的任何子句中指定了表,则该表将作为NOWAIT处理。

在无法用单独的表行清楚地标识返回的行的上下文中,不能使用锁定子句;例如,它们不能与聚合一起使用。

当锁定子句出现在SELECT查询的顶层时,被锁定的行与查询返回的行完全相同。 对于连接查询,锁定的行是那些促成返回连接行的行。 此外,查询快照中满足查询条件的行将被锁定,尽管这些行在快照后对其进行更新并且不再满足查询条件不会返回。 如果使用LIMIT,则一旦返回了足够的行以满足限制,锁定就会停止(但请注意,被OFFSET跳过的行将被锁定)。 同样,如果在游标的查询中使用锁定子句,则仅锁定实际被游标读取或跳过的行。

当sub-SELECT中出现locking子句时,被锁定的行就是该子查询返回给外部查询的行。 这可能涉及的行数少于单独检查子查询所建议的行数,因为外部查询的条件可用于优化子查询的执行。 例如,

  1. SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;

将仅锁定col1 = 5的行,即使该条件在文本上不在子查询中。

SELECT命令可能以READ COMMITTED事务隔离级别运行,并且使用ORDER BY和锁定子句可以使行无序返回。 这是因为ORDER BY首先被应用。 该命令对结果进行排序,但随后可能会阻止尝试获得对一个或多个行的锁定。 一旦SELECT解除阻塞,某些排序列值可能已被修改,从而导致这些行看起来是乱序的(尽管就原始列值而言,它们是有序的)。 例如,可以通过在子查询中放置FOR UPDATE/SHARE子句来解决此问题。

  1. SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;

请注意,这将导致锁定mytable的所有行,而顶层的FOR UPDATE将仅锁定实际返回的行。 这可能会导致明显的性能差异,特别是如果将ORDER BY与LIMIT或其他限制结合使用。 因此,仅当期望并发更新排序列并且需要严格排序的结果时才建议使用此技术。

在REPEATABLE READ或SERIALIZABLE事务隔离级别, 这将导致序列化失败(SQLSTATE为40001),因此在这些隔离级别下,不可能乱序接收行。

TABLE命令

命令

  1. TABLE name

完全等同于

  1. SELECT * FROM name

在部分复杂查询中,它可用作顶级命令或节省空间的语法变体。

示例

连接表films与表distributors:

  1. SELECT f.title, f.did, d.name, f.date_prod, f.kind FROM
  2. distributors d, films f WHERE f.did = d.did

将表films的length列求和并将结果按kind分组:

  1. SELECT kind, sum(length) AS total FROM films GROUP BY kind;

将表films的length列求和并将结果按kind分组并显示总和小于5小时的组:

  1. SELECT kind, sum(length) AS total FROM films GROUP BY kind
  2. HAVING sum(length) < interval '5 hours';

计算电影kind和distributor的所有销售部分和与总和。

  1. SELECT kind, distributor, sum(prc*qty) FROM sales
  2. GROUP BY ROLLUP(kind, distributor)
  3. ORDER BY 1,2,3;

根据总销量计算电影发行商的排名:

  1. SELECT distributor, sum(prc*qty),
  2. rank() OVER (ORDER BY sum(prc*qty) DESC)
  3. FROM sale
  4. GROUP BY distributor ORDER BY 2 DESC;

以下两个示例是根据第二列(name)的内容对单个结果进行排序的相同方法:

  1. SELECT * FROM distributors ORDER BY name;
  2. SELECT * FROM distributors ORDER BY 2;

下一个示例说明如何获取表distributors和actors的并集,将结果限制为每个表中以字母W开头的行。 只需要不同的行,因此关键字ALL被省略:

  1. SELECT distributors.name FROM distributors WHERE
  2. distributors.name LIKE 'W%' UNION SELECT actors.name FROM
  3. actors WHERE actors.name LIKE 'W%';

此示例说明如何在FROM子句中使用函数,无论是否包含列定义列表:

  1. CREATE FUNCTION distributors(int) RETURNS SETOF distributors
  2. AS $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE
  3. SQL;
  4. SELECT * FROM distributors(111);
  5. CREATE FUNCTION distributors_2(int) RETURNS SETOF record AS
  6. $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE
  7. SQL;
  8. SELECT * FROM distributors_2(111) AS (dist_id int, dist_name
  9. text);

此示例使用一个简单的WITH子句:

  1. WITH test AS (
  2. SELECT random() as x FROM generate_series(1, 3)
  3. )
  4. SELECT * FROM test
  5. UNION ALL
  6. SELECT * FROM test;

本示例使用WITH子句仅显示最高销售区域中的每产品销售总额。

  1. WITH regional_sales AS
  2. SELECT region, SUM(amount) AS total_sales
  3. FROM orders
  4. GROUP BY region
  5. ), top_regions AS (
  6. SELECT region
  7. FROM regional_sales
  8. WHERE total_sales > (SELECT SUM(total_sales) FROM
  9. regional_sales)
  10. )
  11. SELECT region, product, SUM(quantity) AS product_units,
  12. SUM(amount) AS product_sales
  13. FROM orders
  14. WHERE region IN (SELECT region FROM top_regions)
  15. GROUP BY region, product;

该示例可能编写不包含WITH子句,但需要两级嵌套的sub-SELECT语句。

本示例使用WITH RECURSIVE子句从仅显示直接下属的表中查找员工Mary的所有下属(直接或间接)及其间接级别:

  1. WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS (
  2. SELECT 1, employee_name, manager_name
  3. FROM employee
  4. WHERE manager_name = 'Mary'
  5. UNION ALL
  6. SELECT er.distance + 1, e.employee_name, e.manager_name
  7. FROM employee_recursive er, employee e
  8. WHERE er.employee_name = e.manager_name
  9. )
  10. SELECT distance, employee_name FROM employee_recursive;

递归查询的典型形式:初始条件,后跟UNION [ALL],然后是查询的递归部分。 确保查询的递归部分最终不会返回任何元组,否则查询将无限期地循环。 有关更多示例,请参见WITH查询(公用表表达式)

兼容性

SELECT语句与SQL标准兼容,但是有一些扩展和某些缺少的功能。

省略FROM子句

Greenplum数据库允许省略FROM子句。 它可以直接用于计算简单表达式的结果。例如:

  1. SELECT 2+2;

其他一些SQL数据库无法做到这一点,除非引入一个虚拟的单行表来执行SELECT。

请注意,如果未指定FROM子句,则查询无法引用任何数据库表。 例如,以下查询无效:

  1. SELECT distributors.* WHERE distributors.name = 'Westward';

在较早的版本中,将服务器配置参数add_missing_from设置为true允许Greenplum数据库为查询所引用的每个表向查询的FROM子句添加隐式条目。 这个不再允许。

省略AS关键字

在SQL标准中,只要新列名是有效的列名(即与任何保留关键字不同),就可以在输出列名之前省略可选关键字AS。 Greenplum数据库的限制更为严格:如果新列名完全匹配任何关键字(保留与否),则要求使用AS。 推荐的做法是使用AS或双引号输出列名,以防止与将来添加关键字的任何可能的冲突。

在FROM项中,SQL标准和Greenplum数据库都允许在作为未保留关键字的别名之前省略AS。 但是由于语法上的歧义,这对于输出列名称是不切实际的。

ONLY和Inheritance

使用ONLY时,SQL标准要求在表名前后加上括号,例如:

  1. SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...

Greenplum数据库认为这些括号是可选的。

Greenplum数据库允许编写尾随*来明确指定包括子表的non-ONLY行为。 该标准不允许这样做。

(这些要点同样适用于所有支持ONLY选项的SQL命令。)

Namespace可以用于GROUP BY和ORDER BY

在SQL-92标准中,ORDER BY子句只能使用输出列名称或序号,而GROUP BY子句只能使用基于输入列名称的表达式。 Greenplum数据库扩展了这些子句中的每一个,以允许其他选择(但是如果有歧义,它将使用标准的解释)。 Greenplum数据库还允许两个子句都指定任意表达式。 请注意,出现在表达式中的名称始终被视为输入列名称,而不是输出列名称。

SQL:1999及更高版本使用的定义略有不同,但并不完全与SQL-92向上兼容。 但是,在大多数情况下,Greenplum数据库以与SQL:1999相同的方式解释ORDER BY或GROUP BY表达式。

函数依赖

仅当表的主键包含在GROUP BY列表中时,Greenplum数据库才能识别函数依赖(允许从GROUP BY省略列)。 SQL标准指定了应识别的其他条件。

LIMIT和OFFSET

子句LIMIT和OFFSET是Greenplum数据库特定的语法,也由MySQL使用。 如上所述,SQL:2008标准引入了子句OFFSET .. FETCH {FIRST | NEXT} …来实现相同的功能。 IBM DB2也使用此语法。 (Oracle应用程序经常使用一种变通办法来实现这些子句的效果,该变通办法涉及自动生成的rownum列,Greenplum数据库中不提供该列。)

FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE和FOR KEY SHARE

尽管FOR UPDATE出现在SQL标准中,但该标准仅允许将它作为DECLARE CURSOR的选项。 Greenplum数据库允许在任何SELECT查询以及sub-SELECT中使用它,但这是一个扩展。 FOR NO KEY UPDATE,FOR SHARE和FOR KEY SHARE变体以及NOWAIT选项未出现在标准中。

WITH中的数据修改语句

Greenplum数据库允许将INSERT,UPDATE和DELETE用作WITH查询。 在SQL标准中不允许。

非标准子句

在SQL标准中未定义DISTINCT ON子句。

STABLE和VOLATILE函数的限制

为防止数据在Greenplum数据库中的各个segment之间变得不同步, 如果分类为STABLE或VOLATILE的任何函数包含SQL或以任何方式修改了数据库,则不能在segment数据库级别执行该函数。 有关更多信息,请参见CREATE FUNCTION

另见

EXPLAIN

Parent topic: SQL Command Reference