Beam ZetaSQL クエリ構文

クエリステートメントは、1 つ以上のテーブル、ストリーム、または式をスキャンし、計算された結果行を返します。

SQL 構文

query_statement:
    query_expr

query_expr:
    [ WITH with_query_name AS ( query_expr ) [, ...] ]
    { select | ( query_expr ) | query_expr set_op query_expr }
    [ [ ORDER BY expression [{ ASC | DESC }] [, ...] ] LIMIT count [ OFFSET skip_rows ] ]

select:
    SELECT  [ ALL | DISTINCT ] { * | expression [ [ AS ] alias ] } [, ...]
    [ FROM from_item ]
    [ WHERE bool_expression ]
    [ GROUP BY expression [, ...] ]
    [ HAVING bool_expression ]

set_op:
    UNION { ALL | DISTINCT } | INTERSECT { ALL | DISTINCT } | EXCEPT { ALL | DISTINCT }

from_item: {
    table_name [ [ AS ] alias ] |
    join |
    ( query_expr ) [ [ AS ] alias ] |
    with_query_name [ [ AS ] alias ]
}
table_name:
    identifier [ . identifier ...]

join:
    from_item [ join_type ] JOIN from_item
    ON bool_expression

join_type:
    { INNER | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }

表記

SELECT リスト

構文

SELECT  [ ALL ]
    { * | expression [ [ AS ] alias ] } [, ...]

SELECT リストは、クエリが返す列を定義します。SELECT リストの式は、対応する FROM 句の from_item 内の列を参照できます。

SELECT リストの各項目は次のいずれかです。

SELECT *

SELECT * は、select star と呼ばれることが多く、クエリ全体を実行した後に可視になる列ごとに 1 つの出力列を生成します。

SELECT * FROM (SELECT "apple" AS fruit, "carrot" AS vegetable);

+-------+-----------+
| fruit | vegetable |
+-------+-----------+
| apple | carrot    |
+-------+-----------+

SELECT

注意: 最上位の SELECT では、明示的に選択した列名を使用するか、式を使用する場合は明示的なエイリアスを使用する必要があります。

SELECT リストの項目は式にすることができます。これらの式は単一の値に評価され、オプションの明示的な alias を持つ 1 つの出力列を生成します。

式に明示的なエイリアスがない場合は、可能な場合は暗黙的なエイリアスのルールに従って暗黙的なエイリアスを受け取ります。それ以外の場合、列は匿名になり、クエリの他の場所で名前で参照することはできません。

SELECT 修飾子

次のように、SELECT クエリから返される結果を変更できます。

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

Beam SQL でクエリ可能なデータソースの完全修飾 SQL 名。ドットで区切られた識別子のリストを使用して、標準 SQL の字句構造で指定されます。文字、数字、またはアンダースコア以外の文字を含む識別子を囲むには、バッククォートを使用する必要があります。

SELECT * FROM bigquery.table.`my-project`.baseball.roster;
SELECT * FROM pubsub.topic.`my-project`.incoming_events;

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 句は同じ名前の永続的なテーブルを非表示にします。例:

db.Roster.

サブクエリ

サブクエリは、別のステートメントの内側に表示されるクエリで、かっこで囲まれて記述されます。これらは「サブ SELECT」または「ネストされた SELECT」とも呼ばれます。完全な SELECT 構文はサブクエリで有効です。

サブクエリには 2 つのタイプがあります。

両方のタイプのサブクエリの周りに括弧が必要であることに注意してください。

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

join_type:
    { INNER | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }

JOIN 句は 2 つの from_item をマージし、SELECT 句が 1 つのソースとしてクエリできるようにします。join_typeON 句 (「結合条件」) は、2 つの from_item から行を結合および破棄して 1 つのソースを形成する方法を指定します。

すべての JOIN 句には join_type が必要です。

[INNER] JOIN

INNER JOIN または単に JOIN は、2 つの from_item のデカルト積を効果的に計算し、結合条件を満たさないすべての行を破棄します。「効果的に」とは、実際にはデカルト積を計算せずに INNER 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

2 つの from_itemLEFT OUTER JOIN (または単に LEFT JOIN) の結果は、結合述語を満たす右の from_item に行がない場合でも、JOIN 句内の左の 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 が含まれます。結合された行 (2 つの行を結合した結果) は、bool_expression が TRUE を返した場合に結合条件を満たします。

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

JOIN のシーケンス

FROM 句には、複数の JOIN 句を順番に含めることができます。

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

ここで、ab、および 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 STARTS_WITH(LastName, "Mc") OR STARTS_WITH(LastName, "Mac");

WHERE 句では、SELECT リストから列エイリアスを参照することはできません。

GROUP BY 句

構文

GROUP BY expression [, ...]

GROUP BY句は、テーブル内の行をGROUP BY句のexpressionに対して非一意の値を持つ行をグループ化します。ソーステーブル内の複数の行がexpressionに対して非一意の値を持つ場合、GROUP BY句は単一の結合された行を生成します。GROUP BYは、集計関数がSELECTリストに存在する場合、または出力の冗長性を排除するためによく使用されます。expressionのデータ型は、グループ化可能である必要があります。

SELECT SUM(PointsScored), LastName
FROM PlayerStats
GROUP BY LastName;

GROUP BY句は、SELECTリスト内の式の名前を参照できます。また、GROUP BY句では、整数値を使用してSELECTリスト内の式への序数参照も許可されています。1SELECTリストの最初の式を、2は2番目の式を、というように参照します。式リストは、序数と式の名前を組み合わせることができます。

SELECT SUM(PointsScored), LastName, FirstName
FROM PlayerStats
GROUP BY LastName, FirstName;

上記のクエリは以下と同等です。

SELECT SUM(PointsScored), LastName, FirstName
FROM PlayerStats
GROUP BY 2, FirstName;

GROUP BY句はエイリアスを参照することもできます。クエリにSELECT句にエイリアスが含まれている場合、これらのエイリアスは対応するFROM句の名前を上書きします。

SELECT SUM(PointsScored), LastName as last_name
FROM PlayerStats
GROUP BY last_name;

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;

クエリにSELECT句にエイリアスが含まれている場合、これらのエイリアスはFROM句の名前を上書きします。

SELECT LastName, SUM(PointsScored) AS ps
FROM Roster
GROUP BY LastName
HAVING ps > 0;

必須の集計

集計はHAVING句自体に存在する必要はありませんが、集計は次のいずれかの形式で少なくとも1つ存在する必要があります。

SELECTリストの集計関数。

SELECT LastName, SUM(PointsScored) AS total
FROM PlayerStats
GROUP BY LastName
HAVING total > 15;

「HAVING」句の集計関数。

SELECT LastName
FROM PlayerStats
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

SELECTリストとHAVING句の両方の集計。

集計関数がSELECTリストとHAVING句の両方に存在する場合、集計関数とそれらが参照する列は同じである必要はありません。以下の例では、2つの集計関数COUNT()SUM()が異なり、異なる列も使用しています。

SELECT LastName, COUNT(*)
FROM PlayerStats
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

LIMIT 句と OFFSET 句

構文

[ ORDER BY expression [{ASC | DESC}] [,...] ] LIMIT count [ OFFSET skip_rows ]

ORDER BY句は、結果セットのソート基準として列または式を指定します。ORDER BY句が存在しない場合、クエリの結果の順序は定義されません。デフォルトのソート方向はASCで、expressionの値の昇順で結果をソートします。DESCは結果を降順にソートします。FROM句またはSELECTリストの列エイリアスを使用できます。クエリにSELECT句にエイリアスが含まれている場合、これらのエイリアスは対応するFROM句の名前を上書きします。

複数の列で順序付けすることが可能です。

値を順序付けする場合、次のルールが適用されます。

LIMITは、INT64型の負でないcountを指定し、count行以下の行が返されます。LIMIT 0は0行を返します。セット演算がある場合、LIMITはセット演算が評価された後に適用されます。

OFFSETは、INT64型の負でないskip_rowsを指定し、テーブル内のそのオフセットからの行のみが考慮されます。

これらの句は、リテラル値またはパラメーター値のみを受け入れます。

LIMITおよびOFFSETによって返される行は、これらの演算子がORDER BYの後に使用されない限り、指定されません。

WITH 句

WITH句は、1つ以上の名前付きサブクエリの結果を一時テーブル名にバインドします。導入された各テーブル名は、同じクエリ式内の後続のSELECT式で表示されます。これには、次の種類のSELECT式が含まれます。

WITH subQ1 AS (SELECT SchoolID FROM Roster),
     subQ2 AS (SELECT OpponentID FROM PlayerStats)
SELECT * FROM subQ1
UNION ALL
SELECT * FROM subQ2;

WITH句のスコープ規則は次のとおりです。

Beam SQLはWITH RECURSIVEをサポートしていません。

エイリアス

エイリアスは、クエリに存在するテーブル、列、または式に付けられた一時的な名前です。SELECTリストまたはFROM句で明示的なエイリアスを導入できます。

明示的なエイリアス構文

FROM句またはSELECTリストのいずれかで明示的なエイリアスを導入できます。

FROM句では、[AS] aliasを使用して、テーブル、配列、サブクエリなど、任意の項目の明示的なエイリアスを導入できます。ASキーワードはオプションです。

SELECT s.FirstName, s2.SongName
FROM Singers AS s, (SELECT * FROM Songs) AS s2;

[AS] aliasを使用して、SELECTリストの任意の式の明示的なエイリアスを導入できます。ASキーワードはオプションです。

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

明示的なエイリアスの可視性

クエリで明示的なエイリアスを導入した後、クエリの他の場所でそのエイリアスを参照できる場所に制限があります。エイリアスの表示に関するこれらの制限は、Beam SQLの名前スコープ規則の結果です。

FROM句のエイリアス

Beam SQLは、FROM句のエイリアスを左から右に処理し、エイリアスはFROM句の後続のパス式にのみ表示されます。

SingersテーブルにARRAY型のConcerts列があると仮定します。

SELECT FirstName
FROM Singers AS s, s.Concerts;

無効

SELECT FirstName
FROM s.Concerts, Singers AS s;  // INVALID.

FROM句のエイリアスは、同じFROM句のサブクエリには表示されませんFROM句のサブクエリは、同じFROM句内の他のテーブルへの関連参照を含めることはできません。

無効

SELECT FirstName
FROM Singers AS s, (SELECT (2020 - ReleaseDate) FROM s)  // INVALID.

FROMのテーブルの任意の列名を、テーブル名での修飾の有無にかかわらず、クエリ内のエイリアスとしてどこでも使用できます。

SELECT FirstName, s.ReleaseDate
FROM Singers s WHERE ReleaseDate = 1975;

SELECTリストのエイリアス

SELECTリストのエイリアスは、次の句にのみ表示されます。

SELECT LastName AS last, SingerID
FROM Singers
ORDER BY last;

GROUP BY、ORDER BY、HAVING 句での明示的なエイリアス

これら3つの句、GROUP BYORDER BY、およびHAVINGは、次の値のみを参照できます。

GROUP BYおよびORDER BYは、3番目のグループを参照することもできます。

SELECT SingerID AS sid, COUNT(Songid) AS s2id
FROM Songs
GROUP BY 1
ORDER BY 2 DESC LIMIT 10;

上記のクエリは以下と同等です。

SELECT SingerID AS sid, COUNT(Songid) AS s2id
FROM Songs
GROUP BY sid
ORDER BY s2id DESC LIMIT 10;

あいまいなエイリアス

名前が曖昧な場合、つまり複数の固有のオブジェクトに解決できる場合、Beam SQLはエラーを提供します。

このクエリには、SingersSongsの両方にSingerIDという名前の列があるため、テーブル間で競合する列名が含まれています。

SELECT SingerID
FROM Singers, Songs;

このクエリには、SELECTリストで重複しているため、GROUP BY句で曖昧なエイリアスが含まれています。

SELECT FirstName AS name, LastName AS name,
FROM Singers
GROUP BY name;

GROUP BY内のFROM句の列名とSELECTリストのエイリアス間の曖昧さ

SELECT UPPER(LastName) AS LastName
FROM Singers
GROUP BY LastName;

上記のクエリは曖昧であり、GROUP BY句のLastNameSingersの元の列LastNameを参照するか、値がUPPER(LastName)であるエイリアスAS LastNameを参照する可能性があるため、エラーが発生します。

パス式にも同じ曖昧さのルールが適用されます。tableに列xyがあり、列zがSTRUCT型で、フィールドvw、およびxがある次のクエリを考えてみましょう。

SELECT x, z AS T
FROM table T
GROUP BY T.x;

エイリアスTは曖昧であり、GROUP BY句のT.xtable.xまたはtable.z.xのいずれかを参照する可能性があるため、エラーが発生します。

名前が、基になる同じオブジェクトに解決される限り、列名とSELECTリストのエイリアスの両方である場合、GROUP BYORDER BY、またはHAVINGで曖昧ではありません

SELECT LastName, BirthYear AS BirthYear
FROM Singers
GROUP BY BirthYear;

エイリアスBirthYearは、基になる同じ列Singers.BirthYearに解決されるため、曖昧ではありません。

付録 A: サンプルデータを使った例

サンプルテーブル

次の3つのテーブルには、アスリート、その学校、およびシーズン中に獲得したポイントに関するサンプルデータが含まれています。これらのテーブルは、さまざまなクエリ句の動作を説明するために使用されます。

テーブルRoster

LastNameSchoolID
Adams50
Buchanan52
Coolidge52
Davis51
Eisenhower77

Rosterテーブルには、選手名(LastName)と学校に割り当てられた一意のID(SchoolID)のリストが含まれています。

テーブルPlayerStats

LastNameOpponentIDPointsScored
Adams513
Buchanan770
Coolidge771
Adams524
Buchanan5013

PlayerStatsテーブルには、選手名(LastName)、特定のゲームで対戦した対戦相手に割り当てられた一意のID(OpponentID)、およびそのゲームでアスリートが獲得したポイント数(PointsScored)のリストが含まれています。

テーブルTeamMascot

SchoolIdマスコット
50ジャガーズ
51ナイツ
52レイカーズ
53マスタングス

TeamMascotテーブルには、ユニークな学校ID(SchoolID)と、その学校のマスコット(Mascot)のリストが含まれています。

JOIN タイプ

1) [INNER] JOIN

SELECT * FROM Roster JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

結果

LastNameRoster.SchoolIdTeamMascot.SchoolIdマスコット
Adams5050ジャガーズ
Buchanan5252レイカーズ
Coolidge5252レイカーズ
Davis5151ナイツ

2) FULL [OUTER] JOIN

SELECT * FROM Roster FULL JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;
LastNameRoster.SchoolIdTeamMascot.SchoolIdマスコット
Adams5050ジャガーズ
Buchanan5252レイカーズ
Coolidge5252レイカーズ
Davis5151ナイツ
Eisenhower77NULLNULL
NULLNULL53マスタングス

3) LEFT [OUTER] JOIN

SELECT * FROM Roster LEFT JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

結果

LastNameRoster.SchoolIdTeamMascot.SchoolIdマスコット
Adams5050ジャガーズ
Buchanan5252レイカーズ
Coolidge5252レイカーズ
Davis5151ナイツ
Eisenhower77NULLNULL

4) RIGHT [OUTER] JOIN

SELECT * FROM Roster RIGHT JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

結果

LastNameRoster.SchoolIdTeamMascot.SchoolIdマスコット
Adams5050ジャガーズ
Davis5151ナイツ
Coolidge5252レイカーズ
Buchanan5252レイカーズ
NULLNULL53マスタングス

GROUP BY 句

SELECT LastName, SUM(PointsScored)
FROM PlayerStats
GROUP BY LastName;
LastNameSUM
Adams7
Buchanan13
Coolidge1

セット演算子

UNION

UNION演算子は、2つ以上のSELECTステートメントの結果セットを、各SELECTステートメントの結果セットから列をペアリングし、それらを垂直方向に連結することによって結合します。

SELECT Mascot AS X, SchoolID AS Y
FROM TeamMascot
UNION ALL
SELECT LastName, PointsScored
FROM PlayerStats;

結果

XY
ジャガーズ50
ナイツ51
レイカーズ52
マスタングス53
Adams3
Buchanan0
Coolidge1
Adams4
Buchanan13

INTERSECT

このクエリは、RosterとPlayerStatsの両方に存在するラストネームを返します。

SELECT LastName
FROM Roster
INTERSECT ALL
SELECT LastName
FROM PlayerStats;

結果

LastName
Adams
Coolidge
Buchanan

EXCEPT

以下のクエリは、Rosterに存在し、PlayerStatsに存在しないラストネームを返します。

SELECT LastName
FROM Roster
EXCEPT DISTINCT
SELECT LastName
FROM PlayerStats;

結果

LastName
Eisenhower
Davis

SELECTステートメントの順序を逆にすると、PlayerStatsに存在し、Rosterに存在しないラストネームが返されます。

SELECT LastName
FROM PlayerStats
EXCEPT DISTINCT
SELECT LastName
FROM Roster;

結果

(empty)