BigQueryのSQLいろいろ (1) 数値型 | Wantedly Engineer Blog
BigQueryのSQLについて、ドキュメントを読んだり実験したりしながら挙動を解き明かしていこうと思います。第1回は数値型についてです。はじめにさいきん業務でBigQuery SQLのコードジ...
https://www.wantedly.com/companies/wantedly/post_articles/1010260
BigQueryのSQLについて、ドキュメントを読んだり実験したりしながら挙動を解き明かしていこうと思います。第2回は文字列型についてです。
本稿では以下を扱います。
文字列型はUnicode文字列を扱う型です。エンコード形式としてUTF-8を使っています。
BigQueryの文字列型は、well-formedなものだけを扱います。つまり、UTF-8のルールに沿っていない入力は弾かれるようになっています。他プログラミング言語では、Goがill-formedな文字列も許容するのに対してRustがwell-formedな文字列に限定しているという例があります。
well-formedなUTF-8文字列は、コードポイント (Unicode Scalar Value) の並びと1対1対応します。そのため、普段はUTF-8であるかどうかを意識する必要はありません。BigQueryでエンコーディングを意識するのは主に以下の場合です。
他の言語にも通じることですが、Unicode文字列を扱うにあたっては以下のような点に注意する必要があります。
照合順は、文字列の比較演算の振舞いを定めるオプションです。現時点で、BigQueryは以下の2つの照合順のみをサポートしています。
オプションを指定しない場合は空の照合順指定 ('') と同等とみなされ、バイナリ比較が使われます。
バイナリ比較はUTF-8のバイト列による辞書順比較です。この辞書順比較では、接頭辞は元の文字列よりも前にソートされます。このアルゴリズムは、コードポイントごと (=UTF-32) で辞書順比較した場合と同じ結果になります。
'und:ci' は大文字と小文字を同一視して比較します。
SELECT COLLATE(x, 'und:ci') AS x FROM UNNEST(['java', 'Java', 'JAVA', 'Jake', 'jail']) AS x
ORDER BY x
-- jail, Jake, java, Java, JAVA'und:ci' は非ASCII文字に対してもある程度期待通りに動作します。仮名文字に対しても動作することから、内部的にはDUCETではないかと推察されます。
PostgreSQLなどの他のSQLでは比較演算などの構文にコレーション情報を付加します。いっぽう、BigQueryでは比較構文ではなく COLLATE 関数で比較対象の式にコレーション情報を付加します。しかし、COLLATE関数の効果は実際には静的に解決されるため、異なるコレーションの入った式を比較しようとすると実行時エラーではなく静的検査でエラーになります。おそらく内部的にSTRING型をコレーション別の型に分けて推論しているのではないかと思います。
つまり、BigQueryのコレーション構文は一見すると独特に見えますが、内部的にはPostgreSQLなどの他のSQLと同じような形で実行されていると考えられます。
テーブルカラムでは STRING(10) のように長さの上限を指定できます。これはコードポイント (Unicode Scalar Value) の個数で数えられます。そのため以下の点に注意が必要です。
BYTES型は名前の通り、バイト列を表す型です。バイナリデータを扱う場合やUnicode以外の文字列を扱う場合などはこちらの型を使うことになります。BigQueryのUIやAPI上はBase64で表示されます。
文字列操作に使われる関数の多くはBYTES型でも利用できます。 (BYTE_LENGTH, CONCAT, STARTS_WITH, SPLIT, SUBSTR など)
テーブルカラムでは BYTES(10) のように長さの上限を指定できます。これはバイト数で数えられます。 STRING(10) とは大きく意味が異なる点に注意が必要です。
JSON型はJSON Valueを表現した型です。つまり内部的には構造をそのまま保持しており、ARRAYやSTRUCTに近いと考えたほうが適切です。ただし、BigQuery上はSTRING型と共通で利用できる処理が多いため、ここで紹介しています。
パース済みのJSONからは以下のような情報が欠落しているので注意が必要です。
また、null返却時の振舞いにも差異があります。
BigQueryのJSON Valueの数値は、内部的には以下のいずれかで表現されます。
同じ数値を複数の方法で表現できる場合、内部表現の差異は基本的に区別されません。ただし負のゼロは他と区別される点に注意が必要です。
JSONの数値のパースの規則は以下のようになっているようです。
SELECT
  -- 9123456789012345678
  INT64(JSON '9123456789012345678'),
  -- 9123456789012345856
  INT64(JSON '9123456789012345678.0'),JSON型はSTRING型と異なり、 Orderable, Groupable, Comparable のいずれでもありません。したがって同等性の比較・大小比較・ソート・グルーピングはいずれも不可能です。
BigQueryの以下の型について、細部の振舞いに注意しながら紹介しました。