O hirunewani blog

BigQueryのフィールド取得とクエリで利用できる型への変換

Created at

取得できるBigQueryのフィールドの型のいくつかは、クエリにそのまま利用することが出来ない。GolangのBigQueryパッケージを利用してスキーマを取得し、クエリで利用できるように変換する方法について。

Table.Metadata 各フィールドのスキーマを取得する

cloud.google.com/go/bigqueryを利用すると、次のようにBigQueryのテーブルのスキーマを取得できる。

md, err := client.Dataset("my_dataset").Table("my_table").Metadata(ctx)

for _, fs := range md.Schema {
  fmt.Printf("Name: %s, FieldType: %s\n", fs.Name, fs.Type)
}

https://pkg.go.dev/cloud.google.com/go/bigquery#FieldSchema

FieldTypeをGoogle SQLで利用できる型に変換する

Table.Metadataで取得されるFieldTypeは、BigQueryでフィールドを定義する値であって、Google SQL*で利用できる型とは異なる場合がある。

*Google SQL : BigQueryのSQLは、Google SQLを採用している。

Google SQLのData typesについてのドキュメントを参照して、可能な限りBigQuery FieldTypeと同名のGoogle SQL Data Typeを選択した変換表は次のようになる。

BigQuery FieldTypeGoogle SQL Data Type
STRINGSTRING
BYTESBYTES
INTEGERINTEGER(alias)
FLOATFLOAT64
BOOLEANBOOLEAN (alias)
TIMESTAMPTIMESTAMP
RECORDSTRUCT
DATEDATE
TIMETIME
DATETIMEDATETIME
NUMERICNUMERIC
GEOGRAPHYGEOGRAPHY
BIGNUMERICBIGNUMERIC
INTERVALINTERVAL
JSONJSON
RAMGERANGE

RECORDが当然として、FLOATはFLOAT64などへの変換が必要になる。INTEGERとBOOLEANはそれぞれ同名のエイリアスがあるため、そのまま利用できる。

取得したスキーマを元にNULLを挿入するクエリを生成する場合を考える。STRINGなどの場合は、取得されたFieldTypeをそのまま利用して次のようにすればいい。

fmt.Sprintf("CAST(NULL AS %s) AS %s", fs.Type, fs.Name)

しかし、FLOATの場合を考慮すると分岐が必要になる。

fieldType := fs.Type
if fs.Type == bigquery.FloatFieldType {
    fieldType = "FLOAT64"
}
fmt.Sprintf("CAST(NULL AS %s) AS %s", fieldType, fs.Name)

RECORDを考慮する場合は、さらにFieldのスキーマを見て、再帰的に処理する必要がある。 例えば、STRING型のp1とp2というフィールドを持つrecord_fieldの場合、次のようなクエリを生成すればいい。

CAST(NULL AS STRUCT<p1 STRING, p2 FLOAT64>) AS record_field