クエリ結果の書き込み

このドキュメントでは、一時テーブルや永続テーブルにクエリ結果を書き込む方法について説明します。

一時テーブルと永続テーブル

BigQuery は、すべてのクエリ結果を永続テーブルまたは一時テーブルに保存します。

  • BigQuery は、永続的なテーブルに書き込まれていない一時テーブルを使用してクエリ結果をキャッシュに保存します。テーブルは、特別なデータセット内に作成され、ランダムに名前が付けられます。また、マルチステートメント クエリセッション内で使用する一時テーブルを作成することもできます。一時キャッシュのクエリ結果テーブルには料金はかかりません。キャッシュに保存されていないクエリ結果の一時テーブルに対して料金が発生します。

  • クエリの終了後、一時テーブルは最大 24 時間存在します。テーブルの構造とデータを表示するには、次の操作を行います。

    1. [BigQuery] ページに移動します。

      [BigQuery] に移動

    2. 左側のペインで、 [エクスプローラ] をクリックします。

      エクスプローラ ペインのボタンがハイライト表示されている。

      左側のペインが表示されていない場合は、 [左ペインを開く] をクリックしてペインを開きます。

    3. [エクスプローラ] ペインで、[ジョブ履歴] をクリックします。

    4. [個人履歴] をクリックします。

    5. 一時テーブルを作成したクエリを選択します。次に、[宛先テーブル] 行の [一時テーブル] をクリックします。

  • 一時テーブルデータへのアクセスは、クエリジョブを作成したユーザーまたはサービス アカウントに限定されます。

  • 一時テーブルは共有できず、標準のリストやその他のテーブル操作の方法を使用して表示することもできません。クエリ結果を共有する必要がある場合は、結果を永続テーブルに書き込むか、ダウンロードするか、Google スプレッドシートまたは Google ドライブで共有します。

  • 一時テーブルは、クエリ対象の 1 つまたは複数のテーブルと同じリージョンに作成されます。

  • 永続テーブルは、ユーザーがアクセス可能なデータセットに含まれる新規または既存のテーブルです。新しいテーブルにクエリ結果を書き込んだ場合、そのデータの保管に対して料金がかかります。永続テーブルにクエリ結果を書き込む場合、クエリ対象のテーブルは、宛先テーブルが含まれるデータセットと同じロケーションに存在する必要があります。

  • ドメイン制限付きの組織のポリシーが有効になっている場合、クエリ結果を一時テーブルに保存することはできません。回避策として、ドメイン制限付きの組織のポリシーを一時的に無効にしてクエリを実行し、ポリシーを再度有効にします。または、宛先テーブルにクエリ結果を保存することはできます。

必要な権限

クエリ結果をテーブルに書き込むには、少なくとも次の権限が付与されている必要があります。

  • 新しいテーブルを作成するための bigquery.tables.create 権限
  • 新しいテーブルへのデータの書き込み、テーブルの上書き、テーブルへのデータの追加を行うための bigquery.tables.updateData 権限
  • クエリジョブを実行するための bigquery.jobs.create 権限

クエリ対象のデータにアクセスするために、bigquery.tables.getData などの権限も必要になる場合があります。

次の事前定義済みの IAM ロールには bigquery.tables.create 権限と bigquery.tables.updateData 権限の両方が含まれています。

  • bigquery.dataEditor
  • bigquery.dataOwner
  • bigquery.admin

次の事前定義済みの IAM ロールには bigquery.jobs.create 権限が含まれています。

  • bigquery.user
  • bigquery.jobUser
  • bigquery.admin

また、bigquery.datasets.create 権限を持つユーザーがデータセットを作成すると、そのデータセットに対する bigquery.dataOwner アクセス権がユーザーに付与されます。bigquery.dataOwner アクセス権があれば、データセット内でテーブルを作成および更新できます。

BigQuery での IAM のロールと権限については、事前定義ロールと権限をご覧ください。

クエリ結果を永続テーブルに書き込む

永続テーブルにクエリ結果を書き込む際は、新しいテーブルの作成、既存テーブルへの結果の追加、既存のテーブルの上書きを行うことができます。

クエリ結果の書き込み

クエリ結果を永続テーブルに書き込むには、次の手順を使用します。費用を抑えるために、クエリを実行する前にデータをプレビューできます。

コンソール

  1. Google Cloud コンソールで [BigQuery] ページを開きます。

    [BigQuery] ページに移動

  2. 左側のペインで、 [エクスプローラ] をクリックします。

    エクスプローラ ペインのボタンがハイライト表示されている。

    左側のペインが表示されていない場合は、 [左ペインを開く] をクリックしてペインを開きます。

  3. [エクスプローラ] ペインでプロジェクトを開き、[データセット] をクリックして、データセットを選択します。

  4. クエリエディタで、有効な SQL クエリを入力します。

  5. [展開] をクリックして、[クエリの設定] を選択します。

    クエリの設定

  6. [クエリ結果の宛先テーブルを設定する] オプションを選択します。

    宛先の設定

  7. [送信先] セクションで、テーブルを作成するデータセットを選択し、テーブル ID を選択します。

  8. [宛先テーブルの書き込み設定] セクションで、次のいずれかを選択します。

    • [空の場合に書き込む] - テーブルが空の場合にのみ、クエリ結果をテーブルに書き込みます。
    • [テーブルに追加する] - クエリ結果を既存のテーブルに追加します。
    • [テーブルを上書きする] - 既存のテーブルにクエリ結果を同じ名前で上書きします。
  9. 省略可: [データのロケーション] で、ロケーションを選択します。

  10. クエリの設定を更新するには、[保存] をクリックします。

  11. [実行] をクリックします。これにより、指定したテーブルにクエリ結果を書き込むクエリジョブが作成されます。

宛先テーブルを指定せずにクエリを実行した場合は、エディタの下にある [結果を保存する] ボタンをクリックすると、キャッシュに保存された結果テーブルを永続テーブルにコピーできます。

SQL

次の例では、CREATE TABLE ステートメントを使用して、一般公開 bikeshare_trips テーブルのデータから trips テーブルを作成します。

  1. Google Cloud コンソールで、[BigQuery] ページに移動します。

    [BigQuery] に移動

  2. クエリエディタで次のステートメントを入力します。

    CREATE TABLE mydataset.trips AS (
      SELECT
        bike_id,
        start_time,
        duration_minutes
      FROM
        bigquery-public-data.austin_bikeshare.bikeshare_trips
    );

  3. [実行] をクリックします。

クエリの実行方法については、インタラクティブ クエリを実行するをご覧ください。

詳細については、既存のテーブルから新しいテーブルを作成するをご覧ください。

bq

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. クエリ結果に基づいて永続テーブルを作成するには、bq query コマンドを入力して、--destination_table フラグを指定します。GoogleSQL 構文を使用するには、use_legacy_sql=false フラグを指定します。デフォルト プロジェクト以外のプロジェクトにあるテーブルにクエリ結果を書き込むには、project_id:dataset の形式でプロジェクト ID をデータセット名に追加します。

    省略可: --location フラグを指定して、その値を使用するロケーションに設定します。

    既存の宛先テーブルに対する書き込み処理を制御するには、次のオプション フラグのいずれかを指定します。

    • --append_table: 宛先テーブルが存在する場合、クエリ結果がそのテーブルに追加されます。
    • --replace: 宛先テーブルが存在する場合、そのテーブルはクエリ結果で上書きされます。

      bq --location=location query \
      --destination_table project_id:dataset.table \
      --use_legacy_sql=false 'query'

      次のように置き換えます。

    • location は、クエリの処理に使用するロケーションの名前です。--location フラグは省略可能です。たとえば、BigQuery を東京リージョンで使用している場合は、このフラグの値を asia-northeast1 に設定します。ロケーションのデフォルト値は、.bigqueryrc ファイルを使用して設定できます。

    • project_id はプロジェクト ID です。

    • dataset は、クエリ結果を書き込むテーブルを含むデータセットの名前です。

    • table は、クエリ結果を書き込むテーブルの名前です。

    • query は、GoogleSQL 構文のクエリです。

      書き込み処理フラグが指定されていない場合は、デフォルトの動作として、テーブルが空の場合にのみ結果が書き込まれます。テーブルが存在していて空でない場合は、BigQuery error in query operation: Error processing job project_id:bqjob_123abc456789_00000e1234f_1: Already Exists: Table project_id:dataset.table というエラーが返されます。

      例:

      次のコマンドを入力すると、mydataset 内の mytable という宛先テーブルにクエリ結果が書き込まれます。このデータセットはデフォルト プロジェクトにあります。コマンドに書き込み処理フラグは指定されていないため、宛先テーブルは新規または空である必要があります。それ以外の場合は、Already exists エラーが返されます。このクエリは、USA Name Data 一般公開データセットからデータを取得します。

      bq query \
      --destination_table mydataset.mytable \
      --use_legacy_sql=false \
      'SELECT
      name,
      number
      FROM
      `bigquery-public-data`.usa_names.usa_1910_current
      WHERE
      gender = "M"
      ORDER BY
      number DESC'

      クエリ結果を使用して mydataset 内の mytable という名前の宛先テーブルを上書きするには、次のコマンドを入力します。このデータセットはデフォルト プロジェクトにあります。このコマンドには --replace フラグが指定されているため、宛先テーブルが上書きされます。

      bq query \
      --destination_table mydataset.mytable \
      --replace \
      --use_legacy_sql=false \
      'SELECT
      name,
      number
      FROM
      `bigquery-public-data`.usa_names.usa_1910_current
      WHERE
      gender = "M"
      ORDER BY
      number DESC'

      mydataset 内の mytable という名前の宛先テーブルにクエリ結果を追加するには、次のコマンドを入力します。このデータセットはデフォルト プロジェクトではなく my-other-project にあります。このコマンドには --append_table フラグが指定されているため、クエリ結果が宛先テーブルに追加されます。

      bq query \
      --append_table \
      --use_legacy_sql=false \
      --destination_table my-other-project:mydataset.mytable \
      'SELECT
      name,
      number
      FROM
      `bigquery-public-data`.usa_names.usa_1910_current
      WHERE
      gender = "M"
      ORDER BY
      number DESC'

      上記のそれぞれの例では、次のような出力が生成されます。読みやすくするために、出力の一部のみを示します。

      Waiting on bqjob_r123abc456_000001234567_1 ... (2s) Current status: DONE
      +---------+--------+
      |  name   | number |
      +---------+--------+
      | Robert  |  10021 |
      | John    |   9636 |
      | Robert  |   9297 |
      | ...              |
      +---------+--------+
      

API

クエリ結果を永続テーブルに保存するには、jobs.insert メソッドを呼び出して query ジョブを構成し、destinationTable プロパティの値を含めます。既存の宛先テーブルに対する書き込み処理を制御するには、writeDisposition プロパティを構成します。

クエリジョブの処理を行うロケーションを制御するには、ジョブリソースjobReference セクションにある location プロパティを指定します。

Go

このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Go の設定手順を完了してください。詳細については、BigQuery Go API のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/bigquery"
	"google.golang.org/api/iterator"
)

// queryWithDestination demonstrates saving the results of a query to a specific table by setting the destination
// via the API properties.
func queryWithDestination(w io.Writer, projectID, destDatasetID, destTableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydataset"
	// tableID := "mytable"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	q := client.Query("SELECT 17 as my_col")
	q.Location = "US" // Location must match the dataset(s) referenced in query.
	q.QueryConfig.Dst = client.Dataset(destDatasetID).Table(destTableID)
	// Run the query and print results when the query job is completed.
	job, err := q.Run(ctx)
	if err != nil {
		return err
	}
	status, err := job.Wait(ctx)
	if err != nil {
		return err
	}
	if err := status.Err(); err != nil {
		return err
	}
	it, err := job.Read(ctx)
	for {
		var row []bigquery.Value
		err := it.Next(&row)
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintln(w, row)
	}
	return nil
}

Java

このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Java の設定手順を完了してください。詳細については、BigQuery Java API のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

クエリの結果を永続テーブルに保存するには、QueryJobConfiguration宛先テーブルを目的の TableId に設定します。

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.QueryJobConfiguration;
import com.google.cloud.bigquery.TableId;

public class SaveQueryToTable {

  public static void runSaveQueryToTable() {
    // TODO(developer): Replace these variables before running the sample.
    String query = "SELECT corpus FROM `bigquery-public-data.samples.shakespeare` GROUP BY corpus;";
    String destinationTable = "MY_TABLE";
    String destinationDataset = "MY_DATASET";

    saveQueryToTable(destinationDataset, destinationTable, query);
  }

  public static void saveQueryToTable(
      String destinationDataset, String destinationTableId, String query) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      // Identify the destination table
      TableId destinationTable = TableId.of(destinationDataset, destinationTableId);

      // Build the query job
      QueryJobConfiguration queryConfig =
          QueryJobConfiguration.newBuilder(query).setDestinationTable(destinationTable).build();

      // Execute the query.
      bigquery.query(queryConfig