【BigQuery】bqコマンド チートシート

# はじめに
チームでBigQueryをシステムに導入しようとなり、本格的に向き合うことになりそうなので一通りbqコマンドを触ってみようと思います。

以前書いた記事では、レガシーな使い方をしていたりしたのでアップデートしたいと思います。
[【BigQuery】知っておくと便利なbqコマンドのオプション【GCP】【bq】](https://qiita.com/chan-p/items/441308e6ac90c1f6b0ca)

# チートシート
前提として下記の情報を使っています。

* データセット名：data_qiita
* サービスアカウント名：test@[Project名].iam.gserviceaccount.com
* 暗号鍵名：projects/[Project名]/locations/asia-northeast1/keyRings/[KeyRing名]/cryptoKeys/[Key名]
* ロケーション：asia-northeast1

## bqの省略

```
$ bq shell
Welcome to BigQuery! (Type help for more information.)
[プロジェクト名]>select * from data_qiita.test_202007
```

## データセット/テーブルの一覧表示
```
$ bq ls
  datasetId  
 ----------- 
  data_qiita   
  g90001
```

```
$ bq ls data_qiita
    tableId     Type    Labels   Time Partitioning   Clustered Fields  
 ------------- ------- -------- ------------------- ------------------ 
  test_202006   TABLE                                                  
  test_202007   TABLE  
```

### -n 
* デフォルトで50行くらいが制限になっているため、このオプションでさらに表示を増やせる

```
$bq ls -n 1000 data_qiita
    tableId     Type    Labels   Time Partitioning   Clustered Fields  
 ------------- ------- -------- ------------------- ------------------ 
  test_20200601   TABLE
    ・・・・・                                                  
  test_20201031   TABLE
```  

## ジョブ履歴の表示

```
$ bq ls --jobs
                    jobId                      Job Type    State      Start Time         Duration     
 -------------------------------------------- ---------- --------- ----------------- ---------------- 
  bqjob_r350795b155d507d6_0000017395de7f89_1   load       SUCCESS   28 Jul 14:40:54   0:00:03.013000  
  bqjob_r2228f453d05a1384_000001739589af1a_1   extract    SUCCESS   28 Jul 13:08:15   0:00:03.866000  
  bqjob_r1f064a9ce743da3f_000001739589a25d_1   query      SUCCESS   28 Jul 13:08:12   0:00:00.240000  
  bqjob_r7acf7abdad16d904_000001739589961a_1   query      SUCCESS   28 Jul 13:08:09   0:00:00.185000 
```

## ジョブの詳細履歴の表示
```
$ bq show --job [Project名]:asia-northeast1.[jobID]
Job [Project名]:asia-northeast1.[jobID]

  Job Type    State      Start Time         Duration                           User Email                        Bytes Processed   Bytes Billed   Billing Tier   Labels  
 ---------- --------- ----------------- ---------------- ------------------------------------------------------ ----------------- -------------- -------------- -------- 
  load       SUCCESS   28 Jul 14:40:54   0:00:03.013000   test@[Project名].iam.gserviceaccount.com    
```


## データセットを作成
```
$ bq mk --dataset --location=asia-northeast1 data_qiita
Dataset '[Project名]:data_qiita' successfully created.
```

###  --use_legacy_sql=false
* 作成したデータセット配下のテーブルでデフォルトがstadardSQLになる

### --default_kms_key
* 指定した鍵でデータが暗号化される

```
$ bq mk --dataset --location=asia-northeast1 \
  --use_legacy_sql=false \
  --default_kms_key=projects/[Project名]/locations/asia-northeast1/keyRings/[KeyRing名]/cryptoKeys/[Key名] 
　data_qiita
Dataset '[Project名]:data_qiita' successfully created.
```

### --force
* 同一名のデータセットがすでに存在していてもエラーにならない

```
$ bq mk --dataset data_qiita
BigQuery error in mk operation: Dataset '[Project名]:data_qiita' already exists.
$ bq mk --dataset --force data_qiita
Dataset '[Project名]:data_qiita' already exists.
```

## 空のテーブルの作成

```
$ bq mk --table --location=asia-northeast1 data_qiita.test_202008
Table '[Project名]:data_qiita.test_202008' successfully created.
```

### --schema
* スキーマを定義したファイルを指定してテーブル作成

```
$ bq mk --table --location=asia-northeast1 --schema=schema.json data_qiita.test_202009
Table '[Project名]:data_qiita.test_202009' successfully created.
```

```schema.json
[
  {
    "description":"",
    "name":"key",
    "type":"INTEGER",
    "mode":""
  },
  {
    "description":"",
    "name":"word",
    "type":"STRING",
    "mode":""
  }
]
```

## データをロード
```
bq load --source_format=AVRO data_qiita.test_202010 gs://qiita/[ファイルパス]
```

### --autodetect
* 読み込みファイルから自動でスキーマも読み込む

```
bq load --source_format=CSV --autodetect data_qiita.test_202010 gs://qiita/[ファイルパス].csv
```

### --replace
* テーブル構造をそのものを上書きしてロードする

```
bq load --source_format=CSV --replace data_qiita.test_202010 gs://qiita/[ファイルパス].csv
```

### --schema_update_option=ALLOW_FIELD_ADDITION
* ロードする際にテーブル構造が変わっても自動でカラムを追加してロードする

```
bq load --source_format=CSV --schema_update_option=ALLOW_FIELD_ADDITION data_qiita.test_202010 gs://qiita/[ファイルパス].csv
```

## データセットのメタデータを表示
```
$ bq show data_qiita
Dataset [Project名]:data_qiita

   Last modified                             ACLs                             Labels                                                      kmsKeyName                                                      
 ----------------- --------------------------------------------------------- -------- ------------------------------------------------------------------------------------------------------------------- 
  28 Jul 13:17:13   Owners:                                                            projects/{Project名}/locations/asia-northeast1/keyRings/[KeyRing名]/cryptoKeys/[Key名]  
                      test@[Project名].iam.gserviceaccount.com,                                                                                                                               
                      projectOwners                                                                                                                                                                       
                    Writers:                                                                                                                                                                              
                      projectWriters                                                                                                                                                                      
                    Readers:                                                                                                                                                                              
                      projectReaders    
```

## テーブルのメタデータを表示
```
$ bq show data_qiita.tmp2_202010
Table [Project名]:data_qiita.tmp2_202010

   Last modified        Schema        Total Rows   Total Bytes   Expiration   Time Partitioning   Clustered Fields   Labels                                                      kmsKeyName                                                      
 ----------------- ----------------- ------------ ------------- ------------ ------------------- ------------------ -------- ------------------------------------------------------------------------------------------------------------------- 
  28 Jul 16:02:51   |- f0_: integer   1            8                             
```
                                            
## データセットの権限の一覧表示
```
$ bq show --format=prettyjson data_qiita > qiita.json
```

```qiita.json
{
  "access": [
    {
      "role": "WRITER", 
      "specialGroup": "projectWriters"
    }, 
    {
      "role": "OWNER", 
      "specialGroup": "projectOwners"
    }, 
    {
      "role": "OWNER", 
      "userByEmail": "test@[Project名].iam.gserviceaccount.com"
    }, 
    {
      "role": "READER", 
      "specialGroup": "projectReaders"
    }
  ], 
  "creationTime": "1595942233609", 
  "datasetReference": {
    "datasetId": "data_qiita, 
    "projectId": [Project名]
  }, 
  "defaultEncryptionConfiguration": {
    "kmsKeyName": "projects/[Project名]/locations/asia-northeast1/rojects/{Project名}/locations/asia-northeast1/keyRings/[KeyRing名]/cryptoKeys/[Key名]"
  }
}
```
## データセットの権限を更新
```
$ bq update --source=qiita_re.json data_qiita
Dataset '[Project名]:data_qiita' successfully updated.
```

```qiita_re.json
{
  "access": [
    {
      "role": "WRITER", 
      "specialGroup": "projectWriters"
    }, 
    {
      "role": "OWNER", 
      "specialGroup": "projectOwners"
    }, 
    {
      "role": "OWNER", 
      "userByEmail": "test@[Project名].iam.gserviceaccount.com"
    }
  ], 
  "creationTime": "1595942233609", 
  "datasetReference": {
    "datasetId": "data_qiita, 
    "projectId": [Project名]
  }, 
  "defaultEncryptionConfiguration": {
    "kmsKeyName": "projects/[Project名]/locations/asia-northeast1/rojects/{Project名}/locations/asia-northeast1/keyRings/[KeyRing名]/cryptoKeys/[Key名]"
  }
}
```


## クエリを投げる
```
$ bq query 'select count(*) from data_qiita.test_202010'
Waiting on bqjob_r292b672551aa59b9_0000017395f86254_1 ... (0s) Current status: DONE   
+-----+
| f0_ |
+-----+
|  27 |
+-----+
```

* SQLファイルを読み込ませる

```
$ bq query < test.sql 
Waiting on bqjob_r44bc1c144c0c51b_0000017395fb2daf_1 ... (0s) Current status: DONE   
+-----+
| f0_ |
+-----+
|  27 |
+-----+
```

```test.sql
select count(*) from data_qiita.test_202010
```

### --use_legacy_sql=false
* データセットをレガシーオフにしていない場合、legacySQLがデフォルトになる
* stadardSQLを使用する

```
bq query --use_lecacy_sql=false 'select count(*) from data_qiita.test_202010'
```

### --destination_table
* クエリの結果をテーブルに出力する

```
$ bq query --destination_table=data_qiita.tmp_202010 'select count(*) from data_qiita.test_202010'
Waiting on bqjob_r440946d3cc02908d_0000017395ff9411_1 ... (0s) Current status: DONE   
+-----+
| f0_ |
+-----+
|  27 |
+-----+

$ bq ls data_qiita
    tableId     Type    Labels   Time Partitioning   Clustered Fields  
 ------------- ------- -------- ------------------- ------------------ 
  test_202009   TABLE                                                  
  test_202010   TABLE                                                  
  tmp_202010    TABLE     
                                             
$ bq head data_qiita.tmp_202010
+-----+
| f0_ |
+-----+
|  27 |
+-----+
```

### --dry_run
* 実際に実行はされずにデータのスキャン量が計測できる

```
$ bq ls --jobs
                    jobId                      Job Type    State      Start Time         Duration     
 -------------------------------------------- ---------- --------- ----------------- ---------------- 
  bqjob_r440946d3cc02908d_0000017395ff9411_1   query      SUCCESS   28 Jul 15:17:02   0:00:00.738000  
  bqjob_r79c9d4c27d870e48_0000017395ff6947_1   query      FAILURE   28 Jul 15:16:51   0:00:00.381000 

$ bq query --dry_run 'select * from data_qiita.test_202010'
Query successfully validated. Assuming the tables are not modified, running this query will process 41478 bytes of data.

$ bq ls --jobs
                    jobId                      Job Type    State      Start Time         Duration     
 -------------------------------------------- ---------- --------- ----------------- ---------------- 
  bqjob_r440946d3cc02908d_0000017395ff9411_1   query      SUCCESS   28 Jul 15:17:02   0:00:00.738000  
  bqjob_r79c9d4c27d870e48_0000017395ff6947_1   query      FAILURE   28 Jul 15:16:51   0:00:00.381000 
```

### --maximum_bytes_billed
* クエリに対して課金されるバイト数を制限する

```
$ bq query --maximum_bytes_billed=3000  'select * from data_qiita.test_202010'
Waiting on bqjob_r49b23566f45a238d_000001739605edb8_1 ... (0s) Current status: DONE   
BigQuery error in query operation: Error processing job '[Project名]:bqjob_r49b23566f45a238d_000001739605edb8_1': Query exceeded limit for bytes billed: 3000. 10485760 or higher required.
```

### --parameter
* クエリパラメータを含むSQLを実行できる

```
$ bq query 'select count(*) from data_qiita.test_202010 where principalEmail="test@[Project名].iam.gserviceaccount.com"'
Waiting on bqjob_r6f551d87c5aa84fb_00000173960c7db9_1 ... (0s) Current status: DONE   
+-----+
| f0_ |
+-----+
|   8 |
+-----+

$ bq query --use_legacy_sql=false --parameter=param::test@[Project名].iam.gserviceaccount.com < test_param.sql
Waiting on bqjob_r486bc94d854a2b67_0000017396109223_1 ... (0s) Current status: DONE   
+-----+
| f0_ |
+-----+
|   8 |
+-----+
```

```test_param.sql
select count(*) from data_qiita.test_202010 where principalEmail = @param
```

## テーブルの数行を表示
```
$ bq head data_qiita.tmp_202010
+-----+
| f0_ |
+-----+
|  27 |
+-----+
```

## ジョブIDから結果を取得
```
$ bq head --job [Project名]:asia-northeast1.[jobID]
+-----+
| f0_ |
+-----+
|   8 |
+-----+
```

## テーブルの外部への出力
```
$ bq extract --location=asia-northeast1 --destination_format=AVRO data_qiita.test_202010 gs://qiita/[ファイル名].avro
```

### --print_header
* カラム名が出力されなくなる

```
$ bq extract --location=asia-northeast1 --destination_format=AVRO data_qiita.test_202010 gs://qiita/[ファイル名].avro
```

## テーブルのコピー
```
$ bq ls data_qiita
    tableId     Type    Labels   Time Partitioning   Clustered Fields  
 ------------- ------- -------- ------------------- ------------------ 
  test_202010   TABLE                                                  
  tmp_202010    TABLE                                                  

$ bq cp data_qiita.tmp_202010 data_qiita.tmp2_202010
Waiting on bqjob_r6c94a687e178598a_000001739629836d_1 ... (0s) Current status: DONE   
Table '[Project名]:data_qiita.tmp_202010' successfully copied to '[Project名]:data_qiita.tmp2_202010'

$ bq ls data_qiita
    tableId     Type    Labels   Time Partitioning   Clustered Fields  
 ------------- ------- -------- ------------------- ------------------ 
  test_202010   TABLE                                                  
  tmp2_202010   TABLE                                                  
  tmp_202010    TABLE                                                  
```

## テーブルの削除
```
bq rm data_qiita.test_202008
rm: remove table '[Project名]:data_qiita.test_202008'? (y/N) y
```

### --force
* 確認されず削除される

```
$ bq rm --force data_qiita.test_202009
```

## データセットの削除
```
$ bq rm --dataset data_qiita
rm: remove dataset '[Project名]:data_qiita'? (y/N) y
```

### --recursive
```
$ bq rm data_qiita
rm: remove dataset '[Project名]:data_qiita'? (y/N) y
BigQuery error in rm operation: Dataset [Project名]:data_qiita is still in use

$ bq rm --recursive data_qiita
rm: remove dataset '[Project名]:data_qiita'? (y/N) y
```

## ジョブのキャンセル
```
$ bq cancel [Project名].asia-northeast1.[jobID]
```

### --sync=false
* すぐにコマンドの結果が返される
* たまにキャンセルしてもすぐに停止しないジョブが現れるためこのオプションを適用するとキャンセルされる

```
$ bq cancel --sync [Project名].asia-northeast1.[jobID]
```

# 参考
[コマンドラインツールリファレンス](https://cloud.google.com/bigquery/docs/reference/bq-cli-reference?hl=ja#bq_rm)