💻

BigQuery Scriptingを使ってデータセット内のテーブルにループ処理を行う

 
 
BigQueryのあるデータセット内の全テーブルに対して、同じ処理を行いたいときに、BigQuery Scriptingを使うとループ処理を実行することができます。
 
▼BigQuery Scripting(和訳は手続き型言語というらしい)
 
 
最終的なクエリ
 
 

シチュエーション

 
あるデータセット()内に、
 
 
  • table_a
  • table_b
  • table_c
  • ….
  • table_z
 
 
のように、a~zまでの26個のテーブルがあったとします。
 
 
そのうち、2022年1月1日に作られたレコードだけを各テーブルから抜き出して、1つのテーブルにまとめたい状況があったとします。
 
を使用して、全てのテーブルを縦に連結すれば実現可能ですが、
 
 
  • クエリが長くなる
  • table名を1つ1つ入力しなければいけない
  • tableが増減した際にクエリを修正しなければならない
 
 
 
のような問題があり、ループ処理が適している場面と言えるでしょう。
 
 

BigQuery Scriptingによるループ処理

 
冒頭の公式ドキュメントを見ると、BigQuery Scriptingには色々なループ処理の記法が存在します。LOOP, REPEAT, WHILE, FOR…INなど、他のプログラミング言語でも見られるロジックがあります。
 
今回のシチュエーションでは、データセット内のテーブル一覧を抜き出して、その要素1つ1つに対して処理を実行していくので、FOR…INループが適していると思います。
 
FOR…INループのサンプルクエリは以下のような感じです。
 
基本的には、Pythonのループと同じですが、の後にから始まる一連のクエリを書くことができ、その実行結果を1レコードずつループして処理を実行していくことができます。
 
1レコードずつ実行したい処理は、 の後に記述し、この例だと、, の2列を 句で抽出しているだけということになります。
 
それでは、ループを使って、ループ処理を書いていきます。
 
 
 

アルゴリズムの全体像

 
 
アルゴリズムの全体像は以下の通りです。
 
 
ポイントは3つで、
 
  1. データセットからテーブル名一覧を取得する
  1. ループ処理で、各テーブルから対象データを抽出する
  1. 結果をひとつのテーブルに格納する
 
という流れになっています。
 
 
それでは、順にみていきましょう。
 
 
 

1. データセット内のテーブル名一覧を取得する

 
まず、「処理を行いたいテーブル名のリスト」を取得していきます。
 
あるデータセット内のテーブル名の一覧は、BigQuery INFORMATION_SCHEMA を用いて取得することが可能です。
 
このうち、TABLESというINFORMATION_SCHEMAビューを使用すると、デートセット内のテーブル名のリストを簡単に取得することができます。
 
 
 

2. 1テーブルずつクエリを実行する

 
次に、前のステップで抽出したテーブル名を1つずつ取得して、各テーブルに対してクエリを実行する処理を書きます。
 
しかし、テーブル名を変数で渡して、句で受け取る際には、以下のようにひと手間加える必要があります。
 
 
の後に という記述をしています。
 
これは、EXECUTE IMMEDIATEというBigQuery Scriptingの一種と、format関数を組み合わせたものです。
 
かなりざっくりと説明すると、
 
  • format関数で、変数として渡されるテーブル名を文字列にマッピングする
  • で、文字列で記述されたSQLを実行する
 
という処理を、各ループで行っています。
 
 
これにより、 内の各テーブルに対して、2022年1月1日のレコードだけを抽出するという処理がループ処理で実行できます。
 
 

3. 結果をひとつのテーブルにまとめる

 
前のステップまでで、クエリ実行自体はループ処理が可能になりました。
しかし、実行結果は別々のジョブとして実行され、別々のテーブルとして吐き出されています。最後にこれをひとつのテーブルにまとめる処理を追加したいと思います。
 
その処理を追加したものが以下のクエリになります。
 
 
変更点としては、
 
  1. でクエリを実行した結果を、一時テーブルとして保持する
  1. if文を使い、1回目のループは結果テーブルの作成、2回目以降は結果の を行う
 
という処理を追加しています。
 
これで、各ループで各テーブルに対してクエリを実行した結果を、ひとつのテーブル()に格納することができます。
 
 
 

参考

この記事を書くにあたり、以下の記事を参考にさせて頂きました。
BigQuery Scriptingの便利な使い方をまとめてみた - yasuhisa's blog
自分自身はこれまでBigQuery Scriptingをほぼ使っていませんでした BigQuery自体は3年くらいの利用歴 SQL単発で済ませるのが苦しそうな場合は、Pythonなどのプログラミング言語 + ワークフローエンジンの組み合わせで戦っており、自分としては特に困っていなかった 社内で他の方が使うケースをぼちぼち見ることがある 自分は困っていなくても、社内のBigQueryユーザーでBigQuery Scriptingを使っていて困っている人がそれなりにいる 著者はそれなりのBigQueryユーザーがいる企業のデータ基盤の人間です さすがに「使ったことないので、分からないですねー」で済ませるわけにはいかなくなってきた そもそもどんなユースケースで便利なのかすらも分かっていない状態なので、便利そうに思える場合をまとめてみることにしました というわけで、もっといい例などがあるかもしれないので、その辺は差し引いて読んでください...。むしろコメントなどで教えてください Syntaxの説明などはしないので、公式リファレンスを読んでください。便利そうな実例重視で書いてます BigQueryの普通のクエリは単一のSQLのステートメントです。1000行あろうが、 WITH 句のようなCTEがあったとしても単一のSQLです。BigQuery Scriptingは複数のSQLのステートメントの集合を一つのリクエストで実行できる機能です。 SELECT 句のみからなる複数のSQLを扱っていると何がうれしいかピンときませんが、例えばこういった処理は単一のリクエストで処理できるとうれしい場合があります。 SQLで中間テーブルA, B, Cを作る A, B, CをJOINしてテーブルDを作る テーブルDをテーブルEにマージする 例: 累積で結果を溜めているテーブルEに今日の分の統計量のDをマージする 不要になったテーブルA, B, Cを削除 単純にSQLを上から下に実行していくだけではなく、BigQuery Scriptingは以下のようなもっと高度な機能を提供しています。 テーブルの作成などのDDL BigQueryのDDLは色々充実していて、なぜかスロットの購入までサポートされている*1、権限付与もできてしまう WHILEやIFなどの制御構文が使える例: INFORMATION_SCHEMAなどの結果を受け取って、ループで後続のSQLを実行する 変数が扱える BigQuery Scriptingでなくとも、@paramのような形でパラメータを渡すこと自体はできます が、BigQuery Scriptingで扱える変数はもう少し強力で、例えばテーブル名を変数にできます 型が扱えます、BEGINとENDで変数のスコープを狭めることができます 動的にSQLを組み立てて(EXECUTE IMMEDIATE)実行できますWHERE句の条件を制御構文を使ってガシガシ作っていく、など トランザクションが使えます 単体で見ていてもイメージが分かないことも多いので、例を見ていきましょう。 BigQueryに限らずビューは便利ですが、多段のビューになると Resources exceeded during query execution: Not enough resources for query planning - too many subqueries or query is too complexというエラーでクエリが実行できないことがたまにあります。 WITH句を多用していたり、ビューの多段が10個近くになってくるとこのエラーがよく発生することが多いです*2 。 分析できないのは困るので、ビューのどこかをテーブル化して回避することが多いと思います。テーブル化は便利ではあるのですが中間テーブル自体は不要であり、集計後には消すこともセットで考えたいです。さもないとデータセットがゴミ屋敷になってしまいます...。しかし「何かの処理が終わった後にこのテーブルを消す」というのはそれなりに面倒なものです。Airflowのようなワークフローエンジンを使えば済みますが、SQLを動かしている分析チームにそういったワークフローエンジンをメンテナンスする工数がないということもあるでしょう。 そういった場合に便利なのがBigQuery Scriptingの機能の一つである 一時テーブルです。 CREATE TEMP TABLE を使ってテーブル化すると テーブルを元に後段のクエリを書けるため、too many subqueries or query