redshift-api について
Amazon Redshift Data API のクエリと管理操作を、ガイダンスとスクリプトで支援するスキルです。Data API を使うデータワークフロー向けに、非同期実行、状態確認、結果のページング取得をまとめ、カタログ参照やバッチ、キャンセルも扱います。
主な機能
- 01SQL の送信とステートメント状態の確認
- 02クエリ結果のページング取得とデコード
- 03ID による再開またはキャンセル
- 04トランザクション内で複数ステートメントを実行
- 05データベース、スキーマ、テーブル、列の参照
活用シーン
- 01クエリを実行しページング結果を取得
- 02待機タイムアウト後に ID で処理を再開
- 03テーブル構造の確認やトランザクションバッチの実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ anthropics/ claude-tag-plugins --skill redshift-apiインストール後、Claude Code で/redshift-apiを入力して読み込まれたか確認します。
同梱ファイルreferences/api.mdscripts/rs_query.sh
詳細
Amazon Redshift Data API では、すべての呼び出しが https://redshift-data.<region>.amazonaws.com/ への POST であり、
Content-Type: application/x-amz-json-1.1 と X-Amz-Target: RedshiftData.<Action> を指定します。REST 形式のパスはありません。API は完全に非同期です。ステートメントを送信して Id を受け取り、完了するまで
DescribeStatement をポーリングし、その後 GetStatementResult で結果をページ単位で取得します。
scripts/rs_query.sh(操作 1)がこの一連の処理を代わりに実行します。同じ呼び出しはプロビジョンドクラスターと Serverless の両方で使えます。異なるのは接続先フィールドだけです。
リクエストの設定
認証はランタイムが処理します。この API へのリクエストは、ワークスペースに設定された認証情報で署名されるため、設定作業は不要です。AWS キーを取得したり、自分でリクエストに署名したりしないでください。AccessDeniedException が継続して発生する場合、その認証情報はこのワークスペースに設定されていません。認証のデバッグではなく、その旨を報告してください。
実際に必要な設定は 2 つあります。
1. リージョン — エンドポイントのホスト名に含まれています。
export AWS_DEFAULT_REGION="us-east-1" # the region your cluster / workgroup is in
2. 接続先 — Data API が接続するクラスター/ワークグループとデータベースです。いずれかを選び、対応する JSON フィールドを RS_TARGET に設定してください。以下の手順では、これを各リクエスト本文にマージします。
- Serverless —
WorkgroupNameを渡します。設定された ID はデータベースユーザーにマッピングされます。最も簡単な方法です。 - プロビジョンド、一時認証情報 —
ClusterIdentifierとDbUserを渡します。Data API が内部でデータベースの認証情報を解決します。 - プロビジョンドまたは Serverless、Secrets Manager — データベースのログイン情報を保持するシークレットを指す
SecretArnを渡します。
該当する設定を一度だけ行います。
export RS_DATABASE="dev"
# Serverless:
export RS_TARGET='{"WorkgroupName": "my-workgroup"}'
# — or provisioned + temp creds:
# export RS_TARGET='{"ClusterIdentifier": "my-cluster", "DbUser": "my_user"}'
# — or either + Secrets Manager:
# export RS_TARGET='{"ClusterIdentifier": "my-cluster", "SecretArn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:rs-creds-AbCdEf"}'
以下で使用するヘルパー。 1 つの関数で、エンドポイント、ヘッダー、アクション名をまとめて指定します。Authorization ヘッダーはプレースホルダーであり、ランタイムが実際の署名に置き換えます。
rsapi() {
local action="$1"
curl -sS "https://redshift-data.${AWS_DEFAULT_REGION}.amazonaws.com/" \
-H "Content-Type: application/x-amz-json-1.1" \
-H "X-Amz-Target: RedshiftData.${action}" \
-H "Authorization: placeholder" \
-d "${2:?rsapi needs a JSON body as the second argument}"
}
動作確認 — データベースを一覧表示します。Databases 配列を含む 200 が返れば、ワークスペースが正しく接続され、接続先も正しいことを確認できます。エラーには、失敗したレイヤーが示されます。
rsapi ListDatabases "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" \
'$t + {Database: $db}')" | jq .
基本操作
データベースに接続するすべてのアクションで、同じ接続先のマージ済み本文、$t + {Database: $db, ...} を使用します。エラーは期待される形式ではなく、{"__type": "<Exception>", "message": "..."} として返されます。どの呼び出しでも、トップレベルのフィールド(Id、Status、Records など)が存在しない場合は、エラーの内容が返されています。表示して処理を停止してください。
1. クエリを実行する(scripts/rs_query.sh)
同梱のスクリプトを使って SQL を実行します(パスはこのスキルのディレクトリからの相対パスです)。ExecuteStatement で送信し、終端状態になるまで DescribeStatement をポーリングし、NextToken を使って GetStatementResult から結果をページ単位で取得して、型情報を含む 1 キーのセルオブジェクトをデコードします。
scripts/rs_query.sh \
'SELECT event_name, COUNT(*) AS n FROM public.events
WHERE event_date >= :start GROUP BY 1 ORDER BY 2 DESC LIMIT 20' \
--param start=2024-01-01 --name top-events
- SQL は 1 つの引数として指定するか、標準入力から渡します。インスタンス固有の設定には、上記の
AWS_DEFAULT_REGION/RS_TARGET/RS_DATABASEを使用します。--databaseを指定するとデータベースを上書きできます。 --param NAME=VALUE(複数回指定可能)で:NAMEプレースホルダーにバインドします。値は常に文字列であり、データベース側で型変換されます。--nameを指定するとStatementNameが設定され、クエリがListStatementsに表示されます。--max-rows Nは取得する行数の上限です(デフォルトは 10000、0= すべて)。--jsonを指定すると、ヘッダー付き TSV の代わりに、1 行につき 1 つの JSON オブジェクトを出力します。ステートメント ID、ステータス、実行時間、行数は stderr に出力されます。- 終了コード:
0は成功、1は送信失敗または SQL のFAILED/ABORTED(API 自体のメッセージを stderr に出力)、2は--max-wait秒(デフォルトは 600)の経過後に待機を中断した場合です。ステートメント ID は stderr に出力されます。操作 2 で再開してください。
スクリプトでエラーが発生した場合は、内容を確認してください。これは通常の curl と jq です。references/api.md を参照してデバッグしてください。
BatchExecuteStatement とサブステートメントの結果、セッションの再利用(SessionKeepAliveSeconds/SessionId)、ResultFormat: CSV、キャンセル、またはカタログの閲覧には、以下のアクションを使用してください。
2. IDでステートメントを再開する(DescribeStatement → GetStatementResult)
スクリプトが終了コード2(タイムアウト)で終了した場合や、別の場所でステートメント ID を取得した場合は、直接ポーリングして取得します。
rsapi DescribeStatement "$(jq -n --arg id "$ID" '{Id: $id}')" \
| jq '{Status, Duration, ResultRows, HasResultSet, Error}'
rsapi GetStatementResult "$(jq -n --arg id "$ID" '{Id: $id}')" \
| jq -r '.Records[]? | [.[] | if .isNull then null else to_entries[0].value end] | @tsv'
StatusはSUBMITTED、PICKED、STARTED、FINISHED、FAILED、ABORTEDのいずれかです。行を含むのはHasResultSet: trueのFINISHEDのみです。FAILEDの場合、SQL エラーは.Errorに格納されます。Durationの単位は ナノ秒 です。- 結果のセルは、1つのキーを持つ型付きオブジェクトです(「エラー処理」の注意点を参照)。列名と型は、最初のページの
.ColumnMetadataにあります。続きのページはNextTokenで取得します。ページサイズを指定するパラメーターはありません。DescribeStatement.ResultRowsには、最初から合計行数が格納されています。
3. 実行中のステートメントをキャンセルする(CancelStatement)
rsapi CancelStatement "$(jq -n --arg id "$ID" '{Id: $id}')" | jq .
# {"Status": true} on success — best-effort, check DescribeStatement to confirm.
4. 1回の呼び出しで複数のステートメントを実行する(BatchExecuteStatement)
すべてのステートメントは1つのトランザクションで実行され、すべてコミットされるか、すべてロールバックされます。
rsapi BatchExecuteStatement "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" '$t + {
Database: $db,
Sqls: ["CREATE TEMP TABLE tmp AS SELECT 1 AS x", "SELECT * FROM tmp"]
}')" | jq '{Id}'
親 Id に対する DescribeStatement は、SubStatements[] 配列を返します。各サブステートメントには独自の Id(親 ID に :1、:2、…を付加したもの)、Status、HasResultSet があります。各サブステートメントの結果は、それぞれの GetStatementResult 呼び出しで取得します。
5. 最近のステートメントを一覧表示する(ListStatements)
rsapi ListStatements '{"MaxResults": 20, "Status": "ALL"}' \
| jq '.Statements[] | {Id, StatementName, Status, QueryString: (.QueryString[0:80]), CreatedAt}'
Status フィルター:SUBMITTED、PICKED、STARTED、FINISHED、FAILED、ABORTED、ALL。指定しない場合は、完了したステートメントのみが一覧表示されます。MaxResults は0~100です。RoleLevel のデフォルトは true です(同じ IAM ロールを引き受けているすべてのユーザーのステートメントを含みます)。false に設定すると、このセッションのステートメントのみが表示されます。
6. カタログを参照する(ListDatabases / ListSchemas / ListTables / DescribeTable)
4つのアクションすべてで、統合されたターゲット本文を指定します。パターンでは SQL の LIKE ワイルドカード(%、_)を使用します。
ListDatabases—Databases[](文字列)ListSchemas—SchemaPattern(任意)—Schemas[](文字列)ListTables—SchemaPattern、TablePattern—Tables[] {schema, name, type}—typeはTABLE/VIEW/SYSTEM TABLE/GLOBAL TEMPORARY/LOCAL TEMPORARY/ALIAS/SYNONYMのいずれかですDescribeTable—Schema、Table—ColumnList[] {name, typeName, nullable, length, precision}
rsapi ListTables "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" \
'$t + {Database: $db, SchemaPattern: "public", TablePattern: "ev%"}')" | jq '.Tables'
JSON フィールド名は PascalCase です(workgroup-name ではなく WorkgroupName)。4つのアクションすべてでページネーションが行われます(NextToken)。各アクションの本文の形式については、references/api.md を参照してください。
ページネーション
GetStatementResult、ListStatements、ListDatabases、ListSchemas、ListTables、DescribeTable はすべて同じ方式を使用します。次のページがある場合、レスポンスに NextToken が含まれます。次のリクエスト本文で NextToken として渡してください。値がなくなったら終了です。
レート制限
- アクティブなステートメント — クラスターまたはワークグループごとに、最大500件のアクティブなステートメント(
SUBMITTED/STARTED)を実行できます。上限を超えると、送信はActiveStatementsExceededExceptionで失敗します。 - 結果サイズ — ステートメントあたり500 MB(gzip 圧縮後)、1行あたり64 KBです。これを超える結果は失敗します。
LIMITを追加するか、UNLOAD ... TO 's3://...'を使用してください。 - 結果の保持期間 — 24時間です。その後は
GetStatementResultがResourceNotFoundExceptionを返します。 - ステートメントの実行時間 — 最大24時間です。クエリ文字列 — 最大100 KBです。
- API レート — アカウント/リージョンごとに固定され、調整できない TPS クォータがあります。
DescribeStatementは100、ExecuteStatementは30、GetStatementResultは20、BatchExecuteStatementは20、CancelStatement、ListStatements、ListDatabases、ListSchemas、ListTables、DescribeTableはそれぞれ 3 TPS のみです。上限を超えるとThrottlingException(HTTP 400)が返されます。間隔を空けて再試行し、短時間に連続してポーリングしないでください。
エラー処理
エラーは {"__type": "<Exception>", "message": "..."} として返されます(HTTP 400/403/500)。__type
フィールドが判別子です。
ValidationException(400) — パラメーターが不正です。よくある例:ClusterIdentifierとWorkgroupNameを両方指定する、またはどちらも指定しない、Databaseが不足している、フィールドの大文字・小文字が正しくない。ActiveStatementsExceededException(400) — 実行中のステートメントが多すぎます。ListStatements{"Status":"STARTED"}で実行中のものを確認できます。ActiveSessionsExceededException(400) — 開いているセッションが500を超えています。SessionKeepAliveSecondsの指定をやめるか、アイドル状態のセッションが期限切れになるまで待ってください。ExecuteStatementException(500) — DB がリクエストを受け取る前に送信に失敗しました。クラスター名またはワークグループ名が間違っている、クラスターに到達できない、DbUserが不正であるなどの原因が考えられます。RS_TARGETを確認してください。ResourceNotFoundException(400) — ステートメント ID が不明、または24時間以上経過しています。BatchExecuteStatementException(500) — バッチ内のステートメントが失敗し、トランザクション全体がロールバックされました。SubStatements[].Errorを確認してください。DatabaseConnectionException/QueryTimeoutException— カタログ呼び出しでデータベースに接続できなかったか、タイムアウトしました。接続先が稼働していることを確認し、再試行してください。AccessDeniedException(403) — 認証情報にはクラスターまたはワークグループの ARN に対するredshift-data:*が必要です。さらに、接続モードに応じてredshift:GetClusterCredentials/redshift-serverless:GetCredentials/secretsmanager:GetSecretValueも必要です。不足している権限を報告してください。InternalServerException(500) —ClientTokenを渡さない限り、ExecuteStatementは冪等ではありません。書き込みを再試行する前にListStatementsを確認してください。DescribeStatementのStatus: FAILED— 送信後に SQL が失敗しました。.Errorで SQL のエラーメッセージを確認してください。
注意点が2つあります。
ExecuteStatementが200を返しても、クエリの成功を意味しません。 SQL エラーは後からDescribeStatementのStatus: FAILEDとして現れます。結果を取得する前に必ずポーリングしてください。- セルの値は型情報を持つ1キーのオブジェクトであり、単なる値ではありません。
longValueは JSON の数値で、isNull: trueは別の形式です。単純な.valueの読み取りでは何も返されず、型付きキーに対して jq の//を連結するとfalse/0で問題が起きます。to_entries[0].valueを使用してください。
さらに詳しく
references/api.md には完全なカタログがあり、各アクションのリクエスト/レスポンス形式(生の HTTP 向けの PascalCase)、
SqlParameter のバインド形式、ColumnMetadata のフィールド、バッチ用の SubStatementData、セッションの再利用(SessionKeepAliveSeconds / SessionId)、クォータ表を確認できます。上記で扱っていないアクションや、生の HTTP リクエスト本文の正確な形式を確認する必要がある場合は、こちらをお読みください。