Upgrade to Pro — share decks privately, control downloads, hide ads and more …

BigQuery MERGEクエリを生成してくれるCLIを作成した話

Yuu Ito
February 26, 2022

BigQuery MERGEクエリを生成してくれるCLIを作成した話

Yuu Ito

February 26, 2022
Tweet

More Decks by Yuu Ito

Other Decks in Technology

Transcript

  1. 自己紹介 Yuu ITO Github ID: u110 Twitter ID: yuu_ito Web

    / Data Engineer 2021.03 ~ 長野県塩尻市 職場は東京なので、フルリモ ート(そろそろ2年目) trocco というETLサービスを運営 する会社で、 開発したり、実際にtroccoを使っ た仕事しています。
  2. MERGEの使いかた例 初回のデータ取り込みはBigQueryに全件転送 ex) select * from users BigQuery (users) id

    name favorites created_at updated_at 1 taro Ruby, SQL 2021/01/01 2022/02/01 2 jiro Java 2021/01/02 2022/02/10
  3. MERGEの使いかた例 Webサービスを介して、以下のように追加と更新があった場合 DB (users) id name favorites created_at updated_at 1

    taro Ruby, SQL 2021/01/01 2022/02/01 2 jiro Java, Python 2021/01/02 2022/02/26 3 saburo Python, SQL 2022/02/26 2022/02/26
  4. MERGEの使いかた例 updated_at を基準にフィルタしたものを一時テーブルに抽出する ex) select * from users where updated_at

    >= '2022/02/26' BigQuery (tmp_users) id name favorites created_at updated_at 2 jiro Java, Python 2021/01/02 2022/02/26 3 saburo Python, SQL 2022/02/26 2022/02/26
  5. MERGEの使いかた例 BigQuery上の、users、tmp_usersを使ってMERGEクエリを書く場合は以下のようにな る。 MERGE `dataset.users` target USING `dataset.tmp_users` tmp ON

    (target.id = tmp.id) WHEN MATCHED and target.updated_at < tmp.updated_at THEN UPDATE SET target.name = tmp.name, target.favorites = tmp.favorites, target.updated_at = tmp.updated_at WHEN NOT MATCHED THEN INSERT ROW ;
  6. コード require "genbqq" require "google/cloud/bigquery" require "thor" module GenBqq class

    CLI < Thor desc "merge {project.dataset.table}", "generate merge sql template from BigQuery table" def merge(full_table_str) prj, dataset, tbl = full_table_str.split "." puts "-- project: #{prj}" puts "-- dataset: #{dataset}" puts "-- table: #{tbl}" bq = Google::Cloud::Bigquery.new project: prj target_tbl = bq.dataset(dataset).table(tbl) # puts target_tbl.headers cols_str = target_tbl.headers.map{|col| " target.#{col} = tmp.#{col}"}.join(",\n") result = <<-EOQ MERGE `#{full_table_str}` target USING `#{full_table_str}_tmp` tmp ON(target.id = tmp.id) WHEN MATCHED AND target.updated_at < tmp.updated_at THEN -- id が一致かつ、更新日時が増えている場合は行を更新する UPDATE SET -- 更新対象としたいカラムをすべて記述する #{cols_str} WHEN NOT MATCHED THEN -- 不一致 = 新規行として判断し、追加する INSERT ROW EOQ puts result end end end
  7. デモ $ genbqq Commands: genbqq help [COMMAND] # Describe available

    commands or one specific command genbqq merge {project.dataset.table} # generate merge sql template from BigQuery table
  8. デモ $ BIGQUERY_CREDENTIALS=/path/to/credentials.json genbqq merge web-u-project.sample_dataset.many_cols_tbl -- project: web-u-project --

    dataset: sample_dataset -- table: many_cols_tbl MERGE `web-u-project.sample_dataset.many_cols_tbl` target USING `web-u-project.sample_dataset.many_cols_tbl_tmp` tmp ON(target.id = tmp.id) WHEN MATCHED AND target.updated_at < tmp.updated_at THEN -- id が一致かつ、更新日時が増えている場合は行を更新する UPDATE SET -- 更新対象としたいカラムをすべて記述する target.id = tmp.id, ... -- ここにたくさんカラム名が記載される target.created_at = tmp.created_at, target.updated_at = tmp.updated_at WHEN NOT MATCHED THEN -- 不一致 = 新規行として判断し、追加する INSERT ROW
  9. デモ Billing has not been enabled for this project. Enable

    billing at https://console.cloud.google.com/billing. DML queries are not allowed in the free tier. Set up a billing account to remove this restriction. なんと、無料枠だとDMLが記述できなかった。。