標準 SQL のクエリ構文

クエリ ステートメントは、1 つ以上のテーブルまたは式をスキャンし、計算結果の行を返します。このトピックでは、BigQuery での SQL クエリの構文について説明します。

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 [ AS { STRUCT | VALUE } ] [{ ALL | DISTINCT }]
        { [ expression. ]* [ EXCEPT ( column_name [, ...] ) ]
[ REPLACE ( expression [ AS ] column_name [, ...] ) ]
| expression [ [ AS ] alias ] } [, ...] [ FROM from_item [, ...] ] [ WHERE bool_expression ] [ GROUP BY { expression [, ...] | ROLLUP ( expression [, ...] ) } ] [ HAVING bool_expression ] [ WINDOW named_window_expression AS { named_window | ( [ window_definition ] ) } [, ...] ] set_op: UNION { ALL | DISTINCT } | INTERSECT DISTINCT | EXCEPT DISTINCT from_item: { table_name [ [ AS ] alias ] [ FOR SYSTEM_TIME AS OF timestamp_expression ] | join | ( query_expr ) [ [ AS ] alias ] | field_path | { UNNEST( array_expression ) | UNNEST( array_path ) | array_path } [ [ AS ] alias ] [ WITH OFFSET [ [ 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 を表します。
  • 波括弧「{ }」ではオプションのセットを囲みます。
  • 角括弧内の省略記号に先立つカンマ「[, ... ]」は、前の項目をカンマで区切ったリストに繰り返すことができることを示しています。

サンプル テーブル

以降のテーブルでは、このリファレンスのさまざまなクエリ句の動作を例で説明しています。

Roster テーブル

Roster テーブルには、選手名(LastName)と、選手が所属する学校に割り当てられた一意の ID(SchoolID)が含まれます。次のようになります。

+-----------------------+
| LastName   | SchoolID |
+-----------------------+
| Adams      | 50       |
| Buchanan   | 52       |
| Coolidge   | 52       |
| Davis      | 51       |
| Eisenhower | 77       |
+-----------------------+

このリファレンスのサンプルの一時テーブル名は、次の WITH 句を使用して再現できます。

WITH Roster AS
 (SELECT 'Adams' as LastName, 50 as SchoolID UNION ALL
  SELECT 'Buchanan', 52 UNION ALL
  SELECT 'Coolidge', 52 UNION ALL
  SELECT 'Davis', 51 UNION ALL
  SELECT 'Eisenhower', 77)
SELECT * FROM Roster

PlayerStats テーブル

PlayerStats テーブルには、選手名(LastName)、ある試合の対戦相手に割り当てられた一意の ID(OpponentID)、その試合での選手の得点数(PointsScored)が含まれます。

+----------------------------------------+
| LastName   | OpponentID | PointsScored |
+----------------------------------------+
| Adams      | 51         | 3            |
| Buchanan   | 77         | 0            |
| Coolidge   | 77         | 1            |
| Davis      | 52         | 4            |
| Eisenhower | 50         | 13           |
+----------------------------------------+

このリファレンスのサンプルの一時テーブル名は、次の WITH 句を使用して再現できます。

WITH PlayerStats AS
 (SELECT 'Adams' as LastName, 51 as OpponentID, 3 as PointsScored UNION ALL
  SELECT 'Buchanan', 77, 0 UNION ALL
  SELECT 'Coolidge', 77, 1 UNION ALL
  SELECT 'Adams', 52, 4 UNION ALL
  SELECT 'Buchanan', 50, 13)
SELECT * FROM PlayerStats

TeamMascot テーブル

TeamMascot テーブルには、一意の学校 ID(SchoolID)とその学校のマスコット(Mascot)が含まれます。

+---------------------+
| SchoolID | Mascot   |
+---------------------+
| 50       | Jaguars  |
| 51       | Knights  |
| 52       | Lakers   |
| 53       | Mustangs |
+---------------------+

このリファレンスのサンプルの一時テーブル名は、次の WITH 句を使用して再現できます。

WITH TeamMascot AS
 (SELECT 50 as SchoolID, 'Jaguars' as Mascot UNION ALL
  SELECT 51, 'Knights' UNION ALL
  SELECT 52, 'Lakers' UNION ALL
  SELECT 53, 'Mustangs')
SELECT * FROM TeamMascot

SELECT リスト

SELECT [ AS { typename | STRUCT | VALUE } ] [{ ALL | DISTINCT }]
    { [ expression. ]* [ EXCEPT ( column_name [, ...] ) ]
[ REPLACE ( expression [ AS ] column_name [, ...] ) ]
| expression [ [ AS ] alias ] } [, ...]

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

SELECT リストの各項目は、次のうちの 1 つです。

  • *
  • expression
  • expression.*

SELECT *

SELECT * は、select star とも呼ばれ、クエリ全体を実行した後に表示される各列に対して 1 つの出力列を生成します。

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

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

SELECT expression

SELECT リストの項目には、式を指定できます。これらの式から、1 つの値が求められ、オプションの明示的 alias を持つ 1 つの出力列が生成されます。

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

SELECT expression.*

SELECT リスト内の項目は expression.* という形式で指定することもできます。この場合、expression の各列または先頭フィールドに 1 つの出力列が生成されます。式は、テーブル エイリアスか、STRUCT のような単一値フィールド付きのデータ型になります。

次のクエリは、テーブル groceries の各列に対して 1 つの出力列を生成し、エイリアスには 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 |
+-------+---------+-------+

その他の例:

WITH locations AS
  (SELECT STRUCT("Seattle" AS city, "Washington" AS state) AS location
  UNION ALL
  SELECT STRUCT("Phoenix" AS city, "Arizona" AS state) AS location)
SELECT l.location.*
FROM locations l;

+---------+------------+
| city    | state      |
+---------+------------+
| Seattle | Washington |
| Phoenix | Arizona    |
+---------+------------+
WITH locations AS
  (SELECT ARRAY<STRUCT<city STRING, state STRING>>[("Seattle", "Washington"),
    ("Phoenix", "Arizona")] AS location)
SELECT l.LOCATION[offset(0)].*
FROM locations l;

+---------+------------+
| city    | state      |
+---------+------------+
| Seattle | Washington |
+---------+------------+

* 演算子の修飾子

SELECT * EXCEPT

SELECT * EXCEPT ステートメントは、結果から除外する 1 つ以上の列の名前を指定します。指定された名前と一致する列はすべて出力から除外されます。

WITH orders AS
  (SELECT 5 as order_id,
  "sprocket" as item_name,
  200 as quantity)
SELECT * EXCEPT (order_id)
FROM orders;

+-----------+----------+
| item_name | quantity |
+-----------+----------+
| sprocket  | 200      |
+-----------+----------+

SELECT * REPLACE

SELECT * REPLACE ステートメントでは、expression AS identifier 句を 1 つ以上指定します。個々の ID が SELECT * ステートメントの列名と一致している必要があります。出力列のリストで、REPLACE 句の ID と一致する列が REPLACE 句の表現で置き換えられます。

SELECT * REPLACE ステートメントでは、列の名前や順序は変更されません。ただし、値と値の型は変更できます。

WITH orders AS
  (SELECT 5 as order_id,
  "sprocket" as item_name,
  200 as quantity)
SELECT * REPLACE ("widget" AS item_name)
FROM orders;

+----------+-----------+----------+
| order_id | item_name | quantity |
+----------+-----------+----------+
| 5        | widget    | 200      |
+----------+-----------+----------+

WITH orders AS
  (SELECT 5 as order_id,
  "sprocket" as item_name,
  200 as quantity)
SELECT * REPLACE (quantity/2 AS quantity)
FROM orders;

+----------+-----------+----------+
| order_id | item_name | quantity |
+----------+-----------+----------+
| 5        | sprocket  | 100      |
+----------+-----------+----------+

重複行の処理

次のとおり、SELECT クエリから返された結果を修正できます。

SELECT DISTINCT

SELECT DISTINCT ステートメントは、重複した行を破棄し、残りの行のみを返します。SELECT DISTINCT は、次の型の列を返すことはできません。

  • STRUCT
  • ARRAY

SELECT ALL

SELECT ALL ステートメントは、重複した行も含めて、すべての行を返します。SELECT ALLSELECT のデフォルト動作です。

値テーブル

BigQuery の値テーブルは、行の型が単一値であるテーブルです。通常のテーブルでは各行が複数の列で構成され、各列には名前と型があります。値テーブルでは行の型が単一値のみであり、列名はありません。

注: BigQuery のクエリでは、型が STRUCT の値テーブルだけを返すことができます。

1 列だけが返されるクエリを使用する場合、代わりに値テーブルが返されるクエリを使用できます。たとえば、スカラー サブクエリと配列サブクエリ(サブクエリを参照)では、通常は 1 列が返されるクエリを使用する必要がありますが、BigQuery では値テーブルが返されるクエリも使用できます。

クエリで SELECT AS が使用される場合、次のいずれかの構文を使用すると、値テーブルが生成されます。

SELECT AS STRUCT

SELECT AS STRUCT expr [[AS] struct_field_name1] [,...]

上記の構文を使用すると、行の型が STRUCT である値テーブルが生成されます。この場合、STRUCT フィールドの名前と型は、SELECT リストで生成される列の名前と型と一致します。

例:

SELECT ARRAY(SELECT AS STRUCT 1 a, 2 b)

SELECT AS STRUCT をスカラー サブクエリや配列サブクエリで使用すると、複数の値をまとめた単一の STRUCT 型を生成できます。通常、スカラー サブクエリと配列サブクエリ(サブクエリを参照)で複数の列を返すことは許可されていませんが、STRUCT 型の単一列を返すことはできます。

SELECT AS VALUE

SELECT AS VALUE では、1 列だけを生成する SELECT リストから値テーブルが生成されます。1 列の出力テーブル(名前付きの場合もある)が生成される代わりに、出力として値テーブルが生成されます。この値テーブルの行の型は 1 つの SELECT 列で生成された値の型になります。その列にエイリアスがあっても、値テーブルでは破棄されます。

例:

SELECT AS VALUE STRUCT(1 AS a, 2 AS b) xyz

上記のクエリを使用すると、行の型が STRUCT<a int64, b int64> であるテーブルが生成されます。

エイリアス

SELECT リストのエイリアスの構文と可視性については、エイリアスの使用をご覧ください。

FROM 句

from_item: {
    table_name [ [ AS ] alias ] [ FOR SYSTEM_TIME AS OF timestamp_expression ]  |
    join |
    ( query_expr ) [ [ AS ] alias ] |
    field_path |
    { UNNEST( array_expression ) | UNNEST( array_path ) | array_path }
        [ [ AS ] alias ] [ WITH OFFSET [ [ AS ] alias ] ] |
    with_query_name [ [ AS ] alias ]
}

FROM 句は行を取得する 1 つまたは複数のテーブルを示し、これらの行を結合して、残りのクエリの処理のための単一ストリームの行を生成する方法を指定します。

table_name

既存のテーブルの名前(修飾可)。

SELECT * FROM Roster;
SELECT * FROM dataset.Roster;
SELECT * FROM project.dataset.Roster;

FOR SYSTEM_TIME AS OF

FOR SYSTEM_TIME AS OF は、timestamp_expression の時点で最新であったテーブル定義と行の履歴バージョンを参照します。

制限事項:

FOR SYSTEM_TIME AS OF を含む FROM 句のソーステーブルには、次のいずれも指定できません。

  • ARRAY スキャン。フラット化配列UNNEST 演算子の出力などを含む。
  • WITH 句で定義された共通テーブル式。

timestamp_expressionは、定数式である必要があります。以下を含めることはできません。

  • サブクエリ。
  • 相関参照(SELECT リストなど、より高いレベルのクエリ ステートメントに表示されるテーブルの列への参照)。
  • ユーザー定義関数(UDF)。

次の範囲に該当する timestamp_expression の値は指定できません。

  • 現在のタイムスタンプより後(将来)。
  • 現在のタイムスタンプより 7 日以上前。

1 つのクエリ ステートメントで、現在の時刻を含めた複数の時点における 1 つのテーブルを参照することはできません。つまり、クエリで同じタイムスタンプで複数回テーブルを参照することはできますが、現在のバージョンと履歴バージョン、または異なる 2 つの履歴バージョンを参照することはできません。

例:

次のクエリは、1 時間前のテーブルの履歴バージョンを返します。

SELECT *
FROM t
  FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR);

次のクエリは、絶対的な時刻でのテーブルの履歴バージョンを戻します。

SELECT *
FROM t
  FOR SYSTEM_TIME AS OF '2017-01-01 10:00:00-07:00';

次のクエリでは、timestamp_expression が、同じクエリの別の列に対する相関参照を行っているため、エラーになります。

SELECT *
FROM t1
WHERE t1.a IN (SELECT t2.a
               FROM t2 FOR SYSTEM_TIME AS OF t1.timestamp_column);

次のオペレーションは、テーブルが置換される前のテーブルの履歴バージョンへのアクセスを示しています。

DECLARE before_replace_timestamp TIMESTAMP;

-- Create table books.
CREATE TABLE books AS
SELECT 'Hamlet' title, 'William Shakespeare' author;

-- Get current timestamp before table replacement.
SET before_replace_timestamp = CURRENT_TIMESTAMP();

-- Replace table with different schema(title and release_date).
CREATE OR REPLACE TABLE books AS
SELECT 'Hamlet' title, DATE '1603-01-01' release_date;

-- This query returns Hamlet, William Shakespeare as result.
SELECT * FROM books FOR SYSTEM_TIME AS OF before_replace_timestamp;

次のオペレーションは、DML ジョブの前のテーブルの履歴バージョンの表へのアクセスを示しています。

DECLARE JOB_START_TIMESTAMP TIMESTAMP;

-- Create table books.
CREATE OR REPLACE TABLE books AS
SELECT 'Hamlet' title, 'William Shakespeare' author;

-- Insert two rows into the books.
INSERT books (title, author)
VALUES('The Great Gatsby', 'F. Scott Fizgerald'),
      ('War and Peace', 'Leo Tolstoy');

SELECT * FROM books;

SET JOB_START_TIMESTAMP = (
  SELECT start_time
  FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_USER
  WHERE job_type="QUERY"
    AND statement_type="INSERT"
  ORDER BY start_time DESC
  LIMIT 1
 );

-- This query only returns Hamlet, William Shakespeare as result.
SELECT * FROM books FOR SYSTEM_TIME AS OF JOB_START_TIMESTAMP;

join

JOIN のタイプをご覧ください。

select

( select ) [ [ AS ] alias ] は、テーブルのサブクエリです。

field_path

FROM 句内で、field_path は特定のデータ型内のフィールドに解決する任意のパスです。field_path は、ネストされたデータ構造の中に任意で深く入り込むことができます。

有効な field_path の値の例を以下に示します。

SELECT * FROM T1 t1, t1.array_column;

SELECT * FROM T1 t1, t1.struct_column.array_field;

SELECT (SELECT ARRAY_AGG(c) FROM t1.array_column c) FROM T1 t1;

SELECT a.struct_field1 FROM T1 t1, t1.array_of_structs a;

SELECT (SELECT STRING_AGG(a.struct_field1) FROM t1.array_of_structs a) FROM T1 t1;

FROM 句のフィールドパスは、配列フィールドで終了しなければなりません。さらに、フィールドパスでは、パスの末尾の前に配列を含めることができません。たとえば、パス array_column.some_array.some_array_field は、パスの末尾の前に配列が含まれているため無効です。

UNNEST

UNNEST 演算子は ARRAY を受け取り、ARRAY 内の各要素を 1 行にしてテーブルを返します。UNNESTFROM 句の外で IN 演算子とともに使用することもできます。

ほとんどの要素型の入力 ARRAY について、UNNEST の出力には通常 1 つの列が含まれます。この単一の列にはオプションの alias があり、これを使用するとクエリの別の場所で列を参照できます。こうした要素型を持つ ARRAYS は、以下のような複数の列を返します。

  • STRUCT

UNNEST は入力 ARRAY 内の要素の順序を破壊します。配列要素のインデックスを含む 2 番目の列を返すには、オプションの WITH OFFSET 句を使用します(以下をご覧ください)。

STRUCT の入力 ARRAY について、UNNESTSTRUCT ごとに 1 行を返し、STRUCT 内の各フィールドについてそれぞれ別個の列が生成されます。各列のエイリアスは、対応する STRUCT フィールドの名前になります。

SELECT *
FROM UNNEST(ARRAY<STRUCT<x INT64, y STRING>>[(1, 'foo'), (3, 'bar')]);

+---+-----+
| x | y   |
+---+-----+
| 3 | bar |
| 1 | foo |
+---+-----+

UNNEST 演算子は値テーブルを返すため、UNNEST のエイリアスを作成して範囲変数を定義し、それをクエリの他の場所で参照できます。その範囲変数を SELECT リスト内で参照すると、クエリの結果として、入力テーブルの元の STRUCT の全フィールドを含む STRUCT が返されます。

例:

SELECT *, struct_value
FROM UNNEST(ARRAY<STRUCT<x INT64, y STRING>>[(1, 'foo'), (3, 'bar')])
       AS struct_value;

+---+-----+--------------+
| x | y   | struct_value |
+---+-----+--------------+
| 3 | bar | {3, bar}     |
| 1 | foo | {1, foo}     |
+---+-----+--------------+

ARRAY のネスト解除は、明示的にも、暗黙的にもできます。明示的なネスト解除の場合、array_expressionARRAY 値を返す必要がありますが、ARRAY に解決される必要はなく、UNNEST キーワードが必要になります。

例:

SELECT * FROM UNNEST ([1, 2, 3]);

暗黙のネスト解除の場合、array_pathARRAY に解決される必要があり、UNNEST キーワードは任意になります。

例:

SELECT x
FROM mytable AS t,
  t.struct_typed_column.array_typed_field1 AS x;

このシナリオでは、array_path はデータ構造に任意に深く入ることができますが、末尾のフィールドは ARRAY データ型でなければなりません。式の前のフィールドは、ARRAY から名前付きのフィールドを抽出できないため、いずれも ARRAY データ型にすることはできません。

UNNEST は、NULL を次のとおり扱います。

  • NULL と空の配列はゼロ行を生成します。
  • NULL を含む配列は、NULL 値を含む行を生成します。

オプションの WITH OFFSET 句は、UNNEST 演算で生成される行ごとに「オフセット」値(カウントはゼロから始まります)を含む別の列を返します。この列にはオプションの alias があり、デフォルトのエイリアスはオフセットです。

例:

SELECT * FROM UNNEST ( ) WITH OFFSET AS num;

UNNEST のその他の使用方法(作成、フラット化、フィルタリングなど)については、Arrays topic をご覧ください。

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 句では、次のようにテーブル名を修飾する場合を除き、クエリの実行中は同名の永続テーブルを非表示にします。

dataset.Roster または project.dataset.Roster

エイリアス

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 句は 2 つの from_item を結合して、SELECT 句でそれらを 1 つのソースとしてクエリできるようにします。join_typeON または USING 句(「結合条件」)によって、2 つの from_item で行の結合と廃棄を行い、1 つのソースを形成する方法が指定されます。

JOIN 句には、join_type が必須です。

JOIN 句は、次の条件の 1 つが true でない限り、結合条件を必要とします。

  • join_typeCROSS です。
  • from_item の 1 つまたは両方がテーブルではない(array_pathfield_path など)。

[INNER] JOIN

INNER JOIN または単に JOIN は、2 つの from_item のデカルト積を効率的に計算し、結合条件を満たさないすべての行を廃棄します。「効率的に」とは、実際にデカルト積を計算せずに、INNER JOIN を実行することができることを意味します。

FROM A INNER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------+
| w | x |  *  | y | z |  =  | w | x | y | z |
+-------+     +-------+     +---------------+
| 1 | a |     | 2 | k |     | 2 | b | 2 | k |
| 2 | b |     | 3 | m |     | 3 | c | 3 | m |
| 3 | c |     | 3 | n |     | 3 | c | 3 | n |
| 3 | d |     | 4 | p |     | 3 | d | 3 | m |
+-------+     +-------+     | 3 | d | 3 | n |
                            +---------------+
FROM A INNER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +-----------+
| x | y |  *  | x | z |  =  | x | y | z |
+-------+     +-------+     +-----------+
| 1 | a |     | 2 | k |     | 2 | b | k |
| 2 | b |     | 3 | m |     | 3 | c | m |
| 3 | c |     | 3 | n |     | 3 | c | n |
| 3 | d |     | 4 | p |     | 3 | d | m |
+-------+     +-------+     | 3 | d | n |
                            +-----------+

次のクエリは、Roster テーブルと TeamMascot テーブルに対して INNER JOIN を実行します。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
+---------------------------+

CROSS JOIN

CROSS JOIN は、2 つの from_item のデカルト積を返します。言い換えれば、最初の from_item の各行を 2 番目の from_item の各行と結合します。

2 つの from_item の行が独立している場合、一方の from_itemM 行、もう一方が N 行とすると、結果は M * N 行になります。これは、どちらかの from_item がゼロ行の場合にも当てはまります。

FROM A CROSS JOIN B

Table A       Table B       Result
+-------+     +-------+     +---------------+
| w | x |  *  | y | z |  =  | w | x | y | z |
+-------+     +-------+     +---------------+
| 1 | a |     | 2 | c |     | 1 | a | 2 | c |
| 2 | b |     | 3 | d |     | 1 | a | 3 | d |
+-------+     +-------+     | 2 | b | 2 | c |
                            | 2 | b | 3 | d |
                            +---------------+

相関 CROSS JOIN を使用すると、ARRAY 列をフラット化できます。この場合、最初の from_item の各行に対する 2 番目の from_item の行が変化します。

FROM A CROSS JOIN A.y

Table A                    Result
+-------------------+      +-----------+
| w | x | y         |  ->  | w | x | y |
+-------------------+      +-----------+
| 1 | a | [P, Q]    |      | 1 | a | P |
| 2 | b | [R, S, T] |      | 1 | a | Q |
+-------------------+      | 2 | b | R |
                           | 2 | b | S |
                           | 2 | b | T |
                           +-----------+

CROSS JOIN は、次のように明示的に記述できます。

FROM a CROSS JOIN b

または、次のように暗黙的にコンマクロス結合として記述できます。

FROM a, b

丸括弧内に、コンマクロス結合は記述できません。

FROM a CROSS JOIN (b, c)  // INVALID

コンマクロス結合が JOIN の順序でどのように動作するかについては、JOIN の順序をご覧ください。

このクエリは、Roster テーブルと TeamMascot テーブルに対して、明示的に CROSS JOIN を実行します。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster CROSS JOIN TeamMascot;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Adams      | Knights      |
| Adams      | Lakers       |
| Adams      | Mustangs     |
| Buchanan   | Jaguars      |
| Buchanan   | Knights      |
| Buchanan   | Lakers       |
| Buchanan   | Mustangs     |
| ...                       |
+---------------------------+

このクエリは、上記の明示的な CROSS JOIN と同じ結果を生成するコンマクロス結合を実行します。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster, TeamMascot;

FULL [OUTER] JOIN

FULL OUTER JOIN(または単に FULL JOIN)は、結合条件を満たす両方の from_item 内のすべての行のすべてのフィールドを返します。

FULL は、結合条件を満たさない場合でも、両方の from_item からすべての行が返されるように指定します。

OUTER は 1 つの from_item の指定された行が他の from_item の任意の行に結合しない場合、行が他の from_item からのすべての列に対して NULL を返すことを示します。

FROM A FULL OUTER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------------------+
| w | x |  *  | y | z |  =  | w    | x    | y    | z    |
+-------+     +-------+     +---------------------------+
| 1 | a |     | 2 | k |     | 1    | a    | NULL | NULL |
| 2 | b |     | 3 | m |     | 2    | b    | 2    | k    |
| 3 | c |     | 3 | n |     | 3    | c    | 3    | m    |
| 3 | d |     | 4 | p |     | 3    | c    | 3    | n    |
+-------+     +-------+     | 3    | d    | 3    | m    |
                            | 3    | d    | 3    | n    |
                            | NULL | NULL | 4    | p    |
                            +---------------------------+
FROM A FULL OUTER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +--------------------+
| x | y |  *  | x | z |  =  | x    | y    | z    |
+-------+     +-------+     +--------------------+
| 1 | a |     | 2 | k |     | 1    | a    | NULL |
| 2 | b |     | 3 | m |     | 2    | b    | k    |
| 3 | c |     | 3 | n |     | 3    | c    | m    |
| 3 | d |     | 4 | p |     | 3    | c    | n    |
+-------+     +-------+     | 3    | d    | m    |
                            | 3    | d    | n    |
                            | 4    | NULL | p    |
                            +--------------------+

このクエリは、Roster テーブルと TeamMascot テーブルに対して FULL JOIN を実行します。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster FULL JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
| Eisenhower | NULL         |
| NULL       | Mustangs     |
+---------------------------+

LEFT [OUTER] JOIN

2 つの from_item に対する LEFT OUTER JOIN(または単に LEFT JOIN)の結果は、右側の from_item に結合の述語を満たす行がない場合でも、常に JOIN 句の左側の from_item のすべての行を保持します。

LEFT は、左側の from_item からすべての行が返されることを示します。左側の from_item のいずれかの行が右側の from_item のどの行とも結合しない場合、行は右側の from_item のすべての列に対して NULL を返します。左側の from_item のどの行にも結合されない右側の from_item の行は破棄されます。

FROM A LEFT OUTER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------------------+
| w | x |  *  | y | z |  =  | w    | x    | y    | z    |
+-------+     +-------+     +---------------------------+
| 1 | a |     | 2 | k |     | 1    | a    | NULL | NULL |
| 2 | b |     | 3 | m |     | 2    | b    | 2    | k    |
| 3 | c |     | 3 | n |     | 3    | c    | 3    | m    |
| 3 | d |     | 4 | p |     | 3    | c    | 3    | n    |
+-------+     +-------+     | 3    | d    | 3    | m    |
                            | 3    | d    | 3    | n    |
                            +---------------------------+
FROM A LEFT OUTER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +--------------------+
| x | y |  *  | x | z |  =  | x    | y    | z    |
+-------+     +-------+     +--------------------+
| 1 | a |     | 2 | k |     | 1    | a    | NULL |
| 2 | b |     | 3 | m |     | 2    | b    | k    |
| 3 | c |     | 3 | n |     | 3    | c    | m    |
| 3 | d |     | 4 | p |     | 3    | c    | n    |
+-------+     +-------+     | 3    | d    | m    |
                            | 3    | d    | n    |
                            +--------------------+

このクエリは、Roster テーブルと TeamMascot テーブルに対して LEFT JOIN を実行します。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster LEFT JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
| Eisenhower | NULL         |
+---------------------------+

RIGHT [OUTER] JOIN

RIGHT OUTER JOIN(または単に RIGHT JOIN)の結果は、LEFT OUTER JOIN の結果と同様になり、対称的になります。

FROM A RIGHT OUTER JOIN B ON A.w = B.y

Table A       Table B       Result
+-------+     +-------+     +---------------------------+
| w | x |  *  | y | z |  =  | w    | x    | y    | z    |
+-------+     +-------+     +---------------------------+
| 1 | a |     | 2 | k |     | 2    | b    | 2    | k    |
| 2 | b |     | 3 | m |     | 3    | c    | 3    | m    |
| 3 | c |     | 3 | n |     | 3    | c    | 3    | n    |
| 3 | d |     | 4 | p |     | 3    | d    | 3    | m    |
+-------+     +-------+     | 3    | d    | 3    | n    |
                            | NULL | NULL | 4    | p    |
                            +---------------------------+
FROM A RIGHT OUTER JOIN B USING (x)

Table A       Table B       Result
+-------+     +-------+     +--------------------+
| x | y |  *  | x | z |  =  | x    | y    | z    |
+-------+     +-------+     +--------------------+
| 1 | a |     | 2 | k |     | 2    | b    | k    |
| 2 | b |     | 3 | m |     | 3    | c    | m    |
| 3 | c |     | 3 | n |     | 3    | c    | n    |
| 3 | d |     | 4 | p |     | 3    | d    | m    |
+-------+     +-------+     | 3    | d    | n    |
                            | 4    | NULL | p    |
                            +--------------------+

このクエリは、Roster テーブルと TeamMascot テーブルに対して RIGHT JOIN を実行します。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster RIGHT JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
| NULL       | Mustangs     |
+---------------------------+

ON 句

ON 句には bool_expression が含まれます。bool_expression が TRUE を返した場合、結合された行(2 つの行を結合した結果)は、結合条件を満たします。

FROM A JOIN B ON A.x = B.x

Table A   Table B   Result (A.x, B.x)
+---+     +---+     +-------+
| x |  *  | x |  =  | x | x |
+---+     +---+     +-------+
| 1 |     | 2 |     | 2 | 2 |
| 2 |     | 3 |     | 3 | 3 |
| 3 |     | 4 |     +-------+
+---+     +---+

このクエリは、Roster テーブルと TeamMascot テーブルに対して INNER JOIN を実行します。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster JOIN TeamMascot ON Roster.SchoolID = TeamMascot.SchoolID;

+---------------------------+
| LastName   | Mascot       |
+---------------------------+
| Adams      | Jaguars      |
| Buchanan   | Lakers       |
| Coolidge   | Lakers       |
| Davis      | Knights      |
+---------------------------+

USING 句

USING 句には、両方の入力テーブルに出現する 1 つ以上の列からなる column_list が必要です。その列で等価比較を実行し、等価比較で TRUE が返された場合、その行は結合条件を満たします。

FROM A JOIN B USING (x)

Table A   Table B   Result
+---+     +---+     +---+
| x |  *  | x |  =  | x |
+---+     +---+     +---+
| 1 |     | 2 |     | 2 |
| 2 |     | 3 |     | 3 |
| 3 |     | 4 |     +---+
+---+     +---+

このクエリは、Roster テーブルと TeamMascot テーブルに対して INNER JOIN を実行します。

このステートメントは、Roster.SchooldIDTeamMascot.SchooldID と同じ場合に RosterTeamMascot から行を返します。結果には、単一の SchooldID 列が含まれます。

SELECT * FROM Roster INNER JOIN TeamMascot USING (SchoolID);

+----------------------------------------+
| SchoolID   | LastName   | Mascot       |
+----------------------------------------+
| 50         | Adams      | Jaguars      |
| 52         | Buchanan   | Lakers       |
| 52         | Coolidge   | Lakers       |
| 51         | Davis      | Knights      |
+----------------------------------------+

ON と USING の等価性

キーワードの ONUSING は等価ではありませんが類似しています。ON では複数の列が返され、USING では 1 列が返されます。

FROM A JOIN B ON A.x = B.x
FROM A JOIN B USING (x)

Table A   Table B   Result ON     Result USING
+---+     +---+     +-------+     +---+
| x |  *  | x |  =  | x | x |     | x |
+---+     +---+     +-------+     +---+
| 1 |     | 2 |     | 2 | 2 |     | 2 |
| 2 |     | 3 |     | 3 | 3 |     | 3 |
| 3 |     | 4 |     +-------+     +---+
+---+     +---+

ONUSING は等価ではありませんが、返す列を指定すると同じ結果が得られます。

SELECT x FROM A JOIN B USING (x);
SELECT A.x FROM A JOIN B ON A.x = B.x;

Table A   Table B   Result
+---+     +---+     +---+
| x |  *  | x |  =  | x |
+---+     +---+     +---+
| 1 |     | 2 |     | 2 |
| 2 |     | 3 |     | 3 |
| 3 |     | 4 |     +---+
+---+     +---+

JOIN の順序

FROM 句には、複数の JOIN 句を続けて含めることができます。JOIN は左から右にバインドされます。例:

FROM A JOIN B USING (x) JOIN C USING (x)

-- A JOIN B USING (x)        = result_1
-- result_1 JOIN C USING (x) = result_2
-- result_2                  = return value

丸括弧を挿入して JOIN をグループ化することも可能です。

FROM ( (A JOIN B USING (x)) JOIN C USING (x) )

-- A JOIN B USING (x)        = result_1
-- result_1 JOIN C USING (x) = result_2
-- result_2                  = return value

丸括弧を使用すると、異なる順序でバインドされるように JOIN をグループ化できます。

FROM ( A JOIN (B JOIN C USING (x)) USING (x) )

-- B JOIN C USING (x)       = result_1
-- A JOIN result_1          = result_2
-- result_2                 = return value

また、コンマ結合がない場合は、連続する ON 句と USING 句の丸括弧を省略することもできます。

FROM A JOIN B JOIN C JOIN D USING (w) ON B.x = C.y ON A.z = B.x

句にコンマ結合が含まれている場合は、丸括弧を使用する必要があります。

FROM A, B JOIN C JOIN D ON C.x = D.y ON B.z = C.x    // INVALID
FROM A, B JOIN (C JOIN D ON C.x = D.y) ON B.z = C.x  // VALID

コンマクロス結合が JOIN の順序でクエリにある場合、それらは他の JOIN データ型と同様に、左から右にグループ化されます。

FROM A JOIN B USING (x) JOIN C USING (x), D

-- A JOIN B USING (x)        = result_1
-- result_1 JOIN C USING (x) = result_2
-- result_2 CROSS JOIN D     = return value

コンマ結合の後に RIGHT JOIN または FULL JOIN があってはなりません。

FROM A, B RIGHT JOIN C ON TRUE // INVALID
FROM A, B FULL JOIN C ON TRUE  // INVALID
FROM A, B JOIN C ON TRUE       // VALID

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 リストから列のエイリアスを参照できません。

INNER JOIN の式には、WHERE 句に同等の式があります。たとえば、INNER JOINON を使用するクエリには、CROSS JOINWHERE を使用する同等の式があります。

次のクエリがあるとします。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster INNER JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

これは、次のステートメントと同等になります。

SELECT Roster.LastName, TeamMascot.Mascot
FROM Roster CROSS JOIN TeamMascot
WHERE Roster.SchoolID = TeamMascot.SchoolID;

GROUP BY 句

GROUP BY { expression [, ...] | ROLLUP ( expression [, ...] ) }

GROUP BY 句は、GROUP BY 句にある expression の値が同じ行をグループ化し、1 つのテーブルにまとめます。ソーステーブルのうち、expression の値が同じ複数の行に対して、GROUP BY 句は 1 つの結合行を生成します。一般に GROUP BY は、集計関数が SELECT リストに存在する場合に、または出力の冗長性を排除する場合に使用されます。expression のデータ型は Groupable である必要があります。

例:

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;

GROUP BY ROLLUP は、ROLLUP リスト内の式の接頭辞に対する GROUP BY の結果を返します。各接頭辞はグループ化セットと呼ばれます。ROLLUP リスト (a, b, c) の場合、グループ化セットは (a, b, c)(a, b)(a)() です。特定のグループ化セットの GROUP BY の結果を評価する場合、GROUP BY ROLLUP はグループ化セットに含まれない式を NULL 値があるものとして処理します。次のような SELECT 文では、

SELECT a, b, SUM(c) FROM Input GROUP BY ROLLUP(a, b);

ロールアップ リスト (a, b) が使用されています。結果には、すべての行が含まれるグループ化セット (a, b)(a)()GROUP BY の結果が含まれます。これによって、次と同じ行が返されます。

SELECT NULL, NULL, SUM(c) FROM Input               UNION ALL
SELECT a,    NULL, SUM(c) FROM Input GROUP BY a    UNION ALL
SELECT a,    b,    SUM(c) FROM Input GROUP BY a, b;

これにより、ROLLUP リスト内の式とそのリストの接頭辞によって定義されたグループ化セットの集計の計算が可能になります。

例:

WITH Sales AS (
  SELECT 123 AS sku, 1 AS day, 9.99 AS price UNION ALL
  SELECT 123, 1, 8.99 UNION ALL
  SELECT 456, 1, 4.56 UNION ALL
  SELECT 123, 2, 9.99 UNION ALL
  SELECT 789, 3, 1.00 UNION ALL
  SELECT 456, 3, 4.25 UNION ALL
  SELECT 789, 3, 0.99
)
SELECT
  day,
  SUM(price) AS total
FROM Sales
GROUP BY ROLLUP(day);

上記のクエリは、すべての日のロールアップされた合計に加えて、NULL 日と示されている各日に対する行を出力します。

+------+-------+
| day  | total |
+------+-------+
| NULL | 39.77 |
|    1 | 23.54 |
|    2 |  9.99 |
|    3 |  6.24 |
+------+-------+

例:

WITH Sales AS (
  SELECT 123 AS sku, 1 AS day, 9.99 AS price UNION ALL
  SELECT 123, 1, 8.99 UNION ALL
  SELECT 456, 1, 4.56 UNION ALL
  SELECT 123, 2, 9.99 UNION ALL
  SELECT 789, 3, 1.00 UNION ALL
  SELECT 456, 3, 4.25 UNION ALL
  SELECT 789, 3, 0.99
)
SELECT
  sku,
  day,
  SUM(price) AS total
FROM Sales
GROUP BY ROLLUP(sku, day)
ORDER BY sku, day;

上記のクエリは、次のグループ化セットによってグループ化された行を返します。

  • sku と day
  • sku(day は NULL
  • 空のグループ化セット(day と sku が NULL

これらのグループ化セットの合計は、sku と day の組み合わせごとの合計、すべての日の各 sku の合計、および総計に対応しています。

+------+------+-------+
| sku  | day  | total |
+------+------+-------+
| NULL | NULL | 39.77 |
|  123 | NULL | 28.97 |
|  123 |    1 | 18.98 |
|  123 |    2 |  9.99 |
|  456 | NULL |  8.81 |
|  456 |    1 |  4.56 |
|  456 |    3 |  4.25 |
|  789 |    3 |  1.99 |
|  789 | NULL |  1.99 |
+------+------+-------+

HAVING 句

HAVING bool_expression

HAVING 句は、WHERE と似ています。bool_expression に照らした評価の際に TRUE を返さない行をフィルタで除外します。

WHERE 句の場合と同様、bool_expression はブール値を返す任意の式で、複数の従属条件を含めることができます。

HAVING 句は次の点で、WHERE 句と異なります。

  • HAVING 句では、クエリに GROUP BY または集計が必要です。
  • HAVING 句は、GROUP BY と集計の後、ORDER BY の前に置かれます。つまり、結果セットの集計行ごとに HAVING 句が 1 回評価されます。この点は、GROUP BY と集計の前に評価される 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;

ORDER BY 句

ORDER BY expression
  [{ ASC | DESC }]
  [{ NULLS FIRST | NULLS LAST }]
  [, ...]

ORDER BY 句は結果セットの並べ替え基準として列または式を指定します。ORDER BY 句が存在しない場合、クエリ結果の順序は定義されません。FROM 句からの列のエイリアスまたは SELECT リストを使用できます。クエリの SELECT 句にエイリアスが含まれる場合、これらのエイリアスは、対応する FROM 句の名前をオーバーライドします。

省略可能な句

  • NULLS FIRST | NULLS LAST:
    • NULLS FIRST: Null 以外の値の前に Null 値がくるように並べ替えます。
    • NULLS LAST: Null 以外の値の後に Null 値がくるように並べ替えます。
  • ASC | DESC: 結果を、expression の値の昇順または降順に並べ替えます。ASC がデフォルト値です。NULLS FIRST または NULLS LAST で Null の順序が指定されない場合は、次のように処理されます。
    • 並べ替え順序が昇順の場合、デフォルトでは NULLS FIRST が適用されます。
    • 並べ替え順序が降順の場合、デフォルトでは NULLS LAST が適用されます。

デフォルトの並べ替え順序(昇順)を使用します。

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true UNION ALL
      SELECT NULL, false)
ORDER BY x;
+------+-------+
| x    | y     |
+------+-------+
| NULL | false |
| 1    | true  |
| 9    | true  |
+------+-------+

デフォルトの並べ替え順序(昇順)を使用しますが、Null 値は最後に返します。

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true UNION ALL
      SELECT NULL, false)
ORDER BY x NULLS LAST;
+------+-------+
| x    | y     |
+------+-------+
| 1    | true  |
| 9    | true  |
| NULL | false |
+------+-------+

降順で並べ替えます。

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true UNION ALL
      SELECT NULL, false)
ORDER BY x DESC;
+------+-------+
| x    | y     |
+------+-------+
| 9    | true  |
| 1    | true  |
| NULL | false |
+------+-------+

降順の並べ替えを使用しますが、初めに Null 値を返します。

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true UNION ALL
      SELECT NULL, false)
ORDER BY x DESC NULLS FIRST;
+------+-------+
| x    | y     |
+------+-------+
| NULL | false |
| 9    | true  |
| 1    | true  |
+------+-------+

複数の列を基準にした並べ替えを行うことができます。下の例では、結果セットは最初に SchoolID で、次に LastName で並べ替えられます。

SELECT LastName, PointsScored, OpponentID
FROM PlayerStats
ORDER BY SchoolID, LastName;

以下のルールは、値を順番に並べるときに適用されます。

  • NULL: ORDER BY 句のコンテキストでは、NULL が最小可能値になります。つまり、ASC での並べ替えでは NULL が最初になり、DESC による並べ替えでは最後になります。
  • 浮動小数点データ型の場合の順序とグループ化については、浮動小数点のセマンティクスをご覧ください。

集合演算子と組み合わせて使用すると、ORDER BY 句はクエリ全体の結果セットに適用されます。最も近くにある SELECT ステートメントだけに適用されるわけではありません。このため、括弧を使用して ORDER BY の範囲を示すと便利です(ただし、必須ではありません)。

括弧なしの次のクエリがあるとします。

SELECT * FROM Roster
UNION ALL
SELECT * FROM TeamMascot
ORDER BY SchoolID;

これは、括弧ありのこのクエリと同等です。

( SELECT * FROM Roster
  UNION ALL
  SELECT * FROM TeamMascot )
ORDER BY SchoolID;

ただし、ORDER BY 句が 2 番目の SELECT ステートメントにのみ適用される次のクエリとは同等ではありません。

SELECT * FROM Roster
UNION ALL
( SELECT * FROM TeamMascot
  ORDER BY SchoolID );

ORDER BY 句では、整数リテラルを列参照として使用することもできます。整数リテラルは SELECT リストの順序となります(例: カウントは 1 から開始)。

例 - 次の 2 つのクエリは同等です。

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

WINDOW 句

WINDOW named_window_expression [, ...]

named_window_expression:
  named_window AS { named_window | ( [ window_specification ] ) }

WINDOW 句は名前付きウィンドウのリストを定義します。名前付きウィンドウは、分析関数を使用するテーブル内の行のグループを表します。名前付きウィンドウは、ウィンドウ指定で定義するか、別の名前付きウィンドウを参照することが可能です。別の名前付きウィンドウを参照している場合、参照されるウィンドウは、参照するウィンドウよりも前に定義されている必要があります。

この例では、Produce というテーブルを参照しています。どの例でもすべて同じ結果が返されます。名前付きウィンドウは、組み合わせや、分析関数の OVER 句での使用などさまざまな方法で利用できます。

SELECT item, purchases, category, LAST_VALUE(item)
  OVER (item_window) AS most_popular
FROM Produce
WINDOW item_window AS (
  PARTITION BY category
  ORDER BY purchases
  ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
SELECT item, purchases, category, LAST_VALUE(item)
  OVER (d) AS most_popular
FROM Produce
WINDOW
  a AS (PARTITION BY category),
  b AS (a ORDER BY purchases),
  c AS (b ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING),
  d AS (c)
SELECT item, purchases, category, LAST_VALUE(item)
  OVER (c ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING) AS most_popular
FROM Produce
WINDOW
  a AS (PARTITION BY category),
  b AS (a ORDER BY purchases),
  c AS b

集合演算子

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

集合演算子は、2 つ以上の入力クエリの結果を 1 つの結果セットに結合します。ALL または DISTINCT を指定する必要があります。ALL を指定する場合、すべての行が保留されます。DISTINCT が指定された場合、重複する行は廃棄されます。

指定された行 R が最初の入力クエリで正確に m 回表示され、2 番目の入力クエリで n 回表示される場合(m >= 0, n >= 0):

  • UNION ALL の場合、R は結果で正確に m + n 回表示されます。
  • UNION DISTINCT の場合、DISTINCTUNION が計算された後に計算されるため、R は正確に 1 回表示されます。
  • INTERSECT DISTINCT の場合、上記の結果が計算された後に DISTINCT が計算されます。
  • EXCEPT DISTINCT の場合、m> 0 かつ n = 0 の場合に行 R が出力に 1 回表示されます。
  • 2 つ以上の入力クエリがある場合、上記のオペレーションは概算され、出力は入力が左から右へ結合されて漸増する場合と同じになります。

以下のルールが適用されます。

  • UNION ALL 以外の set オペレーションの場合、すべての列の型で等価比較がサポートされている必要があります。
  • 演算子の左右の入力クエリが、同じ数の列を返さなければなりません。
  • 演算子は、該当する SELECT リストの列の位置に従って、各入力クエリにより返される列をペアリングします。つまり、最初の入力クエリの最初の列は、2 番目の入力クエリの最初の列とペアリングされます。
  • 結果セットは常に、最初の入力クエリの列名を使用します。
  • 結果セットは常に対応する列の入力データ型のスーパーデータ型を使用するため、ペアリングした列もまた同じデータ型であるか、共通のスーパーデータ型でなければなりません。
  • UNION ALLUNION DISTINCT などの異なる set オペレーションの処理を行う場合は、括弧を使用してそれらを区切る必要があります。ステートメントが同じ set オペレーションを繰り返すだけであれば、括弧は必要ありません。

例:

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 演算子は各クエリの結果セットの列を組み合わせて、縦方向に連結させることにより、2 つ以上の入力クエリの結果セットを結合します。

INTERSECT

INTERSECT 演算子は、左右の入力クエリの結果セットにある行を戻します。EXCEPT とは異なり、入力クエリの配置(INTERSECT 演算子の左辺と右辺)は重要ではありません。

EXCEPT

EXCEPT 演算子は、左側の入力クエリに存在し、右側の入力クエリには存在しない行を返します。

例:

SELECT * FROM UNNEST(ARRAY<int64>[1, 2, 3]) AS number
EXCEPT DISTINCT SELECT 1;

+--------+
| number |
+--------+
| 2      |
| 3      |
+--------+

LIMIT 句と OFFSET 句

LIMIT count [ OFFSET skip_rows ]

LIMIT はデータ型 INT64 の負ではない count を指定し、count を超えない行数が返されます。LIMIT 0 で返される行数は 0 です。

set オペレーションが存在する場合、set オペレーションを評価してから LIMIT が適用されます。

OFFSET は、LIMIT を適用する前にスキップする行数を示す 0 以上の数を指定します。skip_rows のデータ型は INT64 です。

これらの句はリテラルまたはパラメータの値のみを受け付けます。LIMITOFFSET により返される行は、これらの演算子が ORDER BY の後に使用されない限り、未指定になります。

例:

SELECT *
FROM UNNEST(ARRAY<STRING>['a', 'b', 'c', 'd', 'e']) AS letter
ORDER BY letter ASC LIMIT 2

+---------+
| letter  |
+---------+
| a       |
| b       |
+---------+
SELECT *
FROM UNNEST(ARRAY<STRING>['a', 'b', 'c', 'd', 'e']) AS letter
ORDER BY letter ASC LIMIT 3 OFFSET 1

+---------+
| letter  |
+---------+
| b       |
| c       |
| d       |
+---------+

WITH 句

WITH 句には 1 つ以上の名前付きサブクエリが含まれます。このサブクエリは、後続の SELECT ステートメントから参照されるたびに実行されます。WITH 句で定義するサブクエリは、任意の句またはサブクエリから参照できます。UNION などの集合演算子のいずれかの側にある任意の SELECT ステートメントが含まれます。

BigQuery は WITH 句内のクエリの結果を実体化しないため、読みやすくするために WITH 句は便利です。1 つのクエリが複数の WITH 句に含まれている場合、そのクエリは各句でそれぞれ実行されます。

例:

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

ネストされたテーブルのサブクエリの記述が代替方法として最適ではない場合、WITH を使用してより複雑なクエリを WITH SELECT ステートメントと WITH 句に分割できます。例:

WITH q1 AS (my_query)
SELECT *
FROM
  (WITH q2 AS (SELECT * FROM q1) SELECT * FROM q2)

WITH 句のスコープルールは以下のとおりです。

  • エイリアスは、WITH 句に使用されたエイリアスが、同じ WITH 句の後のサブクエリと、WITH 句の下のクエリにのみ表示されるように範囲を指定します。
  • 同じ WITH 句に使用されたエイリアスは一意にする必要がありますが、同じクエリの複数の WITH 句で同じエイリアスを使用できます。ローカル エイリアスは、このエイリアスが表示される外側のエイリアスをすべてオーバーライドします。
  • WITH 句でエイリアスを設定したサブクエリに相関関係はありません。クエリ外部からの列は表示されません。外部からのもので表示される名前は、同じ WITH 句で先に使用された他の WITH エイリアスのみです。

以下に、WITH サブクエリでエイリアスを使用するステートメントの例を示します。

WITH q1 AS (my_query)
SELECT *
FROM
  (WITH q2 AS (SELECT * FROM q1),  # q1 resolves to my_query
        q3 AS (SELECT * FROM q1),  # q1 resolves to my_query
        q1 AS (SELECT * FROM q1),  # q1 (in the query) resolves to my_query
        q4 AS (SELECT * FROM q1)   # q1 resolves to the WITH subquery
                                   # on the previous line.
    SELECT * FROM q1)  # q1 resolves to the third inner WITH subquery.

WITH RECURSIVE はサポートされていません。

エイリアスの使用

エイリアスはクエリで示されるテーブル、列、または式に対して与えられる一時的な名前です。SELECT リストまたは FROM 句のいずれかで、明示的エイリアスを使用できます。あるいは BigQuery は一部の式に対する暗黙的なエイリアスを推測します。明示的なエイリアスも暗黙のエイリアスもない式は匿名であり、クエリではこれらを名前で参照できません。

明示的なエイリアス

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

FROM 句では、[AS] alias を使用してテーブル、配列、サブクエリ、UNNEST 句を含む項目の明示的なエイリアスを使用できます。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;

暗黙のエイリアス

SELECT リストに明示的エイリアスが指定されていない式がある場合、BigQuery は次のルールに従って暗黙的エイリアスを割り当てます。このルールによって、SELECT リストで複数の列に同じエイリアスが割り当てられる場合があります。

  • 識別子の場合、エイリアスは識別子です。たとえば、SELECT abcAS abc を含意します。
  • パス式の場合、エイリアスはパスの最後の識別子です。たとえば、SELECT abc.def.ghiAS ghi を含意します。
  • 「ドット」メンバー フィールド アクセス演算子を使用するフィールド アクセスの場合、エイリアスはフィールド名になります。たとえば、SELECT (struct_function()).fnameAS fname を含意します。

他のすべての事例では暗黙のエイリアスはないので、列は匿名で、名前では参照できません。その列からのデータは引き続き返され、表示されるクエリの結果にはその列に対して生成されたラベルがある場合がありますが、ラベルはエイリアスのようには使用できません。

FROM 句では、from_item はエイリアスが必要なわけではありません。以下のルールが適用されます。

  • 明示的エイリアスが指定されていない式では、BigQuery によって暗黙的エイリアスが以下のように割り当てられます。
    • 識別子の場合、エイリアスは識別子です。たとえば、FROM abcAS abc を含意します。
    • パス式の場合、エイリアスはパスの最後の識別子です。たとえば、FROM abc.def.ghiAS ghi を含意します。
    • WITH OFFSET を使用して生成された列には、暗黙のエイリアス offset があります。
  • テーブルのサブクエリに、暗黙のエイリアスはありません。
  • FROM UNNEST(x) に暗黙のエイリアスはありません。

エイリアスの可視性

クエリに明示的エイリアスを使用した場合、そのエイリアスを参照できるクエリの他の場所について制限があります。エイリアスの可視性に対するこれらの制限は、BigQuery の名前範囲のルールの結果です。

FROM 句の可視性

BigQuery は 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;

FROM 句に明示的なエイリアスが含まれている場合、そのクエリの他の部分では暗黙のエイリアスではなく、明示的なエイリアスを使用する必要があります(暗黙のエイリアスを参照)。テーブル エイリアスは、クエリ処理中に同じテーブルが複数回スキャンされる自己結合の場合などに、簡潔さの実現や曖昧さの排除に役立ちます。

例:

SELECT * FROM Singers as s, Songs as s2
ORDER BY s.LastName

無効 - ORDER BY では、テーブル エイリアスは使用されません。

SELECT * FROM Singers as s, Songs as s2
ORDER BY Singers.LastName;  // INVALID.

SELECT リストの可視性

SELECT リスト内のエイリアスは、次の句でのみ認識されます。

  • GROUP BY
  • ORDER BY
  • HAVING

例:

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

GROUP BY、ORDER BY、HAVING 句の可視性

GROUP BYORDER BYHAVING の 3 つの句は、以下の値のみを参照できます。

  • FROM 句のテーブルとその列。
  • SELECT リストのエイリアス。

GROUP BYORDER BY は、3 番目のグループも参照できます。

  • 整数リテラル。これは、SELECT リストの項目を参照します。整数 1 は、SELECT リストの最初の項目、2 は 2 番目の項目を参照、などとなります。

例:

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

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

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

重複するエイリアス

SELECT リストまたはサブクエリに複数の明示的なエイリアスまたは暗黙のエイリアスを同じ名前で追加できますが、エイリアス名がクエリの任意の場所で参照されている場合は参照が曖昧になるため、このような処理はできません。

最上位の SELECT リストに重複する列名が含まれていて、宛先テーブルが指定されていない場合、最初の列を除き、重複する列の名前が自動的に変更され、一意になります。変更後の列名がクエリ結果に表示されます。

例:

SELECT 1 AS a, 2 AS a;

+---+-----+
| a | a_1 |
+---+-----+
| 1 | 2   |
+---+-----+

テーブルまたはビュー定義で列名の重複はサポートされていません。クエリで重複する列名を含むステートメントを使用すると失敗します。

CREATE TABLE my_dataset.my_table AS (SELECT 1 AS a, 2 AS a);
CREATE VIEW my_dataset.my_view AS (SELECT 1 AS a, 2 AS a);

曖昧なエイリアス

BigQuery では曖昧な名前の参照はエラーになります。つまり、クエリまたはテーブル スキーマ(複数の宛先テーブルを含む)で一意の複数のオブジェクトに解決できる場合、エラーが発生します。

例:

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

SELECT SingerID
FROM Singers, Songs;

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

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

このクエリでは、名前が重複しているため、SELECT のリストと FROM 句のエイリアスが曖昧になります。table に列 xyz があるとします。z は STRUCT 型で、フィールドは vwx です。

例:

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

エイリアス T が曖昧なためエラーを生成します。これは、GROUP BY 句の T.xtable.xtable.z.x のどちらも参照する可能性があるためです。

基礎となる同じオブジェクトでその名前を解決できる場合、列名と SELECT リストのエイリアスの両方で特定の名前が使用されていても、GROUP BYORDER BYHAVING でその名前は曖昧とはなりません

例:

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

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

暗黙のエイリアス

SELECT リストに明示的エイリアスが指定されていない式がある場合、BigQuery は次のルールに従って暗黙的エイリアスを割り当てます。このルールによって、SELECT リストで複数の列に同じエイリアスが割り当てられる場合があります。

  • 識別子の場合、エイリアスは識別子です。たとえば、SELECT abcAS abc を含意します。
  • パス式の場合、エイリアスはパスの最後の識別子です。たとえば、SELECT abc.def.ghiAS ghi を含意します。
  • 「ドット」メンバー フィールド アクセス演算子を使用するフィールド アクセスの場合、エイリアスはフィールド名になります。たとえば、SELECT (struct_function()).fnameAS fname を含意します。

他のすべての事例では暗黙のエイリアスはないので、列は匿名で、名前では参照できません。その列からのデータは引き続き返され、表示されるクエリの結果にはその列に対して生成されたラベルがある場合がありますが、ラベルはエイリアスのようには使用できません。

FROM 句では、from_item はエイリアスが必要なわけではありません。以下のルールが適用されます。

  • 明示的エイリアスが指定されていない式では、BigQuery によって暗黙的エイリアスが以下のように割り当てられます。
    • 識別子の場合、エイリアスは識別子です。たとえば、FROM abcAS abc を含意します。
    • パス式の場合、エイリアスはパスの最後の識別子です。たとえば、FROM abc.def.ghiAS ghi を含意します。
    • WITH OFFSET を使用して生成された列には、暗黙のエイリアス offset があります。
  • テーブルのサブクエリに、暗黙のエイリアスはありません。
  • FROM UNNEST(x) に暗黙のエイリアスはありません。

範囲変数

BigQuery での範囲変数とは、FROM 句のテーブル式のエイリアスのことです。範囲変数は、table alias と呼ばれることもあります。範囲変数を使用すると、テーブル式からスキャンされた行を参照できます。テーブル式は、テーブルを返す FROM 句の項目を表します。この式で表せる一般的な項目には、値テーブルサブクエリ結合括弧で囲まれた結合があります。

一般に、範囲変数は、テーブル式の行への参照を提供します。範囲変数は、列参照の限定や、関連テーブルを明確に識別するために使用されます。たとえば range_variable.column_1 のようにします。

特定の列サフィックスを含まない範囲変数を単独で参照する場合、テーブル式の結果は関連テーブルの行の型になります。値テーブルには明示的な行の型があるため、値テーブルに関連する範囲変数の場合、結果の型は値テーブルの行の型になります。他のテーブルに明示的な行の型はありません。それらのテーブルの範囲変数は、テーブルのすべての列を含む動的に定義された STRUCT 型になります。

以下の例では、Grid 句という一時テーブルのエミュレートに WITH 句を使用しています。このテーブルには x 列と y 列があります。テーブルがスキャンされる際、範囲変数の Coordinate が現在行を指します。Coordinate を使用すると、行全体またはその行の複数列にアクセスできます。

次の例では、列 x を範囲変数 Coordinate から選択することで、実際にはテーブル Grid の列 x を選択しています。

WITH Grid AS (SELECT 1 x, 2 y)
SELECT Coordinate.x FROM Grid AS Coordinate;

+---+
| x |
+---+
| 1 |
+---+

次の例では、範囲変数 Coordinate からすべての列を選択することで、実際にはテーブル Grid のすべての列を選択しています。

WITH Grid AS (SELECT 1 x, 2 y)
SELECT Coordinate.* FROM Grid AS Coordinate;

+---+---+
| x | y |
+---+---+
| 1 | 2 |
+---+---+

次の例では、範囲変数 Coordinate を選択します。これは、テーブル Grid 内の行への参照になります。Grid は、値テーブルではないため、Coordinate の結果の型は、Grid のすべての列を含む STRUCT になります。

WITH Grid AS (SELECT 1 x, 2 y)
SELECT Coordinate FROM Grid AS Coordinate;

+--------------+
| Coordinate   |
+--------------+
| {x: 1, y: 2} |
+--------------+

付録 A: 例とサンプルデータ

Roster テーブル、TeamMascot テーブル、PlayerStats テーブルに対してクエリを実行するステートメントの例を以下に示します。

GROUP BY 句

例:

SELECT LastName, SUM(PointsScored)
FROM PlayerStats
GROUP BY LastName;
LastName SUM
Adams 7
Buchanan 13
Coolidge 1

UNION

UNION 演算子は各 SELECT ステートメントの結果セットの列をペアリングし、縦方向に連結させることにより、2 つ以上の SELECT ステートメントの結果セットを結合します。

例:

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

結果:

X Y
Jaguars 50
Knights 51
Lakers 52
Mustangs 53
Adams 3
Buchanan 0
Coolidge 1
Adams 4
Buchanan 13

INTERSECT

このクエリは、Roster と PlayerStats の両方に存在する姓を返します。

SELECT LastName
FROM Roster
INTERSECT DISTINCT
SELECT LastName
FROM PlayerStats;

結果:

LastName
Adams
Coolidge
Buchanan

EXCEPT

次のクエリは、PlayerStats に存在していない Roster の姓を返します。

SELECT LastName
FROM Roster
EXCEPT DISTINCT
SELECT LastName
FROM PlayerStats;

結果:

LastName
Eisenhower
Davis

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

SELECT LastName
FROM PlayerStats
EXCEPT DISTINCT
SELECT LastName
FROM Roster;

結果:

(empty)