一个表表达式(table expression)在物理逻辑上用于计算产出一张二维中间表。表表达式以一个 FROM 子句为核心起点,其后可选择性串联附加 WHERE、GROUP BY 与 HAVING 子句。极简的表表达式仅引用磁盘上的单张物理基表,而复杂的表达式则能以多种方式对基表执行水平过滤、垂直投影、多表关联及动态派生转换。
表表达式中可选的 WHERE、GROUP BY 与 HAVING 子句构成了一条顺序执行的数据流水线(pipeline):在 FROM 产出的中间表基础上,依次执行条件过滤、分组聚合与后置筛选。整条流水线最终产出一张虚拟中间表,将其提供给上层的选择列表以计算生成最终的输出行。
FROM 子句 #
FROM 子句根据逗号分隔的表引用列表,计算派生出一张基础中间表:
FROMtable_reference[,table_reference[, ...]]
表引用可以是一个具体的物理表名(可带模式前缀),也可以是子查询、JOIN 连接结构或它们的复合嵌套。如果在 FROM 中列出多个表引用,它们在逻辑上执行笛卡尔积交叉连接(Cartesian product)。
当引用的表处于表继承层级结构且属于父表时,查询默认不仅返回该父表本身的行,还会递归包含其全部后代子表中的数据行,除非在表名前显式添加关键字 ONLY 修饰。但无论如何,查询结果仅包含父表中声明的字段列,子表中额外扩展的新列将被忽略。
连接表是根据特定连接类型的匹配规则,从两张(物理或派生)表中计算派生出的复合关系。系统支持交叉连接、内连接以及各类外连接。其通用语法骨架为:
T1join_typeT2[join_condition]
所有类型的连接均支持无限链式串联或嵌套。圆括号可用于显式控制连接执行的时序次序;在缺少括号时,连接默认遵循自左向右的结合规则。
连接类型
T1CROSS JOINT2
计算两表之间的笛卡尔积。若两表行数分别为 N 与 M,则交叉连接生成的中间表包含 N * M 行数据。T1 CROSS JOIN T2 在语义上等价于 T1 INNER JOIN T2 ON TRUE,也等价于 FROM T1, T2。
T1{ [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOINT2ONboolean_expressionT1{ [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOINT2USING (join_column_list)T1NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOINT2
关键字 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)。
可以通过附加 AS 子句为表引用赋予临时别名:
FROM table_reference AS alias
关键字 AS 可以完全省略。一旦为表赋予了别名,在该查询的其余部分(如选择列表或 WHERE 条件中)必须统一使用别名引用该表,原始表名将被别名屏蔽隐藏。
别名机制还支持同时对数据表输出的各列进行显式就地重命名:
FROM mytable AS t (col1, col2, col3)
在 FROM 子句中可以嵌套书写另一个独立的子查询,该子查询必须使用圆括号包裹,且必须为其显式指定表别名:
FROM (SELECT * FROM table1) AS alias_name
表函数(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;
WHERE 子句 #
WHERE 子句的语法为:
WHERE search_condition
其中 search_condition 是任何返回布尔值(boolean)的标量值表达式。
流水线将 FROM 生成的每一行中间数据代入该表达式求值,只有令表达式严格为真(True)的行才能顺利穿透进入下一阶段;凡是求值为假(False)或未知(NULL)的行将被直接丢弃淘汰。
GROUP BY 与 HAVING 子句 #
在通过 WHERE 过滤之后,可以通过 GROUP BY 子句将剩下的数据行划分为独立的分组,并在各组之上执行聚合计算。
GROUP BY grouping_element [, ...]
当使用 GROUP BY 时,顶层选择列表中引用的字段必须满足:要么该字段直接包含在 GROUP BY 分组键表达式列表中,要么该字段必须包裹在聚合函数内部。这在逻辑上是严格自洽的,因为脱离聚合函数去引用非分组字段,在单行汇总结果中将无法确定应该挑选哪个具体值。
HAVING 子句专门用于在分组聚合完成之后,对汇总结果行进行条件过滤:
HAVING boolean_expression
牢记 WHERE 与 HAVING 的核心区别:WHERE 作用于分组之前的原始行(严禁使用聚合函数);而 HAVING 作用于分组聚合之后的汇总行(通常包含聚合函数)。
GROUPING SETS、CUBE 与 ROLLUP #在商业智能分析与多维报表统计中,常常需要在单次查询中同时计算多种不同维度的汇总统计(例如同时输出按部门聚合、按岗位聚合以及全公司总聚合)。标准 SQL 提供了强大的高级分组扩展:
GROUPING SETS:显式指定需要计算的多套分组维度列表。
ROLLUP:生成具备层级递进从属关系的阶梯式聚合(例如年、月、日逐级上卷汇总)。
CUBE:生成指定所有分组维度维度的全排列笛卡尔组合聚合(即多维立方体全量交叉汇总)。
如果查询中包含了窗口函数调用(参见 Section 4.2.8 与 Section 3.5),这些计算在流水线执行时序上严格发生于所有常规的连接、WHERE 过滤、GROUP BY 分组聚合以及 HAVING 计算彻底完成之后。这意味着窗口函数处理的是最终已经定型、筛选完毕的有效数据集合。