Google Spreadsheetの1枚目シートをBigQueryの外部テーブルにする

社内の同テンプレのスプレッドシートまとめるのこれでやると楽だったのでメモ。

#!/bin/bash

SCHEMA=date:DATE,id:STRING,description:STRING
URL=https://docs.google.com/spreadsheets/hoge/fuga
PRJ=myproject
DS=mydataset
TBL=mytable

bq mk --external_table_definition=${SCHEMA}@GOOGLE_SHEETS=${URL} ${PRJ}:${DS}.${TBL}

データセットは先に作っておかないと怒られる。
しかしこの方法はシート1枚目しか対応してない仕様。

複数シートも扱うならAppsScriptでBQのネイティブテーブル直接作るしかない。
外部テーブルじゃないけどさ。

function main() {
  var projectId = 'myproject';
  var datasetId = 'mydataset';

  var app = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = app.getActiveSheet();
  var tableId = sheet.getSheetName();
  
  var table = {
    tableReference: {
      projectId: projectId,
      datasetId: datasetId,
      tableId: tableId
    },
    schema: {
      fields: [
        {name: 'date', type: 'date'},
        {name: 'id', type: 'string'},
        {name: 'description', type: 'string'}
      ]
    }
  };
  try{
    BigQuery.Tables.remove(projectId, datasetId, tableId); 
  } catch(e) {}
  table = BigQuery.Tables.insert(table, projectId, datasetId);
  
  var range = sheet.getDataRange();
  var blob = Utilities.newBlob(convCsv(range)).setContentType('application/octet-stream');
  var job = {
    configuration: {
      load: {
        destinationTable: {
          projectId: projectId,
          datasetId: datasetId,
          tableId: tableId
        },
        skipLeadingRows: 1
      }
    }
  };
  job = BigQuery.Jobs.insert(job, projectId, blob);
}

function convCsv(range) {
  try {
    var data = range.getValues();
    var ret = "";
    if (data.length > 1) {
      var csv = "";
      for (var i = 0; i < data.length; i++) {
        for (var j = 0; j < data[i].length; j++) {
          if (data[i][j].toString().indexOf(",") != -1) {
            data[i][j] = "\"" + data[i][j] + "\"";
          }
        }
        if (i < data.length-1) {
          csv += data[i].join(",") + "\r\n";
        } else {
          csv += data[i];
        }
      }
      ret = csv;
    }
    return ret;
  }
  catch(e) {
    Logger.log(e);
  }
}