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 expression

SELECT 清單中的項目可以是表達式。這些表達式會評估為單一值,並產生一個輸出資料欄,並具有可選的明確 alias

如果表達式沒有明確的別名,則會根據隱含別名的規則接收隱含的別名(如果可能)。否則,該資料欄是匿名的,您無法在查詢中的其他地方按名稱引用它。

SELECT expression.*

SELECT 清單中的項目也可以採用 expression.* 的形式。這會為 expression 的每個資料欄或最上層欄位產生一個輸出資料欄。該表達式必須是資料表別名。

以下查詢會為資料表 groceries 中每個資料欄產生一個輸出資料欄,別名為 g

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

table_name

現有資料表(可選地限定)的名稱。

SELECT * FROM Roster;
SELECT * FROM beam.Roster;

join

請參閱下方的 JOIN 類型聯結

select

( select ) [ [ AS ] alias ] 是一個資料表子查詢

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 類型

另請參閱 聯結

語法

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

對於兩個 from_item 執行 LEFT OUTER JOIN(或簡稱 LEFT 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);

此語句會傳回 RosterPlayerStats 的資料列,其中 Roster.LastNamePlayerStats.LastName 相同。結果會包含單個 LastName 欄位。

相反地,請考慮以下查詢

SELECT * FROM Roster INNER JOIN PlayerStats
ON Roster.LastName = PlayerStats.LastName;

此語句會傳回 RosterPlayerStats 的資料列,其中 Roster.LastNamePlayerStats.LastName 相同。結果會包含兩個 LastName 欄位;一個來自 Roster,另一個來自 PlayerStats

JOIN 序列

FROM 子句可以依序包含多個 JOIN 子句。

範例

SELECT * FROM a LEFT JOIN b ON TRUE LEFT JOIN c ON TRUE;

其中 abc 是任何 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 JOINON 的查詢具有使用 CROSS JOINWHERE 的對等運算式。

範例 - 這個查詢

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 子句會產生單個組合的資料列。當 SELECT 清單中存在彙總函式時,或為了消除輸出中的冗餘時,通常會使用 GROUP BY

範例

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

集合運算子會將兩個或多個輸入查詢的結果組合到單個結果集中。您必須指定 ALLDISTINCT;如果您指定 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 指定一個非負的 count,類型為 INTEGER,且不會傳回超過 count 個資料列。LIMIT 0 會傳回 0 個資料列。如果存在集合運算,則會在評估集合運算後套用 LIMIT

OFFSET 指定一個非負的 skip_rows,類型為 INTEGER,並且只會考慮表格中該偏移量後的資料列。

這些子句只接受常值或參數值。

LIMITOFFSET 傳回的資料列未指定。

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] aliasSELECT 清單中的任何運算式引入明確別名。AS 關鍵字是選用的。

範例

SELECT s.FirstName AS name, LOWER(s.FirstName) AS lname
FROM Singers s;

明確別名可見性

在查詢中引入明確別名後,對於您可以在查詢中的其他位置參照該別名的地方有限制。這些別名可見性的限制是 Beam 名稱範圍規則的結果。

FROM 子句別名

Beam 從左到右處理 FROM 子句中的別名,並且別名只對後續的 JOIN 子句可見。

不明確的別名

如果名稱不明確,也就是說它可以解析為多個唯一物件,則 Beam 會提供錯誤。

範例

此查詢包含表格之間衝突的欄位名稱,因為 SingersSongs 都有名為 SingerID 的欄位

SELECT SingerID
FROM Singers, Songs;

隱含別名

SELECT 清單中,如果存在沒有明確別名的運算式,Beam 會根據以下規則指派隱含別名。SELECT 清單中可以有多個具有相同別名的欄位。

在所有其他情況下,沒有隱含別名,因此欄位是匿名的,並且無法依名稱參照。該欄位的資料仍會傳回,且顯示的查詢結果可能會為該欄位產生標籤,但該標籤無法像別名一樣使用。

FROM 子句中,from_item 不需要具有別名。適用以下規則

如果存在沒有明確別名的運算式,Beam 會在以下情況下指派隱含別名

表格子查詢沒有隱含別名。

FROM UNNEST(x) 沒有隱含別名。

此頁面的部分內容是根據 work 修改而來,這些內容由 Google 共用,並依照 Creative Commons 3.0 屬名授權條款中所述的條款使用。