Snowflake SQL API 開発者ガイド

このガイドでは、Snowflake SQL API の使用方法について説明します。

このトピックの内容:

紹介

Snowflake SQL API は、Snowflakeデータベースのデータにアクセスして更新するために使用できる REST API です。この API を使用して、次のようなカスタムアプリケーションと統合を開発できます。

  • 簡単なクエリを実行する

  • 展開を管理する(例: ユーザーとロールのプロビジョニング、テーブルの作成など)

SQL API の機能

Snowflake SQL API は、使用可能な次の操作を提供します。

  • 実行のための SQL ステートメントを送信します。

  • ステートメントの実行状況を確認します。

  • ステートメントの実行をキャンセルします。

この API を使用して、 標準クエリ と、ほとんどの DDL および DML ステートメントを実行できます。サポートされていないステートメントの型については、 SQL API の制限 をご参照ください。

クエリの場合は、結果をページ分割できます(例: ページごとに10行ずつで結果を取得)。

SQL API(/api/statements)のエンドポイントは、アカウントへのアクセスを制限するために設定した ネットワークポリシー によって保護されています。

SQL API の制限

SQLAPI には、次の制限があります。

  • 結果のページの最大サイズは約10 MB です。

  • 結果のページで返される最大行数は10,000です。

  • このサービスは現在、結果を同時に(つまり、複数のスレッドで並列に)フェッチすることをサポートしていません。リクエストは単一スレッドからのみサポートされます。

  • 次のステートメントはサポートされていません。

    • Snowflake SQL PUT コマンドを使用したステートメント

    • Snowflake SQL GET コマンドを使用したステートメント

API の使用

SQL API は https://アカウント識別子.snowflakecomputing.com/api で入手できます。ここでの アカウント識別子 は、使用する アカウント識別子 です。

API は /api/statements/ リソースで構成され、次のエンドポイントを提供します。

エンドポイント

説明

/api/statements/

このエンドポイントを使用して、 実行する SQL ステートメントを送信 します。

/api/statements/statementHandle

このエンドポイントを使用して、 ステートメントの実行ステータスを確認 します。(statementHandle は、実行のために送信されたステートメントの一意の識別子。)

/api/statements/statementHandle/cancel

このエンドポイントを使用して、 ステートメントの実行をキャンセル します。

REST APIs の開発ツールとライブラリ(例: Postman)を使用して、リクエストを送信し、応答を処理できます。

サーバーへの認証

リクエストを送信する場合、リクエストには認証情報が含まれている必要があります。次のセクションでは、この情報をリクエストに追加する方法について説明します。

OAuth の使用

OAuth を使用するには、次のステップに従います。

  1. 認証のために OAuth を設定します。

    OAuth を設定して OAuth トークンを取得する方法の詳細については、 OAuth をご参照ください。

  2. 生成された OAuth トークンを使用してSnowflakeに接続できることを確認するために、 SnowSQL を使用します。

    $ snowsql -a <account_identifier> -u <user> --authenticator=oauth --token=<oauth_token>
    
  3. アプリケーションコードの送信する各 API リクエストで、次のヘッダーを設定します。

    • Authorization: Bearer OAuthトークン

      OAuthトークン は、生成された OAuth トークンです。

    • X-Snowflake-Authorization-Token-Type: OAUTH

      X-Snowflake-Authorization-Token-Type ヘッダーを省略することもできます。このヘッダーが存在しない場合、Snowflake は Authorization ヘッダーのトークンが OAuth トークンであると想定します。

キーペア認証の使用

キーペア認証を使用するには、次のステップを実行します。

  1. キーペア認証を設定します。

    このプロセスの一環として、次を実行する必要があります。

    1. 公開キーと秘密キーのペアを生成します。生成された秘密キーはファイル内にある必要があります(例: rsa_key.p8 という名前)。

    2. 公開キーをSnowflakeユーザーに割り当てます。ユーザーにキーを割り当てたら、 DESCRIBE USER コマンドを実行します。出力では、 RSA_PUBLIC_KEY_FP プロパティは、ユーザーに割り当てられた公開キーのフィンガープリントに設定する必要があります。

    キーペアを生成してユーザーにキーを割り当てる方法については、 キーペア認証およびキーペアローテーション をご参照ください。

  2. 生成された秘密キーを使用して Snowflake に接続 できることを確認するために、 SnowSQL を使用します。

    $ snowsql -a <account_identifier> -u <user> --private-key-path <path>/rsa_key.p8
    

    暗号化された秘密キーを生成した場合、 SnowSQL は、キーの生成時に作成したパスフレーズの入力を求めます。

  3. アプリケーションコード内で、

    1. ユーザーの公開キーのフィンガープリント(SHA-256ハッシュ)を生成します。フィンガープリントの前に SHA256: を付けます。例:

      SHA256:ハッシュ

      Pythonで秘密キーファイルからフィンガープリントを生成する例については、jwt-generator をご参照ください。

      コードの次のセクションでは、フィンガープリントを生成する方法を示します。

      from cryptography.hazmat.primitives.serialization import load_pem_private_key
      from cryptography.hazmat.primitives.serialization import Encoding
      from cryptography.hazmat.primitives.serialization import PublicFormat
      from cryptography.hazmat.backends import default_backend
      ..
      import base64
      from getpass import getpass
      import hashlib
      ..
      # If you generated an encrypted private key, implement this method to return
      # the passphrase for decrypting your private key. As an example, this function
      # prompts the user for the passphrase.
      def get_private_key_passphrase():
          return getpass('Passphrase for private key: ')
      
      # Private key that you will load from the private key file.
      private_key = None
      
      # Open the private key file.
      # Replace <private_key_file_path> with the path to your private key file (e.g. /x/y/z/rsa_key.p8).
      with open('<private_key_file_path>', 'rb') as pem_in:
          pemlines = pem_in.read()
          try:
              # Try to access the private key without a passphrase.
              private_key = load_pem_private_key(pemlines, None, default_backend())
          except TypeError:
              # If that fails, provide the passphrase returned from get_private_key_passphrase().
              private_key = load_pem_private_key(pemlines, get_private_key_passphrase().encode(), default_backend())
      
      # Get the raw bytes of the public key.
      public_key_raw = private_key.public_key().public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
      
      # Get the sha256 hash of the raw bytes.
      sha256hash = hashlib.sha256()
      sha256hash.update(public_key_raw)
      
      # Base64-encode the value and prepend the prefix 'SHA256:'.
      public_key_fp = 'SHA256:' + base64.b64encode(sha256hash.digest()).decode('utf-8')
      
    2. ペイロードに次のフィールドを含む JSON Web トークン(JWT) を生成します。

      フィールド

      説明

      iss

      これは、JWT の発行者のフィールドです。これを次の値に設定します。

      アカウント識別子.ユーザー.SHA256:公開キーフィンガープリント

      条件:

      • アカウント識別子 は、Snowflakeの使用する アカウント識別子 です。

        アカウントロケーター を使用している場合は、アカウントロケーターからリージョン情報を除外します。

      • ユーザー は、Snowflakeユーザー名です。

      • SHA256:公開キーフィンガープリント は、前のステップで生成したフィンガープリントです。

      MYORGANIZATION-MYACCOUNT.MYUSER.SHA256:公開キーフィンガープリント

      sub

      これは JWT の件名のフィールドです。これを次の値に設定します。

      アカウント識別子.ユーザー

      MYORGANIZATION-MYACCOUNT.MYUSER

      iat

      これは JWT が発行された時間のフィールドです。これを現在の時刻(UTC のエポック開始からの秒数)に設定します。

      注意: 発行時間を選択するときは、Snowflake展開のタイムゾーンを使用します。

      1615370644

      exp

      これは、JWT の有効期限が切れる時間のフィールドです。これを有効期限(UTC のエポック開始からの秒数)に設定します。

      注意: JWT は、より長い有効期限を指定した場合でも、トークンが発行されてから最大1時間まで有効です。

      1615374184

      Python で JWT を生成する例については、 jwt-generator をご参照ください。

      コードの次のセクションは、 JWT を生成する方法を示しています。この例では、次のコマンドを実行してインストールできる PyJWT モジュール を使用しています。

      pip install pyjwt
      
      from datetime import timedelta, timezone, datetime
      
      # This example relies on the PyJWT module (https://pypi.org/project/PyJWT/).
      import jwt
      
      # Construct the fully qualified name of the user in uppercase.
      # - Replace <account_identifier> with your account identifier.
      #   (See https://docs.snowflake.com/en/user-guide/admin-account-identifier.html .)
      # - Replace <user_name> with your Snowflake user name.
      account = "<account_identifier>"
      # Get the account identifier without the region, cloud provider, or subdomain.
      if not '.global' in account:
          idx = account.find('.')
          if idx > 0:
              account = account[0:idx]
          else:
              # Handle the replication case.
              idx = account.find('-')
              if idx > 0:
                  account = account[0:idx]
      # Use uppercase for the account identifier and user name.
      account = account.upper()
      user = "<user_name>".upper()
      qualified_username = account + "." + user
      
      # Get the current time in order to specify the time when the JWT was issued and the expiration time of the JWT.
      now = datetime.now(timezone.utc)
      # Specify the length of time during which the JWT will be valid. You can specify at most 1 hour.
      lifetime = timedelta(minutes=59)
      
      # Create the payload for the token.
      payload = {
          # Set the issuer to the fully qualified username concatenated with the public key fingerprint (calculated in the
          # previous step).
          "iss": qualified_username + '.' + public_key_fp,
      
          # Set the subject to the fully qualified username.
          "sub": qualified_username,
      
          # Set the issue time to now.
          "iat": now,
      
          # Set the expiration time, based on the lifetime specified for this object.
          "exp": now + lifetime
      }
      
      # Generate the JWT. private_key is the private key that you read from the private key file in the previous step when you
      # generated the public key fingerprint.
      encoding_algorithm="RS256"
      token = jwt.encode(payload, key=private_key, algorithm=encoding_algorithm)
      # If you are using a version of PyJWT prior to 2.0, jwt.encode returns a byte string, rather than a string.
      # If the token is a byte string, convert it to a string.
      if isinstance(token, bytes):
        token = token.decode('utf-8')
      decoded_token = jwt.decode(token, key=private_key.public_key(), algorithm=[encoding_algorithm])
      print("Generated a JWT with the following payload:\n{}".format(decoded_token))
      
    3. 送信する各 API リクエストで、次のヘッダーを設定します。

      • Authorization: Bearer JWT

        JWT は、生成したトークンです。

      • X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT

リクエスト再送信向けの固有リクエスト ID の割り当て

場合によっては、Snowflakeが API リクエストで SQL ステートメントを実行したかどうかが明確ではない場合があります(例: ネットワークエラーまたはタイムアウトのため)。Snowflakeがステートメントを実行しなかった場合に備えて、Snowflakeに同じリクエストを再度送信することを選択できます。

Snowflakeが最初のリクエストでステートメントをすでに実行していて、リクエストを再送信した場合は、ステートメントが2回実行されます。一部のタイプのリクエストでは、同じステートメントを繰り返し実行すると、意図しない結果が生じる可能性があります(例: 重複データをテーブルに挿入)。

リクエストを再送信するときにSnowflakeが同じステートメントを2回実行しないようにするには、リクエスト ID を使用してリクエストを他のリクエストと区別します。最初のリクエストと再送信されたリクエストで同じリクエスト ID を指定すると、ステートメントがすでに正常に実行されている場合、Snowflakeはステートメントを再度実行しません。

リクエスト ID を指定するには、 ユニバーサル一意識別子(UUID) を生成し、この識別子を requestId クエリパラメーターに含めます。例:

POST /api/statements?requestId=ea7b46ed-bdc1-8c32-d593-764fcad64e83 HTTP/1.1

Snowflakeがリクエストの処理に失敗した場合、同じリクエスト ID で同じリクエストを再度送信できます。同じリクエスト ID を使用すると、同じリクエストを再度送信することをサーバーに示します。

SQL ステートメントの実行リクエストの送信

実行のために SQL ステートメントを送信するには、 /api/statements/ リクエストを POST エンドポイントに送信します。詳細については POST /api/statements をご参照ください。

POST /api/statements HTTP/1.1
(request body)

リクエストの設定

リクエスト URL では、クエリパラメーターを次のように設定できます。

リクエストの本文 には、次のフィールドを設定します。

  • 実行する SQL ステートメントに statement フィールドを設定します。

    単一リクエストで複数のステートメントを送信する場合は、ステートメントの間にセミコロン(;)を使用します。詳細については 単一リクエストによる複数の SQL ステートメントの送信 をご参照ください。

  • ステートメントにバインド変数(? プレースホルダー)を含める場合は、各変数に対応するSnowflakeデータ型と値を指定するオブジェクトに bindings フィールドを設定します。

    詳細については、 ステートメントでのバインド変数の使用 をご参照ください。

  • 使用するウェアハウス、データベース、スキーマ、およびロールを指定するには、 warehousedatabaseschema、および role フィールドを設定します。

    これらのフィールドの値では、大文字と小文字が区別されます。

  • ステートメント実行のタイムアウトを設定するには、 timeout フィールドを待機する最大秒数に設定します。 timeout フィールドが設定されていない場合は、 STATEMENT_TIMEOUT_IN_SECONDS パラメーターで指定されたタイムアウトが使用されます。

  • クエリが多数の行を返す場合は、 pageSize パラメーターを設定します。そうしないと、行数がページ内のデフォルトの行数を超える可能性があります。

リクエストの例

たとえば、次の curl コマンドは、実行のために SQL ステートメントを送信します。この例では、ファイル request-body.json を使用してリクエストの本文を指定しています。

curl -i -X POST \
    -H "Authorization: Bearer <jwt>" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "User-Agent: myApplicationName/1.0" \
    -H "X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT" \
    -d "@request-body.json" \
    https://<account_identifier>.snowflakecomputing.com/api/statements

条件:

この例では、 request-body.jsonリクエストの本文 が含まれています。

{
  "statement": "select * from T where c1=?",
  "timeout": 60,
  "resultSetMetaData": {
    "format": "json"
  },
  "database": "TESTDB",
  "schema": "TESTSCHEMA",
  "warehouse": "TESTWH",
  "role": "TESTROLE",
  "bindings": {
    "1": {
      "type": "FIXED",
      "value": "123"
    }
  }
}

上記の例では、

  • リクエスト URL の pageSize リクエストパラメーター(&pageSize=10)は、各応答の結果セットに最大10行を含めることを指定します。

  • リクエストの本文で、

    • statement フィールドは、実行する SQL ステートメントを指定します。

      このステートメントには、 バインド変数"cl=?" の疑問符)が含まれています。これは、 bindings フィールドで指定された最初のバインド("1")に評価されます。

    • timeout フィールドは、サーバーがステートメントの実行に60秒許可することを指定します。

    • databaseschemawarehouse、および role フィールドは、ステートメントの実行時に TESTDB データベース、 TESTSCHEMA スキーマ、 TESTWH ウェアハウス、および TESTROLE ロールを使用することを指定します。

ステートメントでのバインド変数の使用

ステートメントでバインド変数(? プレースホルダー)を使用する場合は、 bindings フィールドを使用して、挿入する値を指定します。

このフィールドは、各バインド変数の Snowflakeデータ型 と値を指定する JSON オブジェクトに設定します。

...
"statement": "select * from T where c1=?",
...
"bindings": {
  "1": {
    "type": "FIXED",
    "value": "123"
  }
},
...

バインドする値の型に対応するバインド型を選択します。たとえば、値が日付(例: 2021-04-15)を表す 文字列 であり、その値を DATE 列に挿入する場合は、 TEXT バインド型を使用します。

次の表は、このプレビューリリースのさまざまな Snowflakeデータ型 にバインドするために使用できる type フィールドの値を示しています。

  • 左の最初の列は、使用できるバインド型を示しています。

  • 残りの列は、データを挿入する予定の列のSnowflakeデータ型を指定します。

  • 各セルは、特定のSnowflakeデータ型の列にデータを挿入する際にバインド型で使用できる値の型を指定します。

    バインド型とSnowflakeデータ型のセルが空の場合は、指定されたバインド型を使用して、そのSnowflakeデータ型の列にデータを挿入することはできません。

さまざまなSnowflakeデータ型でサポートされているバインド型

Snowflakeデータ型

INT / NUMBER

FLOAT

VARCHAR

BINARY

BOOLEAN

DATE

TIME

TIMESTAMP_TZ

TIMESTAMP_LTZ

TIMESTAMP_NTZ

. 型のバインド

FIXED

整数

整数

整数

0(false)/0以外(true)

REAL

整数

整数または浮動小数点数

整数または浮動小数点数

0/0以外

TEXT

整数

整数または浮動小数点数

任意のテキスト

16進数

"true" / "false"

以下のメモを参照

以下のメモを参照

以下のメモを参照

以下のメモを参照

以下のメモを参照

BINARY

16進数

BOOLEAN

true/false、0/1

true/false

DATE

エポック(ミリ秒)

エポック(ミリ秒)

エポック(ミリ秒)

エポック(ミリ秒)

エポック(ミリ秒)

TIME

エポック(ナノ)

エポック(ナノ)

TIMESTAMP_TZ

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

TIMESTAMP_LTZ

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

TIMESTAMP_NTZ

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

エポック(ナノ)

次の点に注意してください。

  • バインド変数の値は文字列である必要があります(たとえば、値 1.0 の場合は "1.0")。

  • DATE バインド型を使用する場合は、エポック以降の ミリ秒 の数を指定します。

  • TIME または TIMESTAMP* バインド型を使用する場合は、エポック以降の ナノ秒 の数を指定します。

  • TIMESTAMP_TZ バインド型を使用する場合は、エポック以降の ナノ秒 の数を指定し、その後にスペースと分単位のタイムゾーンオフセットを指定します(例: 1616173619000000000 960)。

  • TEXT バインド型を使用する場合は、

    • DATE 列にデータを挿入するには、 AUTO 検出でサポートされている任意の 日付形式 を使用できます。

    • TIME 列にデータを挿入するには、 AUTO 検出でサポートされている任意の 時間形式 を使用できます。

    • TIMEZONE* 列にデータを挿入するには、 AUTO 検出でサポートされている任意の 日時形式 を使用できます。

値がSnowflakeでサポートされていない形式の場合、 API はエラーを返します。

{
  code: "100037",
  message: "<bind type> value '<value>' is not recognized",
  sqlState: "22018",
  statementHandle: "<ID>"
}

応答の処理

デフォルトでは、Snowflakeはステートメントを同期的に実行し、以下のフローチャートに示されている応答コードのいずれかを返します。

Flow chart for submitting a statement for execution

上記のフローチャートに示されているように、

  • 正常に実行された1つのステートメントを送信した場合、Snowflakeは HTTP 応答コード200と結果の行を ResultSet オブジェクトに返します。

    ResultSet オブジェクトを使用して、 結果を取得 します。

    オブジェクトには、 pageSize パラメーターで指定された最大行数が含まれることに注意してください。 ResultSet_resultSetMetaDatanumRows フィールドが結果の追加の行があることを示している場合は、 結果の追加ページの取得 をご参照ください。

  • 単一リクエストで複数のステートメント を送信し、リクエストの処理に成功した場合、Snowflakeは HTTP 応答コード200と ResultSet オブジェクトを返します。

    ResultSet オブジェクトには、結果の行が含まれていません。代わりに、 data フィールドには「複数のステートメントが正常に実行されました」というメッセージが含まれるだけです。

    データを取得するには、 statementHandles フィールドから、リクエスト内にある個々のステートメントのハンドルを取得する必要があります。各ステートメントのハンドルのためにリクエストを送信して、ステートメントの実行ステータスを確認します。 ステートメントの実行ステータスの確認およびデータの取得 をご参照ください。

    複数の SQL ステートメントを指定するリクエストの応答を処理するプロセスの詳細については、 リクエスト内にある各 SQL ステートメントの結果の取得 をご参照ください。

  • ステートメントの実行に45秒以上かかる場合、またはステートメントを非同期で実行するように指定した場合、Snowflakeは QueryStatus オブジェクトとともに HTTP 応答コード202を返します。

    QueryStatus オブジェクトの statementStatusUrl フィールドで指定されたエンドポイントにリクエストを送信して、ステートメントの実行ステータスを確認できます。 ステートメントの実行ステータスの確認およびデータの取得 をご参照ください。

    ステートメントの実行をキャンセルする場合は、 QueryStatus オブジェクトの statementHandle フィールドのステートメントハンドルを使用して、 /api/statements/statementHandle/cancel にリクエストを送信できます。 SQL ステートメントの実行のキャンセル をご参照ください。

ステートメントの実行ステータスの確認およびデータの取得

場合によっては、ステートメントの実行ステータスを確認するためにリクエストを送信する必要があります。

  • 実行する SQL ステートメントを送信 すると、ステートメントの実行がまだ完了していない場合、または非同期クエリを送信した場合、Snowflakeは202応答コードを返します。

    ステートメントの実行が終了したかどうかを確認するには、ステートメントのステータスを確認するリクエストを送信する必要があります。

  • 単一リクエストで複数の SQL ステートメントを送信 した場合は、ステートメントのステータスを確認するリクエストを送信することで、個々のステートメントの結果を取得します。

どちらの場合も、 GET リクエストを /api/statements/ エンドポイントに送信し、ステートメントハンドルをパスパラメーターとして URL パスの最後に追加します。詳細については GET /api/statements/{statementHandle} をご参照ください。

GET /api/statements/{statementHandle}

{statementHandle} は、確認するステートメントのハンドルです。ステートメントハンドルを取得するには、

  • 202応答コードで応答を受信した場合、応答の本文には QueryStatus オブジェクトが含まれます。このオブジェクトの statementHandle フィールドから、ステートメントハンドルを取得できます。

    このオブジェクトの statementStatusUrl フィールドから、リクエストのフル URL も取得できます。

    {
      "code": "090001",
      "sqlState": "00000",
      "message": "successfully executed",
      "statementHandle": "e4ce975e-f7ff-4b5e-b15e-bf25f59371ae",
      "statementStatusUrl": "/api/statements/e4ce975e-f7ff-4b5e-b15e-bf25f59371ae"
    }
    
  • 複数の SQL ステートメントを含むリクエストを送信した場合、応答の本文には statementHandles フィールドを含んだ ResultSet オブジェクトが含まれます。このフィールドから、個々のステートメントのハンドルを取得できます。

    {
      ...
      "statementHandles" : [ "019c9fce-0502-f1fc-0000-438300e02412", "019c9fce-0502-f1fc-0000-438300e02416" ],
      ...
    

たとえば、次の curl コマンドは、ハンドル e4ce975e-f7ff-4b5e-b15e-bf25f59371ae を持つステートメントのステータスをチェックします。

curl -i -X GET \
    -H "Authorization: Bearer <jwt>" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "User-Agent: myApplicationName/1.0" \
    -H "X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT" \
    https://<account_identifier>.snowflakecomputing.com/api/statements/e4ce975e-f7ff-4b5e-b15e-bf25f59371ae

条件:

ステータスを確認するリクエストを送信すると、Snowflakeは以下のフローチャートに示された応答コードの1つを返します。

Flow chart for checking the status of a statement submitted for execution

上記のフローチャートに示されているように、

  • ステートメントの実行が正常に終了した場合、Snowflakeは HTTP 応答コード200と結果の行を ResultSet オブジェクトに返します。

    ResultSet オブジェクトを使用して、 結果を取得 します。

    オブジェクトには、 pageSize パラメーターで指定された最大行数が含まれることに注意してください。 ResultSet_resultSetMetaDatanumRows フィールドが結果の追加の行があることを示している場合は、 結果の追加ページの取得 をご参照ください。

  • ステートメントの実行が完了していない場合、Snowflakeは HTTP 応答コード202を QueryStatus オブジェクトとともに返します。

    このオブジェクトを使用して、 ステートメントの実行ステータスを確認 します。

  • ステートメントの実行中にエラーが発生した場合、Snowflake は QueryFailureStatus オブジェクトとともに HTTP 応答コード422を返します。

    このオブジェクトから、 エラーに関する詳細 を取得できます。

応答からの結果の取得

実行用に SQL ステートメントを送信する か、 ステートメント実行のステータスを確認する 場合、ステートメントが正常に実行されたときに、Snowflakeは応答の本文に ResultSet オブジェクトを返します。

以下は、クエリに対して返される ResultSet オブジェクトの例です。クエリは、結果がページ当たり10行でページ分割されることを指定しています。 resultSetMetaData オブジェクトの numPages フィールドは10ページの結果があることを示し、 numRows フィールドはクエリが合計100行を見つけたことを示します。

{
 "code": "090001",
 "statementHandle": "536fad38-b564-4dc5-9892-a4543504df6c",
 "sqlState": "00000",
 "message": "successfully executed",
 "createdOn": 1597090533987,
 "statementStatusUrl": "/api/statements/536fad38-b564-4dc5-9892-a4543504df6c",
 "resultSetMetaData": {
  "page": 1,
  "pageSize": 10,
  "numPages": 10,
  "numRows": 100,
  "format": "json",
  "rowType": [
   {
    "name":"ROWNUM",
    "type":"FIXED",
    "length":0,
    "precision":38,
    "scale":0,
    "nullable":false
   }, {
    "name":"ACCOUNT_NAME",
    "type":"TEXT",
    "length":1024,
    "precision":0,
    "scale":0,
    "nullable":false
   }, {
    "name":"ADDRESS",
    "type":"TEXT",
    "length":16777216,
    "precision":0,
    "scale":0,
    "nullable":true
   }, {
    "name":"ZIP",
    "type":"TEXT",
    "length":100,
    "precision":0,
    "scale":0,
    "nullable":true
   }, {
    "name":"CREATED_ON",
    "type":"TIMESTAMP_NTZ",
    "length":0,
    "precision":0,
    "scale":3,
    "nullable":false
   }
  ]
 },
 "data": [
  ["0","customer1","1234 A Avenue","98765","1565481394123000000"],
  ["1","customer2","987 B Street","98765","1565516712912012345"],
  ["2","customer3","8777 C Blvd","98765","1565605431999999999"],
  ["3","customer4","64646 D Circle","98765","1565661272000000000"]
  ...
 ]
}

結果セットのページサイズが制限を超えているかどうかの判断

SQL API は、 最大サイズが約10 MB の結果セットページを返すことができます。結果セットページがこのサイズを超える場合、エンドポイントには本文に切り捨てられた結果セットが含まれ、 code フィールドが 391908 に設定された HTTP 応答を返します。

HTTP/1.1 200 OK
...
{
  "code": "391908",
  ...

これが発生した場合は、 pageSize パラメーターをページの最大サイズ内に収まる小さな値に設定して、リクエストを再度送信します。

注釈

現在、Snowflakeはこれが発生したときに HTTP 200応答コードを返しますが、これは変更される可能性があります。

結果に関するメタデータの取得

応答で返される ResultSet オブジェクトの resultSetMetaData フィールドには、結果セット(結果の形式、結果のページ数など)を説明する ResultSet_resultSetMetaData オブジェクトが含まれます。

このオブジェクトの rowType フィールドには、 ResultSet_resultSetMetaData_rowType オブジェクトの配列が含まれます。各オブジェクトは、結果の列を表します。 type フィールドは、列のSnowflakeデータ型を指定します。

{
 "resultSetMetaData": {
  "rowType": [
   {
    "name":"ROWNUM",
    "type":"FIXED",
    "length":0,
    "precision":38,
    "scale":0,
    "nullable":false
   }, {
    "name":"ACCOUNT_NAME",
    "type":"TEXT",
    "length":1024,
    "precision":0,
    "scale":0,
    "nullable":false
   }, {
    "name":"ADDRESS",
    "type":"TEXT",
    "length":16777216,
    "precision":0,
    "scale":0,
    "nullable":true
   }, {
    "name":"ZIP",
    "type":"TEXT",
    "length":100,
    "precision":0,
    "scale":0,
    "nullable":true
   }, {
    "name":"CREATED_ON",
    "type":"TIMESTAMP_NTZ",
    "length":0,
    "precision":0,
    "scale":3,
    "nullable":false
   }
  ]
 },
}

結果からのデータの取得

応答の ResultSet オブジェクトでは、結果は data フィールドにあります。 data フィールドには、JSON にある配列の配列が含まれます。例:

{
 "data": [
  ["0","customer1","1234 A Avenue","98765","1565481394123000000"],
  ["1","customer2","987 B Street","98765","1565516712912012345"],
  ["2","customer3","8777 C Blvd","98765","1565605431999999999"],
  ["3","customer4","64646 D Circle","98765","1565661272000000000"]
 ],
}

配列内の各配列には、行のデータが含まれます。

  • 各配列の最初の要素は、0から始まるシーケンス ID を含む JSON 文字列です。

  • 各配列の残りの要素は、行のデータを表します。

結果セットのデータは JSON v1.0でエンコードされます。これは、列のSnowflakeデータ型に関係なく、すべてのデータが文字列として表現されることを意味します。

たとえば、 NUMBER 列の値 1.0 は文字列 "1.0" として返されます。別の例として、タイムスタンプはエポック以降のナノ秒数として返されます。たとえば、2021年1月28日木曜日10:09:37.123456789 PM のタイムスタンプは "1611871777123456789" として返されます。

ユーザーには、文字列を適切なデータ型に変換する責任があります。

Snowflakeは、 Snowflakeデータ型 に応じて、次の形式の文字列として値を返します。

INT / NUMBER

文字列内の10進数。

FLOAT

文字列の整数または浮動小数点数。

VARCHAR

文字列。

BINARY

文字列の16進数。

BOOLEAN

文字列の0(false)または1(true)。

DATE

エポック(例: 18262)以降の日数の整数値(文字列)。

TIME, TIMESTAMP_LTZ, TIMESTAMP_NTZ

エポック(例: 82919.000000000)以降の秒数の浮動小数点値(小数点以下9桁)。

TIMESTAMP_TZ

エポック以降の秒数の浮動小数点値(小数点以下9桁)、その後にスペースと分単位のタイムゾーンオフセットが続きます(例: 1616173619000000000 960

結果の追加ページの取得

結果をページ付けするように pageSize リクエストパラメーターを設定すると、Snowflakeは結果の最初のページを応答で返します。 ResultSet オブジェクトにある ResultSet_resultSetMetaData オブジェクトの numPages フィールドを使用して、結果の合計ページ数を決定できます。

結果の次のページまたは結果の他のページを取得するには、 HTTP 応答の リンクヘッダー で提供される URLs を使用します。 Link ヘッダーは、結果の最初、次、前、および最後のページを取得するための URLs を指定します。

HTTP/1.1 200 OK
Link: </api/statements/e127cc7c-7812-4e72-9a55-3b4d4f969840?page=1>;rel="last",
      </api/statements/e127cc7c-7812-4e72-9a55-3b4d4f969840?page=1>;rel="next",
      </api/statements/e127cc7c-7812-4e72-9a55-3b4d4f969840512c?page=0>;rel="first"
...

ヘッダーの各 URL には、次のいずれかの値を持つ rel 属性があります。

  • first: 結果の最初のページ。

  • next: 結果の次のページ。

  • prev: 結果の前のページ。

  • last: 結果の最後のページ。

単一リクエストによる複数の SQL ステートメントの送信

場合によっては、リクエストで複数の SQL ステートメントを指定する必要があります。たとえば、次が必要になる場合があります。

  • 明示的なトランザクションを定義する

  • ストアドプロシージャを定義する

  • リクエストのステートメントでセッション変数を設定して使用する

  • リクエストのステートメントで仮テーブルを作成して使用する

  • リクエスト内のステートメントのデータベース、スキーマ、ウェアハウス、またはロールを変更する

次のセクションでは、複数の SQL ステートメントを含むリクエストを送信する方法について説明します。

リクエストにおける複数の SQL ステートメントの指定

単一リクエストで複数の SQL ステートメントを送信する場合は、ステートメントの間にセミコロン(;)を使用します。例:

POST /api/statements HTTP/1.1
Authorization: Bearer <jwt>
Content-Type: application/json
Accept: application/json
User-Agent: myApplication/1.0
X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT

{
  "statement": "alter session set QUERY_TAG='mytesttag'; select count(*) from mytable",
  ...

リクエスト内にある各 SQL ステートメントの結果の取得

複数の SQL ステートメントを含むリクエストが正常に処理された場合、応答には個々のステートメントの実行から返されたデータは含まれません。代わりに、応答には、個別ステートメントのハンドルの配列を含む statementHandles フィールドが含まれています。

注釈

statementHandles フィールドは statementHandle フィールドとは異なります。

  • statementHandle フィールドは、リクエストにある SQL のセットに対するステートメントのハンドルを指定します。

  • statementHandles フィールドは、リクエストにある個別 SQL ステートメントのハンドルの配列です。

たとえば、実行のために2つの SQL ステートメントを指定するリクエストを送信するとします。

POST /api/statements HTTP/1.1
Authorization: Bearer <jwt>
Content-Type: application/json
Accept: application/json
User-Agent: myApplication/1.0
X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT

{
  "statement": "select * from A; select * from B",
  ...

応答には、個別ステートメントのハンドルの配列を含む statementHandles フィールドが含まれています。

HTTP/1.1 200 OK
...
{
  ...
  "statementHandles" : [ "019c9fce-0502-f1fc-0000-438300e02412", "019c9fce-0502-f1fc-0000-438300e02416" ],
  ...

ステータスを確認して個々のステートメントのデータを取得するには、 GET リクエストを /api/statements/ エンドポイントに送信し、各ステートメントのハンドルを URL パスに追加します。詳細については ステートメントの実行ステータスの確認およびデータの取得 をご参照ください。

GET /api/statements/019c9fce-0502-f1fc-0000-438300e02412
...
GET /api/statements/019c9fce-0502-f1fc-0000-438300e02416
...

リクエストで複数のステートメントを指定する際のエラーの処理

リクエストで複数の SQL ステートメントを指定し、いずれかのステートメントの実行中にエラーが発生した場合、Snowflakeは QueryFailureStatus オブジェクトを含む HTTP 応答コード422を返します。

このオブジェクトから、 エラーに関する詳細 を取得できます。

たとえば、リクエストで次のステートメントが指定されていて、2番目の INSERT ステートメントにエラーが含まれているとします。

{
  "statement": "create or replace table table1 (i int); insert into table1 (i) values (1); insert into table1 (i) values ('This is not a valid integer.'); insert into table1 (i) values (2); select i from table1 order by i",
  ...

Snowflakeは、 HTTP 応答コード422と、エラーに関する詳細を含む QueryFailureStatus オブジェクトのある応答を返します。

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
...
{
  "code" : "100132",
  "message" : "JavaScript execution error: Uncaught Execution of multiple statements failed on statement \"insert into table1 (i) values ...\" (at line 1, position 75).\nNumeric value 'This is not a valid integer.' is not recognized in SYSTEM$MULTISTMT at '    throw `Execution of multiple statements failed on statement {0} (at line {1}, position {2}).`.replace('{1}', LINES[i])' position 4\nstackstrace: \nSYSTEM$MULTISTMT line: 10",
  "sqlState" : "P0000",
  "statementHandle" : "019d6e97-0502-317e-0000-096d0041f036"
}

上記の例では、エラーのある INSERT ステートメントは、 statement フィールドの の文字位置75から始まります。

エラーのあるステートメントの前のステートメントは正常に実行されます(この例では CREATE TABLE および最初の INSERT ステートメント)。エラーのあるステートメントの後のステートメントは実行されません。

ストアドプロシージャの作成と呼び出し

SQL API を使用して、ストアドプロシージャを作成し、呼び出すことができます。以下は、テーブルの名前を渡し、そのテーブルの行数を返す新しいストアドプロシージャを作成する POST リクエストの本文の例です。

{
  "statement": "create or replace procedure sql_api_stored_proc(table_name varchar) returns varchar language javascript as $$var sql_command = \"select count(*) from \" + TABLE_NAME; var rs = snowflake.execute({sqlText: sql_command}); rs.next(); var rowCount = rs.getColumnValue(1); return rowCount; $$;",
  "resultSetMetaData": {
    "format": "json"
  },
  "role": "MY_ROLE",
  "warehouse": "MY_WAREHOUSE",
  "database": "MY_DB",
  "schema": "MY_SCHEMA"
}

このリクエストに対する応答の本文の例を次に示します。

{
  "resultSetMetaData": {
    "page": 0,
    "numPages": 1,
    "numRows": 1,
    "format": "json",
    "rowType": [ {
      "name": "status",
      "database": "",
      "schema": "",
      "table": "",
      "type": "text",
      "byteLength": 16777216,
      "scale": null,
      "precision": null,
      "nullable": true,
      "collation": null,
      "length": 16777216
    } ]
  },
  "data": [ [ "0", "Function SQL_API_STORED_PROC successfully created." ] ],
  "code": "090001",
  "statementStatusUrl": "/api/statements/019c9f28-0502-f257-0000-438300e0a02a?requestId=...",
  "sqlState": "00000",
  "statementHandle": "019c9f28-0502-f257-0000-438300e0a02a",
  "message": "Statement executed successfully.",
  "createdOn": 1622494569592
}

以下は、ストアドプロシージャを呼び出し、テーブル名「prices」に渡す POST リクエストの本文の例です。

{
  "statement": "call sql_api_stored_proc('prices');",
  "resultSetMetaData": {
    "format": "json"
  },
  "role": "MY_ROLE",
  "warehouse": "MY_WAREHOUSE",
  "database": "MY_DB",
  "schema": "MY_SCHEMA"
}

このリクエストに対する応答の本文の例を次に示します。

{
  "resultSetMetaData": {
    "page": 0,
    "numPages": 1,
    "numRows": 1,
    "format": "json",
    "rowType": [ {
      "name": "SQL_API_STORED_PROC",
      "database": "",
      "schema": "",
      "table": "",
      "type": "text",
      "byteLength": 16777216,
      "length": 16777216,
      "scale": null,
      "precision": null,
      "nullable": true,
      "collation": null
    } ]
  },
  "data": [ [ "0", "4" ] ],
  "code": "090001",
  "statementStatusUrl": "/api/statements/019c9f2a-0502-f244-0000-438300e04496?requestId=...",
  "sqlState": "00000",
  "statementHandle": "019c9f2a-0502-f244-0000-438300e04496",
  "message": "Statement executed successfully.",
  "createdOn": 1622494718694
}

明示的なトランザクションの使用

明示的な トランザクション で SQL ステートメントを実行するには、 単一の HTTP リクエスト を使用して、トランザクション内の開始、終了、およびステートメントを指定する必要があります。例:

{
  "statement": "begin transaction; insert into table2 (i) values (1); commit; select i from table1 order by i",
  ...

リクエストで複数のステートメント を指定する場合と同様に、リクエストが正常に処理された場合、Snowflakeは statementHandles フィールドを含むレスポンスを返します。フィールドは、リクエスト内(BEGIN TRANSACTION および COMMIT ステートメントを含む)にあるステートメントのハンドルの配列に設定されます。

HTTP/1.1 200 OK
Content-Type: application/json

{
  "resultSetMetaData" : {
    "page" : 0,
    "numPages" : 1,
    "numRows" : 1,
    "format" : "json",
    "rowType" : [ {
      "name" : "multiple statement execution",
      "database" : "",
      "schema" : "",
      "table" : "",
      "type" : "text",
      "byteLength" : 16777216,
      "scale" : null,
      "precision" : null,
      "nullable" : false,
      "collation" : null,
      "length" : 16777216
    } ]
  },
  "data" : [ [ "0", "Multiple statements executed successfully." ] ],
  "code" : "090001",
  "statementHandles" : [ "019d6ed0-0502-3101-0000-096d00421082", "019d6ed0-0502-3101-0000-096d00421086", "019d6ed0-0502-3101-0000-096d0042108a", "019d6ed0-0502-3101-0000-096d0042108e" ],
  "statementStatusUrl" : "/api/statements/019d6ed0-0502-3101-0000-096d0042107e?requestId=066920fa-e589-43c6-8cca-9dcb2d4be978",
  "sqlState" : "00000",
  "statementHandle" : "019d6ed0-0502-3101-0000-096d0042107e",
  "message" : "Statement executed successfully.",
  "createdOn" : 1625684162876
}

statementHandles フィールドのハンドルは、リクエストのステートメントに対応しています。この例で、ステートメントとそれに対応するハンドルは次のとおりです。

  • BEGIN TRANSACTION (019d6ed0-0502-3101-0000-096d00421082)

  • INSERT (019d6ed0-0502-3101-0000-096d00421086)

  • COMMIT (019d6ed0-0502-3101-0000-096d0042108a)

  • SELECT (019d6ed0-0502-3101-0000-096d0042108e)

これらのハンドルを使用して、 各ステートメントのステータスを確認 できます。

エラーに関する詳細の取得

ステートメントが正常に実行されない場合、Snowflakeは、以下のフローチャートに示すように、次のいずれかの応答コードを返します。

Flow chart for handling errors during statement execution

このフローチャートに示すように、

  • ステートメントの実行に、リクエストの timeout フィールドで指定されたタイムアウト期間(または timeout フィールドが設定されていない場合は STATEMENT_TIMEOUT_IN_SECONDS パラメーターで指定されたタイムアウト)よりも長い時間がかかる場合、Snowflakeは、 QueryStatus オブジェクトとともに HTTP 応答コード408を返します。

    このオブジェクトを使用して、 ステートメント実行のキャンセルに関する詳細 を取得します。

  • ステートメントの実行中にエラーが発生した場合、Snowflake は QueryFailureStatus オブジェクトとともに HTTP 応答コード422を返します。

    このオブジェクトからエラーの詳細を取得できます。

SQL ステートメントの実行のキャンセル

ステートメントの実行をキャンセルするには、 POST リクエストをキャンセルエンドポイントに送信します。詳細については POST /api/statements/{statementHandle}/cancel をご参照ください。

POST /api/statements/{statementHandle}/cancel

次のフローチャートは、リクエストをキャンセルするために実行するステップを示しています。

Flow chart for cancelling the execution of a statement