BigQueryのテーブル識別子で構文エラー(テーブル名はバッククォートで囲むべきか)

記事タイトルとURLをコピーする

事象

BigQuery で 標準 SQL を実行しようとした際に以下のエラーが発生した。

エラーメッセージで示された該当箇所は、テーブル名の指定であり、一見しておかしなところは見当たらない。

実行しようとした SQL

INSERT
    my-project.mydataset.mytable
    (id, name, subject, score)
VALUES
    ("1111", "John Doe", "Math", 90),
    ("2222", "Jane Doe", "Math", 95)

エラーメッセージ

Syntax error: Expecting VALUES list or query at [2:7]

※ 末尾の大括弧内の数字はエラー構文の位置を示すため改行やインデント等により異なる

SQL の構文は正しいはずなのにエラーとなる

原因

当事象の原因は、プロジェクト ID にダッシュ記号 (別名ハイフン : - ) が使われているのにも関わらず、テーブル指定をバッククォート ( ` ) で囲わなかったことです。

BigQuery では INSERT 句のテーブル識別子がバッククォートで囲まれていない場合、プロジェクト ID にダッシュ記号が使われていると構文エラーとなります。

解説

SQL における BigQuery のテーブル名の指定

BigQuery で標準 SQL を使う際、以下のように、テーブル指定をバッククォート (英語では backquote または backtick) 記号で囲むのが原則です。

SELECT * FROM `my-project.mydataset.mytable`

BigQuery のテーブル識別子は、以下のような構成です。

`(プロジェクト ID).(データセット名).(テーブル名)`

bq コマンドやコンソールからの SQL 投入時等、プロジェクト名が自明の場合は省略することもできます。

またバッククォートは 場合により 省略することができます。しかし 場合により バッククォートで囲まないとエラーとなる場合があります。

バッククォートの要否

ドキュメント「 語彙の構造と構文 」の「テーブル名」の項を確認します。

引用符で囲まれていない識別子は、 FROM 句または TABLE 句で参照される場合にダッシュをサポートします。テーブルパスの最初の識別子(プロジェクト ID またはテーブル名)のみがダッシュを使用できます。ダッシュはデータセットではサポートされていません。

プロジェクト名等にダッシュ記号 (ハイフン記号) が使われている場合でかつバッククォートで囲まれていない場合、 FROM 句や TABLE 句の場合は問題なく使えますが、 当記事冒頭で示したような INSERT 句の後ではエラーになってしまうのです。

なおエラーとならない場合として FROM 句や TABLE 句 の他に UPDATE 等もあります。

エラーにならない

SELECT * FROM my-project.mydataset.mytable
CREATE OR REPLACE TABLE
    my-project.mydataset.mytable
(
    id STRING,
    name STRING,
    subject STRING,
    score INT64
)
UPDATE
    my-project.mydataset.mytable
SET
    score = 100
WHERE
    id = "1111"

エラーになる

INSERT
    my-project.mydataset.mytable
    (id, name, subject, score)
VALUES
    ("1111", "John Doe", "Math", 90),
    ("2222", "Jane Doe", "Math", 95)

対策

対症療法

以下のように SQL を修正すると、構文エラーは発生しません。

バッククォートで囲む

INSERT
    `my-project.mydataset.mytable`
    (id, name, subject, score)
VALUES
    ("1111", "John Doe", "Math", 90),
    ("2222", "Jane Doe", "Math", 95)

バッククォートで囲む (プロジェクト名のみでも可)

INSERT
    `my-project`.mydataset.mytable
    (id, name, subject, score)
VALUES
    ("1111", "John Doe", "Math", 90),
    ("2222", "Jane Doe", "Math", 95)

INTO をつける

INSERT INTO
    my-project.mydataset.mytable
    (id, name, subject, score)
VALUES
    ("1111", "John Doe", "Math", 90),
    ("2222", "Jane Doe", "Math", 95)

原則

コーディング規則として、テーブル識別子はバッククォートで囲むこととするのが望ましいと言えます。

ただし Bash (Linux) 等で bq コマンドを実行する際はバッククォートが別の意味を持つため、適切にエスケープする必要があります。

Bash ではバッククォートは「コマンドの展開」の意味となってしまいますので、バックスラッシュ記号 ( \ ) でバッククォートをエスケープします。

エラーとなるケース

$ bq query --use_legacy_sql=false "SELECT * FROM `my-project.mydataset.mytable`"
-bash: my-project.mydataset.mytable: command not found
Error in query string: Error processing job 'my-project:bqjob_abcde_0000012345_1': Syntax error: Unexpected end of script at [1:14]

問題ないケース

$ bq query --use_legacy_sql=false "SELECT * FROM \`my-project.mydataset.mytable\`"
+------+----------+---------+-------+
|  id  |   name   | subject | score |
+------+----------+---------+-------+
| 1111 | John Doe | Math    |    90 |
| 2222 | Jane Doe | Math    |    95 |
+------+----------+---------+-------+

杉村 勇馬 (記事一覧)

執行役員 CTO / クラウドソリューション部 部長

元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。