Beam Calcite SQL 查询语法
查询语句扫描一个或多个表或表达式,并返回计算结果行。
一般来说,查询的语义是标准的。请参阅以下部分了解支持 Beam 统一批处理/流模型的扩展
Beam SQL 的主要功能是 SELECT
语句。这就是您查询和联接数据的方式。支持的操作是 Apache Calcite SQL 的一个子集。
SQL 语法
query_statement:
[ WITH with_query_name AS ( query_expr ) [, ...] ]
query_expr
query_expr:
{ select | ( query_expr ) | query_expr set_op query_expr }
[ LIMIT count [ OFFSET skip_rows ] ]
select:
SELECT [{ ALL | DISTINCT }]
{ [ expression. ]* [ EXCEPT ( column_name [, ...] ) ]
[ REPLACE ( expression [ AS ] column_name [, ...] ) ]
| expression [ [ AS ] alias ] } [, ...]
[ FROM from_item [, ...] ]
[ WHERE bool_expression ]
[ GROUP BY { expression [, ...] } ]
[ HAVING bool_expression ]
set_op:
UNION { ALL | DISTINCT } | INTERSECT DISTINCT | EXCEPT DISTINCT
from_item: {
table_name [ [ AS ] alias ] |
join |
( query_expr ) [ [ AS ] alias ]
with_query_name [ [ AS ] alias ]
}
join:
from_item [ join_type ] JOIN from_item
[ { ON bool_expression | USING ( join_column [, ...] ) } ]
join_type:
{ INNER | CROSS | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }
符号
- 方括号“[ ]”表示可选子句。
- 圆括号“( )”表示字面圆括号。
- 竖线“|”表示逻辑 OR。
- 花括号“{ }”括起一组选项。
- 方括号中的逗号加省略号“[, … ]”表示前面的项目可以在逗号分隔列表中重复。
SELECT 列表
语法
SELECT [{ ALL | DISTINCT }]
{ [ expression. ]*
| expression [ [ AS ] alias ] } [, ...]
SELECT
列表定义查询将返回的列。SELECT
列表中的表达式可以引用其对应 FROM
子句中任何 from_item
中的列。
SELECT
列表中的每个项目都是以下之一
- *
表达式
表达式.*
SELECT *
SELECT *
,通常称为选择星号,为执行完整查询后可见的每列生成一个输出列。
SELECT * FROM (SELECT 'apple' AS fruit, 'carrot' AS vegetable);
+-------+-----------+
| fruit | vegetable |
+-------+-----------+
| apple | carrot |
+-------+-----------+
SELECT 表达式
SELECT
列表中的项目可以是表达式。这些表达式计算为单个值,并生成一个输出列,以及一个可选的显式别名
。
如果表达式没有显式别名,则根据 隐式别名 的规则接收隐式别名(如果可能)。否则,该列是匿名的,您不能在查询中的其他地方通过名称引用它。
SELECT 表达式.*
SELECT
列表中的项目也可以采用 表达式.*
的形式。这将为 表达式
的每列或顶级字段生成一个输出列。该表达式必须是表别名。
以下查询为名为 g
的 groceries
表中的每列生成一个输出列。
WITH groceries AS
(SELECT 'milk' AS dairy,
'eggs' AS protein,
'bread' AS grain)
SELECT g.*
FROM groceries AS g;
+-------+---------+-------+
| dairy | protein | grain |
+-------+---------+-------+
| milk | eggs | bread |
+-------+---------+-------+
SELECT 修饰符
您可以修改从 SELECT
查询返回的结果,如下所示。
SELECT DISTINCT
SELECT DISTINCT
语句将丢弃重复行,只返回剩余行。SELECT DISTINCT
不能返回以下类型的列
- STRUCT
- ARRAY
SELECT ALL
SELECT ALL
语句返回所有行,包括重复行。SELECT ALL
是 SELECT
的默认行为。
别名
请参阅 别名 以了解 SELECT
列表别名的语法和可见性信息。
FROM 子句
FROM
子句指示要从中检索行的表,并指定如何将这些行联接在一起以生成单个行流,以便在查询的其余部分进行处理。
语法
from_item: {
table_name [ [ AS ] alias ] |
join |
( query_expr ) [ [ AS ] alias ] |
with_query_name [ [ AS ] alias ]
}
表名
现有表的名称(可选地限定)。
SELECT * FROM Roster;
SELECT * FROM beam.Roster;
联接
选择
( select ) [ [ AS ] 别名 ]
是一个表 子查询。
with_query_name
WITH
子句(请参阅 WITH 子句)中的查询名称就像临时表的名称,您可以在 FROM
子句中的任何地方引用这些名称。在下面的示例中,subQ1
和 subQ2
是 with_query_names
。
示例
WITH
subQ1 AS (SELECT * FROM Roster WHERE SchoolID = 52),
subQ2 AS (SELECT SchoolID FROM subQ1)
SELECT DISTINCT * FROM subQ2;
WITH
子句会隐藏查询持续时间内具有相同名称的任何永久表,除非您限定表名,例如 beam.Roster
。
子查询
子查询是出现在另一个语句内部的查询,并写在圆括号内。这些也被称为“子 SELECT”或“嵌套 SELECT”。完整的 SELECT
语法在子查询中有效。
子查询有两种类型
- 表达式子查询,您可以在查询中表达式有效的任何地方使用它们。表达式子查询返回单个值。
- 表子查询,您只能在
FROM
子句中使用它们。外部查询将子查询的结果视为表。
请注意,两种类型的子查询都必须用圆括号括起来。
示例
SELECT AVG ( PointsScored )
FROM
( SELECT PointsScored
FROM Stats
WHERE SchoolID = 77 )
表子查询可以选择有一个别名。
示例
SELECT r.LastName
FROM
( SELECT * FROM Roster) AS r;
别名
请参阅 别名 以了解 FROM
子句别名的语法和可见性信息。
联接类型
另请参阅 联接。
语法
join:
from_item [ join_type ] JOIN from_item
[ ON bool_expression | USING ( join_column [, ...] ) ]
join_type:
{ INNER | CROSS | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }
JOIN
子句合并两个 from_item
,以便 SELECT
子句可以将它们查询为一个源。join_type
和 ON
或 USING
子句(“联接条件”)指定如何组合和丢弃来自两个 from_item
的行以形成单个源。
所有 JOIN
子句都需要一个 join_type
。
JOIN
子句需要一个联接条件,除非以下条件之一为真
join_type
是CROSS
。- 一个或两个
from_item
不是表,例如array_path
或field_path
。
[INNER] JOIN
INNER JOIN
或简称为 JOIN
,实际上计算两个 from_item
的笛卡尔积,并丢弃所有不满足联接条件的行。“实际上”意味着可以实现 INNER JOIN
而不必实际计算笛卡尔积。
CROSS JOIN
CROSS JOIN
通常尚不支持。
FULL [OUTER] JOIN
FULL OUTER JOIN
(或简称为 FULL JOIN
)返回两个 from_item
中所有满足联接条件的行中的所有字段。
FULL
表示返回两个 from_item
中的所有行,即使它们不满足联接条件。对于流式作业,所有不迟于默认触发器且属于相同窗口的(如果应用了非全局窗口)行。
OUTER
表示如果来自一个 from_item
的给定行没有与另一个 from_item
中的任何行联接,则该行将返回,其来自另一个 from_item
的所有列都为 NULL。
另请参阅 联接。
LEFT [OUTER] JOIN
LEFT OUTER JOIN
(或简称为 LEFT JOIN
)的两个 from_item
的结果始终保留 JOIN
子句中左侧 from_item
的所有行,即使右侧 from_item
中没有行满足联接谓词。
LEFT
表示返回左侧 from_item
中的所有行;如果左侧 from_item
中的给定行没有与右侧 from_item
中的任何行联接,则该行将返回,其来自右侧 from_item
的所有列都为 NULL。右侧 from_item
中没有与左侧 from_item
中的任何行联接的行将被丢弃。
RIGHT [OUTER] JOIN
RIGHT OUTER JOIN
(或简称为 RIGHT JOIN
)的结果与 LEFT OUTER JOIN
类似且对称。
ON 子句
ON
子句包含 bool_expression
。如果 bool_expression
返回 TRUE,则组合行(联接两行的结果)满足联接条件。
示例
SELECT * FROM Roster INNER JOIN PlayerStats
ON Roster.LastName = PlayerStats.LastName;
USING 子句
USING
子句需要一个 column_list
,其中包含一个或多个出现在两个输入表中的列。它对该列执行相等性比较,如果相等性比较返回 TRUE,则行满足联接条件。
在大多数情况下,使用 USING
关键字的语句等效于使用 ON
关键字。例如,语句
SELECT FirstName
FROM Roster INNER JOIN PlayerStats
USING (LastName);
等效于
SELECT FirstName
FROM Roster INNER JOIN PlayerStats
ON Roster.LastName = PlayerStats.LastName;
当您使用 SELECT *
时,使用 USING
的查询的结果确实与使用 ON
的查询不同。为了说明这一点,请考虑以下查询
SELECT * FROM Roster INNER JOIN PlayerStats
USING (LastName);
此语句返回 Roster
和 PlayerStats
中 Roster.LastName
与 PlayerStats.LastName
相同的行。结果包含一个 LastName
列。
相比之下,请考虑以下查询
SELECT * FROM Roster INNER JOIN PlayerStats
ON Roster.LastName = PlayerStats.LastName;
该语句返回来自 `Roster` 和 `PlayerStats` 的行,其中 `Roster.LastName` 与 `PlayerStats.LastName` 相同。结果包含两个 `LastName` 列;一个来自 `Roster`,另一个来自 `PlayerStats`。
联接序列
FROM
子句可以包含多个连续的 `JOIN` 子句。
示例
SELECT * FROM a LEFT JOIN b ON TRUE LEFT JOIN c ON TRUE;
其中 `a`、`b` 和 `c` 是任何 `from_item`。JOIN 从左到右绑定,但您可以插入括号以按不同的顺序对它们进行分组。
WHERE 子句
语法
WHERE bool_expression
WHERE
子句通过对每一行进行 `bool_expression` 评估来过滤行,并丢弃所有未返回 TRUE 的行(即返回 FALSE 或 NULL 的行)。
示例
SELECT * FROM Roster
WHERE SchoolID = 52;
bool_expression
可以包含多个子条件。
示例
SELECT * FROM Roster
WHERE LastName LIKE 'Mc%' OR LastName LIKE 'Mac%';
您不能在 `WHERE` 子句中引用 `SELECT` 列表中的列别名。
INNER JOIN
中的表达式在 `WHERE` 子句中具有等效表达式。例如,使用 `INNER` `JOIN` 和 `ON` 的查询具有使用 `CROSS JOIN` 和 `WHERE` 的等效表达式。
示例 - 此查询
SELECT * FROM Roster INNER JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;
等效于
SELECT * FROM Roster CROSS JOIN TeamMascot
WHERE Roster.SchoolID = TeamMascot.SchoolID;
GROUP BY 子句
另请参阅 窗口化和触发
语法
GROUP BY { expression [, ...] }
GROUP BY
子句将表中具有 `GROUP BY` 子句中 `expression` 非唯一值的行分组在一起。对于源表中具有 `expression` 非唯一值的多个行,`GROUP BY` 子句生成一个组合行。`GROUP BY` 通常用于 `SELECT` 列表中存在聚合函数时,或者用于消除输出中的冗余。
示例
SELECT SUM(PointsScored), LastName
FROM PlayerStats
GROUP BY LastName;
HAVING 子句
语法
HAVING bool_expression
HAVING
子句类似于 `WHERE` 子句:它过滤掉在针对 `bool_expression` 评估时不返回 TRUE 的行。
与 `WHERE` 子句一样,`bool_expression` 可以是任何返回布尔值的表达式,并且可以包含多个子条件。
HAVING
子句与 `WHERE` 子句的不同之处在于
HAVING
子句要求查询中存在 `GROUP BY` 或聚合。HAVING
子句发生在 `GROUP BY` 和聚合之后。这意味着 `HAVING` 子句针对结果集中每个聚合行进行评估。这与 `WHERE` 子句不同,`WHERE` 子句是在 `GROUP BY` 和聚合之前进行评估的。
HAVING
子句可以引用通过 `FROM` 子句可用的列,以及 `SELECT` 列表别名。在 `HAVING` 子句中引用的表达式必须出现在 `GROUP BY` 子句中,或者它们必须是聚合函数的结果
SELECT LastName
FROM Roster
GROUP BY LastName
HAVING SUM(PointsScored) > 15;
集合运算符
语法
UNION { ALL | DISTINCT } | INTERSECT DISTINCT | EXCEPT DISTINCT
集合运算符将来自两个或多个输入查询的结果组合到一个结果集中。您必须指定 `ALL` 或 `DISTINCT`;如果指定 `ALL`,则保留所有行。如果指定 `DISTINCT`,则会丢弃重复行。
如果给定行 R 在第一个输入查询中正好出现 m 次,在第二个输入查询中正好出现 n 次 (m >= 0, n >= 0)
- 对于 `UNION ALL`,R 在结果中正好出现 m + n 次。
- 对于 `UNION DISTINCT`,`DISTINCT` 在计算 `UNION` 之后计算,因此 R 只出现一次。
- 对于 `INTERSECT DISTINCT`,`DISTINCT` 在计算上述结果之后计算。
- 对于 `EXCEPT DISTINCT`,如果 m > 0 且 n = 0,则行 R 在输出中出现一次。
- 如果有两个以上的输入查询,则上述操作会泛化,并且输出与从左到右增量组合输入时相同。
以下规则适用
- 对于除 `UNION ALL` 之外的集合运算,所有列类型都必须支持相等比较。
- 运算符两侧的输入查询必须返回相同数量的列。
- 运算符根据列在各自 `SELECT` 列表中的位置,对每个输入查询返回的列进行配对。也就是说,第一个输入查询中的第一列与第二个输入查询中的第一列配对。
- 结果集始终使用第一个输入查询中的列名。
- 结果集始终使用对应列中输入类型的超类型,因此配对列也必须具有相同的类型或公共超类型。
- 您必须使用括号来分隔不同的集合运算;为此目的,集合运算(如 `UNION ALL` 和 `UNION DISTINCT`)是不同的。如果语句只重复相同的集合运算,则不需要括号。
示例
query1 UNION ALL (query2 UNION DISTINCT query3)
query1 UNION ALL query2 UNION ALL query3
无效
query1 UNION ALL query2 UNION DISTINCT query3
query1 UNION ALL query2 INTERSECT ALL query3; // INVALID.
UNION
UNION
运算符通过将来自每个查询结果集的列配对并将它们垂直连接起来,来组合两个或多个输入查询的结果集。
INTERSECT
INTERSECT
运算符返回在左输入查询和右输入查询的结果集中都找到的行。与 `EXCEPT` 不同,输入查询的位置(在 `INTERSECT` 运算符的左侧还是右侧)无关紧要。
EXCEPT
EXCEPT
运算符返回来自左输入查询且未出现在右输入查询中的行。
LIMIT 子句和 OFFSET 子句
语法
LIMIT count [ OFFSET skip_rows ]
LIMIT
指定类型为 INTEGER 的非负 `count`,并且最多返回 `count` 行。LIMIT
`0` 返回 0 行。如果有集合运算,则在评估集合运算之后应用 `LIMIT`。
OFFSET
指定类型为 INTEGER 的非负 `skip_rows`,并且只考虑表中该偏移量后的行。
这些子句只接受文字或参数值。
由 `LIMIT` 和 `OFFSET` 返回的行是未指定的。
WITH 子句
WITH
子句包含一个或多个命名子查询,这些子查询在每次后续 `SELECT` 语句引用它们时都会执行。任何子句或子查询都可以引用您在 `WITH` 子句中定义的子查询。这包括集合运算符(如 `UNION`)两侧的任何 `SELECT` 语句。
示例
WITH subQ1 AS (SELECT SchoolID FROM Roster),
subQ2 AS (SELECT OpponentID FROM PlayerStats)
SELECT * FROM subQ1
UNION ALL
SELECT * FROM subQ2;
别名
别名是在查询中存在的表、列或表达式赋予的临时名称。您可以在 `SELECT` 列表或 `FROM` 子句中引入显式别名,或者 Beam 会为某些表达式推断隐式别名。既没有显式别名也没有隐式别名的表达式是匿名的,并且查询不能按名称引用它们。
显式别名语法
您可以在 `FROM` 子句或 `SELECT` 列表中引入显式别名。
在 `FROM` 子句中,您可以使用 `[AS] alias` 为任何项(包括表、数组、子查询和 `UNNEST` 子句)引入显式别名。`AS` 关键字是可选的。
示例
SELECT s.FirstName, s2.SongName
FROM Singers AS s JOIN Songs AS s2 ON s.SingerID = s2.SingerID;
您可以使用 `[AS] alias` 为 `SELECT` 列表中的任何表达式引入显式别名。`AS` 关键字是可选的。
示例
SELECT s.FirstName AS name, LOWER(s.FirstName) AS lname
FROM Singers s;
显式别名可见性
在您在查询中引入显式别名后,在查询中的其他位置引用该别名会有限制。这些别名可见性的限制是 Beam 命名范围规则的结果。
FROM 子句别名
Beam 从左到右处理 `FROM` 子句中的别名,并且别名仅对后续 `JOIN` 子句可见。
模糊别名
如果名称不明确,这意味着它可以解析为多个唯一对象,Beam 会提供错误。
示例
此查询包含在表之间冲突的列名,因为 `Singers` 和 `Songs` 都具有名为 `SingerID` 的列
SELECT SingerID
FROM Singers, Songs;
隐式别名
在 `SELECT` 列表中,如果存在没有显式别名的表达式,Beam 会根据以下规则分配隐式别名。`SELECT` 列表中可以有多个具有相同别名的列。
- 对于标识符,别名是标识符。例如,`SELECT abc` 意味着 `AS abc`。
- 对于路径表达式,别名是路径中的最后一个标识符。例如,`SELECT abc.def.ghi` 意味着 `AS ghi`。
- 对于使用“点”成员字段访问运算符的字段访问,别名是字段名。例如,`SELECT (struct_function()).fname` 意味着 `AS fname`。
在所有其他情况下,没有隐式别名,因此该列是匿名的,不能按名称引用。该列中的数据仍将返回,并且显示的查询结果可能具有该列的生成标签,但该标签不能像别名那样使用。
在 `FROM` 子句中,`from_item` 不需要有别名。以下规则适用
如果存在没有显式别名的表达式,Beam 会在这些情况下分配隐式别名
- 对于标识符,别名是标识符。例如,`FROM abc` 意味着 `AS abc`。
- 对于路径表达式,别名是路径中的最后一个标识符。例如,`FROM abc.def.ghi` 意味着 `AS ghi`
表子查询没有隐式别名。
FROM UNNEST(x)
没有隐式别名。
本页的部分内容是根据 工作 进行修改的,该工作由 Google 创建和 共享,并根据 Creative Commons 3.0 署名许可 中描述的条款使用。