BigQueryのSQLいろいろ (3) 日付・時刻型 | Wantedly Engineer Blog
BigQueryのSQLについて、ドキュメントを読んだり実験したりしながら挙動を解き明かしていこうと思います。第3回は日付・時刻型についてです。今回扱う型TIMESTAMPDATETIMEDAT...
https://www.wantedly.com/companies/wantedly/post_articles/1011069
Photo by Nick Fewings on Unsplash
BigQueryのSQLについて、ドキュメントを読んだり実験したりしながら挙動を解き明かしていこうと思います。第4回はARRAYとSTRUCTについて紹介します。
ARRAY型は決まった要素型をもつ可変長の配列です。たとえば ARRAY<INT64> は整数の配列を意味します。
これだけで済むなら話は簡単なのですが、ARRAY型の意味論を考えるにあたっては以下の制約が重要になります。
ARRAYをARRAYの要素型にすることはできません。したがって、 ARRAY<ARRAY<INT64>> は無効です。
ただし、間にSTRUCTを挟んで ARRAY<STRUCT<ARRAY<INT64>>> とすることはできるため、表現力の観点からはARRAYのネストは可能ともみなせます。
ARRAYの振舞いは以下の2つの場合により大きく異なります。
クエリ処理時は以下のように振舞います。
いっぽう、テーブルへの保存時は以下のように振舞います。
SELECT [NULL] -- Error
SELECT [NULL][OFFSET(0)] -- NULLSELECT
-- []
CASE WHEN TRUE THEN [] END,
-- []
CASE WHEN FALSE THEN [] END,
-- FALSE
CASE WHEN TRUE THEN [] END IS NULL,
-- TRUE
CASE WHEN FALSE THEN [] END IS NULL第1回〜第3回まででうすうす察していた方もいると思いますが、ここまでで紹介した BigQuery の型は、どことなく Protocol Buffers っぽい感じがあります。その印象が最も強く残るのが、この ARRAY 型の制約です。私は BigQuery の内部構造について知っているわけではないですが、テーブルが Protocol Buffers の Wire Format で保存されているとしたら色々なところに納得がいきます。
要素を書き下すには [1, 2, 3] のように書くか、型を明示して ARRAY<INT64>[1, 2, 3] のように書きます。
規則的な配列は GENERATE_ARRAY やその亜種で生成できます。
クエリから配列を作るには、 Array subquery を使って ARRAY(SELECT ...) のように書くか、 ARRAY_AGG を使います。
添字アクセスは array[1] のように行いますが、添字の種類を明示して array[OFFSET(1)] のように書くこともできます。添字の種類として以下の4種類があります。
さらに頻出なのは、 UNNEST() で直接クエリの対象にする方法です。
STRUCT型は、端的に言うとタプルです。つまり、決まった長さをもち、それぞれの要素が独立に型を持ちます。
STRUCT型では、各要素に名前をつけることもできます。しかし、基本的な振舞いとしては順序対として考えたほうが自然です。名前はあくまでも「おまけ」です。
STRUCT型は STRUCT<INT64, STRING> のように、要素型を順に並べて表記します。要素に名前をつけるときは STRUCT<n INT64, STRING, x FLOAT64> のように、名前を前置します。
STRUCT型の制約は以下の通りです。
STRUCT型は、要素の名前を変えても互換性のある型として扱われます。いっぽう、要素の順番を変えると互換性がありません。原則として、手前側の式に由来する STRUCT 型の要素名がそのまま使われます。
-- OK (x, y として扱われる)
SELECT STRUCT(1 AS x, 'foo' AS y)
UNION ALL
SELECT STRUCT(2 AS y, 'bar' AS x)
-- Error
SELECT STRUCT(1 AS x, 'foo' AS y)
UNION ALL
SELECT STRUCT('bar' AS y, 2 AS x)要素を書き下すには以下のいずれかの記法を用います。
また、 SELECT AS STRUCT を使うことでも STRUCT を生成できます。
STRUCT では、 ARRAY と同じ添字記法が使えます。ただし、インデックスは数値リテラルである必要があります。 s[1] はできても s[i] はできません。
STRUCT の要素に名前がついている場合は、ドット記法でも要素にアクセスできます。ただし、同じ名前の要素が2つあるときは、その名前でアクセスすることはできません。
また、 UNNEST() の特別なルールとして、 ARRAY<STRUCT> を対象に UNNEST した場合は、 STRUCT の内容が行として展開されます。このとき、要素に名前があればその名前で列にアクセスできます。
BigQueryでは、一部の型に型強制関係があります。たとえば以下の例では INT64 → FLOAT64 への型強制が発生しています。
SELECT 1 -- 1.0 に型強制される
UNION ALL
SELECT 1.5しかし、 ARRAY, STRUCT はこの型強制関係に対して非変 (invariant) に振舞います。 (原理的には共変に振舞えるにもかかわらず)
-- Error
SELECT [1]
UNION ALL
SELECT [1.5]ARRAY, STRUCT の比較処理のほとんどは禁止されています。
例外的に、以下のみ許されています。
これらの2つのケースでは、長さと各位置の要素が再帰的に比較されます。また、グルーピングの性質上、 NULL 同士は等しいものとみなされます。
BigQueryの以下の型について、細部の振舞いに注意しながら紹介しました。