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] }

符号

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 列表中的项目也可以采用 表达式.* 的形式。这将为 表达式 的每列或顶级字段生成一个输出列。该表达式必须是表别名。

以下查询为名为 ggroceries 表中的每列生成一个输出列。

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 不能返回以下类型的列

SELECT ALL

SELECT ALL 语句返回所有行,包括重复行。SELECT ALLSELECT 的默认行为。

别名

请参阅 别名 以了解 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 子句中的任何地方引用这些名称。在下面的示例中,subQ1subQ2with_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 语法在子查询中有效。

子查询有两种类型

请注意,两种类型的子查询都必须用圆括号括起来。

示例

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_typeONUSING 子句(“联接条件”)指定如何组合和丢弃来自两个 from_item 的行以形成单个源。

所有 JOIN 子句都需要一个 join_type

JOIN 子句需要一个联接条件,除非以下条件之一为真

[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);

此语句返回 RosterPlayerStatsRoster.LastNamePlayerStats.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 子句可以引用通过 `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)

以下规则适用

示例

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` 列表中可以有多个具有相同别名的列。

在所有其他情况下,没有隐式别名,因此该列是匿名的,不能按名称引用。该列中的数据仍将返回,并且显示的查询结果可能具有该列的生成标签,但该标签不能像别名那样使用。

在 `FROM` 子句中,`from_item` 不需要有别名。以下规则适用

如果存在没有显式别名的表达式,Beam 会在这些情况下分配隐式别名

表子查询没有隐式别名。

FROM UNNEST(x) 没有隐式别名。

本页的部分内容是根据 工作 进行修改的,该工作由 Google 创建和 共享,并根据 Creative Commons 3.0 署名许可 中描述的条款使用。