PostgreSQL 18 中文参考文档(未翻译部分保留英文)🌐 切换到英文原版 →

7.2. 表表达式 #

7.2.1. FROM 子句
7.2.2. WHERE 子句
7.2.3. GROUP BY 与 HAVING 子句
7.2.4. GROUPING SETS、CUBE 与 ROLLUP
7.2.5. 窗口函数处理

一个表表达式(table expression)在物理逻辑上用于计算产出一张二维中间表。表表达式以一个 FROM 子句为核心起点,其后可选择性串联附加 WHERE、GROUP BY 与 HAVING 子句。极简的表表达式仅引用磁盘上的单张物理基表,而复杂的表达式则能以多种方式对基表执行水平过滤、垂直投影、多表关联及动态派生转换。

表表达式中可选的 WHERE、GROUP BY 与 HAVING 子句构成了一条顺序执行的数据流水线(pipeline):在 FROM 产出的中间表基础上,依次执行条件过滤、分组聚合与后置筛选。整条流水线最终产出一张虚拟中间表,将其提供给上层的选择列表以计算生成最终的输出行。

7.2.1. FROM 子句 #

FROM 子句根据逗号分隔的表引用列表,计算派生出一张基础中间表:

FROM table_reference [, table_reference [, ...]]

表引用可以是一个具体的物理表名(可带模式前缀),也可以是子查询、JOIN 连接结构或它们的复合嵌套。如果在 FROM 中列出多个表引用,它们在逻辑上执行笛卡尔积交叉连接(Cartesian product)。

当引用的表处于表继承层级结构且属于父表时,查询默认不仅返回该父表本身的行,还会递归包含其全部后代子表中的数据行,除非在表名前显式添加关键字 ONLY 修饰。但无论如何,查询结果仅包含父表中声明的字段列,子表中额外扩展的新列将被忽略。

7.2.1.1. 连接表 #

连接表是根据特定连接类型的匹配规则,从两张(物理或派生)表中计算派生出的复合关系。系统支持交叉连接、内连接以及各类外连接。其通用语法骨架为:

T1 join_type T2 [ join_condition ]

所有类型的连接均支持无限链式串联或嵌套。圆括号可用于显式控制连接执行的时序次序;在缺少括号时,连接默认遵循自左向右的结合规则。

连接类型

交叉连接(Cross Join)
T1 CROSS JOIN T2

计算两表之间的笛卡尔积。若两表行数分别为 N 与 M,则交叉连接生成的中间表包含 N * M 行数据。T1 CROSS JOIN T2 在语义上等价于 T1 INNER JOIN T2 ON TRUE,也等价于 FROM T1, T2。

限定连接(Qualified Joins)
T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON boolean_expression
T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( join_column_list )
T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2

关键字 INNER 与 OUTER 在所有语法形态中均属于可选关键字。INNER 为默认行为;而声明了 LEFT、RIGHT 或 FULL 则自动意味着外连接(Outer Join)。

连接条件主要支持三种表达机制:

  • ON 子句:最通用的布尔条件表达式,形式与 WHERE 相同。

  • USING 子句:以逗号分隔列出两表中同名的关联列进行等值比对,且在输出结果集中自动将同名列合并为单列,消除重复输出。

  • NATURAL 自然连接:自动扫描并选取两表中所有名称相同的列作为隐式等值连接条件,等价于由系统自动补齐 USING 清单。

外连接的核心行为规则如下:

  • LEFT OUTER JOIN(左外连接):首先执行内连接;对于左表中未能与右表产生任何匹配的剩余孤立行,强制将其保留在结果集中,且右表对应的字段全部自动填充为 NULL。

  • RIGHT OUTER JOIN(右外连接):与左外连接对称,保证右表中的每一行至少出现一次,未匹配的左表字段填充为 NULL。

  • FULL OUTER JOIN(全外连接):同时包含内连接匹配行、左表未匹配行(右侧补 NULL)以及右表未匹配行(左侧补 NULL)。

7.2.1.2. 表与列别名 #

可以通过附加 AS 子句为表引用赋予临时别名:

FROM table_reference AS alias

关键字 AS 可以完全省略。一旦为表赋予了别名,在该查询的其余部分(如选择列表或 WHERE 条件中)必须统一使用别名引用该表,原始表名将被别名屏蔽隐藏。

别名机制还支持同时对数据表输出的各列进行显式就地重命名:

FROM mytable AS t (col1, col2, col3)

7.2.1.3. 子查询 #

在 FROM 子句中可以嵌套书写另一个独立的子查询,该子查询必须使用圆括号包裹,且必须为其显式指定表别名:

FROM (SELECT * FROM table1) AS alias_name

7.2.1.4. 表函数 #

表函数(Table Functions)是指那些计算并返回复合结果集(行集合)的特殊函数。表函数可以直接出现在 FROM 子句中充当数据源。典型代表如数组展开函数 unnest 或序列生成函数 generate_series:

SELECT * FROM unnest(ARRAY['a', 'b', 'c']);
SELECT * FROM generate_series(1, 5);

通过引入关键字 LATERAL,允许置于 FROM 子句较后位置的子查询或表函数,反向引用出现在同一 FROM 列表中较早位置的其他表中的字段列(相关子查询):

SELECT m.name, d.*
FROM manufacturers m,
     LATERAL get_product_names(m.id) d;

7.2.2. WHERE 子句 #

WHERE 子句的语法为:

WHERE search_condition

其中 search_condition 是任何返回布尔值(boolean)的标量值表达式。 流水线将 FROM 生成的每一行中间数据代入该表达式求值,只有令表达式严格为真(True)的行才能顺利穿透进入下一阶段;凡是求值为假(False)或未知(NULL)的行将被直接丢弃淘汰。

7.2.3. GROUP BY 与 HAVING 子句 #

在通过 WHERE 过滤之后,可以通过 GROUP BY 子句将剩下的数据行划分为独立的分组,并在各组之上执行聚合计算。

GROUP BY grouping_element [, ...]

当使用 GROUP BY 时,顶层选择列表中引用的字段必须满足:要么该字段直接包含在 GROUP BY 分组键表达式列表中,要么该字段必须包裹在聚合函数内部。这在逻辑上是严格自洽的,因为脱离聚合函数去引用非分组字段,在单行汇总结果中将无法确定应该挑选哪个具体值。

HAVING 子句专门用于在分组聚合完成之后,对汇总结果行进行条件过滤:

HAVING boolean_expression

牢记 WHERE 与 HAVING 的核心区别:WHERE 作用于分组之前的原始行(严禁使用聚合函数);而 HAVING 作用于分组聚合之后的汇总行(通常包含聚合函数)。

7.2.4. GROUPING SETS、CUBE 与 ROLLUP #

在商业智能分析与多维报表统计中,常常需要在单次查询中同时计算多种不同维度的汇总统计(例如同时输出按部门聚合、按岗位聚合以及全公司总聚合)。标准 SQL 提供了强大的高级分组扩展:

  • GROUPING SETS:显式指定需要计算的多套分组维度列表。

  • ROLLUP:生成具备层级递进从属关系的阶梯式聚合(例如年、月、日逐级上卷汇总)。

  • CUBE:生成指定所有分组维度维度的全排列笛卡尔组合聚合(即多维立方体全量交叉汇总)。

7.2.5. 窗口函数处理 #

如果查询中包含了窗口函数调用(参见 Section 4.2.8 与 Section 3.5),这些计算在流水线执行时序上严格发生于所有常规的连接、WHERE 过滤、GROUP BY 分组聚合以及 HAVING 计算彻底完成之后。这意味着窗口函数处理的是最终已经定型、筛选完毕的有效数据集合。