BigQuery: リテラルとデータ型

BigQuery: リテラルとデータ型

February 7, 2021
BigQuery
BigQuery, SQL

BigQueryでサポートされるデータ型 #

  • 数値型 INT64 NUMERIC BIGNUMERIC FLOAT64
  • ブール型 BOOL
  • 文字列型 STRING
  • バイト型 BYTES
  • 日付型 DATE
  • 日時型 DATETIME
  • 時刻型 TIME
  • タイムスタンプ型 TIMESTAMP
  • 配列型 ARRAY
  • 構造体型 STRUCT
  • 地理型 GEOGRAPHY
SELECT
  NULL AS val_of_NULL,
  1 AS val_of_INT64,
  0xFF AS val_of_INT64,
  1.0 AS val_of_FLOAT64,
  NUMERIC '1' AS val_of_NUMERIC,
  BIGNUMERIC '1' AS val_of_BIGNUMERIC,
  TRUE AS val_of_BOOL_TRUE,
  FALSE AS val_of_BOOL_FALSE,
  'string with single quote' AS val_of_STRING,
  "string with double quote" AS val_of_STRING,
  '''string with triple single quote
it can have multi lines''' AS val_of_STRING,
  """string with triple double quote
it can have multi lines""" AS val_of_STRING,
  B'bytes' AS val_of_BYTES,
  R'regexp' AS val_of_STRING_as_RegExp,
  DATE '2021-02-07' AS val_of_DATE,
  DATETIME '2021-02-07 15:10:20' AS val_of_DATETIME,
  TIME '15:10:20' AS val_of_TIME,
  TIMESTAMP '2021-02-07T15:10:20+0900' AS val_of_TIMESTAMP,
  [1,2,3] AS val_of_ARRAY_OF_INT64,
  ARRAY[1,2,3] AS val_of_ARRAY_OF_INT64,
  ARRAY<INT64>[1,2,3] AS val_of_ARRAY_OF_INT64,
  (123, 'string') AS val_of_STRUCT,
  STRUCT(123 AS num, 'string' AS str) AS val_of_STRUCT,
  STRUCT<num INT64, str STRING>(123, 'string') AS val_of_STRUCT,

R プレフィックスの正規表現リテラル #

正規表現のデータ型があるわけではないので中身は STRING かもしれない。 R プレフィックスを使うとエスケープシーケンスの扱いが変わり正規表現が書きやすい。

SELECT
  REGEXP_REPLACE('___(abc)___', '(abc)', '*replacement*'),
  REGEXP_REPLACE('___(abc)___', R'(abc)', '*replacement*'),
  -- '\(abc\)' とは書けない
  REGEXP_REPLACE('___(abc)___', R'\(abc\)', '*replacement*'),

日時系のリテラル #

日時形式の文字列リテラルの前に DATETIME とか DATE って置けば良い。

暗黙的な型変換 #

関数の期待する型と異なるデータ型のリテラルを指定した場合は暗黙的に型変換がなされる。

SELECT FORMAT_DATE('%b %Y', '2021-02-03')

以下はエラーとなる。

SELECT
  -- FORMAT_DATE(STRING, DATE) を期待しており型不一致でエラー
  FORMAT_DATE('%b %Y', val)
FROM
  UNNEST(['2021-02-03']) AS val

2項演算で異なるデータ型の場合も実際は暗黙的な型変換が発生している。

SELECT DATE '2021-02-03' > '2021-02-02'

キャスト 明示的な型変換 #

CAST 関数を使うことで明示的な型変換が可能。変換できない時は実行時エラーとなる。

CAST([変換する値] AS [変換後のデータ型])
SELECT
  FORMAT_DATE('%b %Y', CAST(val AS DATE))
FROM
  UNNEST(['2021-02-03']) AS val

配列型 #

[] で配列型のリテラルが記述できる。

SELECT [1,2,3]

配列型の個々の要素にアクセスするには OFFSET(i) もしくは ORDINAL(n) を利用する。

SELECT
  [1,2,3][OFFSET(0)],
  [1,2,3][OFFSET(1)],
  [1,2,3][OFFSET(2)],
  [1,2,3][ORDINAL(1)],
  [1,2,3][ORDINAL(2)],
  [1,2,3][ORDINAL(3)],

範囲外の要素にアクセスすると out of bounds エラー

構造体型 #

() でグルーピングすると構造体型のリテラルが記述できる。 構造体は key と value を持つ連想配列や辞書のようなもの。

SELECT (1, 'string')

ただし上記の書き方(タプル構文)だと匿名フィールドとなり個々の値へアクセスはできない。 まとめて値を比較する時には使える。

SELECT
  val,
  val = (1, 'a'),
FROM
  UNNEST([(1, 'a'), (2, 'b'), (3, 'c')]) AS val

型を明示的に指定する場合はフィールド名を指定できる。ネストした値へのアクセスは . ドットを利用する。

SELECT
  val.num,
  val.str,
FROM
  UNNEST(ARRAY<STRUCT<num INT64, str STRING>>[(1, 'a'), (2, 'b'), (3, 'c')]) AS val

サブクエリで SELECT AS STRUCT を宣言すれば STRUCT を返すサブクエリが書けるので、この例の方が直感的か。

SELECT
  val,
  val.num,
  val.str,
FROM
  (SELECT AS STRUCT 1 AS num, 'a' AS str) AS val

やっぱ直感的ではないか。

NULL が含まれる構造体型の等値比較 #

結果は NULL となる。ただし比較は先頭から順に行われ NULL 値の比較前に false になる場合は false となる。

SELECT
  val = (1, NULL),
FROM
  UNNEST(ARRAY<STRUCT<num INT64, str STRING>>[(1, 'a'), (2, NULL), (1, NULL)]) AS val

結果は以下の通り。

null
false
null