Query Go
更新した行を返す - RETURNING / OUTPUT の使い方・オプション・サンプル

更新した行を返す - RETURNING / OUTPUT

INSERT/UPDATE/DELETE の影響行を返す。PostgreSQL RETURNING、SQL Server OUTPUT、MySQL 非対応

概念図

RETURNING / OUTPUT diagram

構文

sql
INSERT ... RETURNING col1, col2;

サンプル

追加で SELECT せず、INSERT と同時に生成値を取得する

sql
-- PostgreSQL: 挿入した行の id と created_at を取得
INSERT INTO users (name, email)
VALUES ('Alice', 'alice@example.com')
RETURNING id, created_at;

RETURNING とは

RETURNINGINSERT / UPDATE / DELETE 文で、影響を受けた行の値を SELECT 相当で返す機能です。採番された id、デフォルト値の created_at、更新前後の比較などを 追加クエリなしで 取得できます。

レースコンディションに強く、last_insert_id() のような副作用 API への依存を減らせる点でもメリットが大きいです。

PostgreSQL の RETURNING

PostgreSQL はすべての DML(INSERT / UPDATE / DELETE / MERGE)で RETURNING をサポートします。RETURNING * で全列、特定列だけでも指定可能。

SQLite も 3.35 以降で RETURNING をサポート。MariaDB も INSERT / DELETE で対応、UPDATE は 10.5 以降で部分対応。

sql
-- 更新と同時に更新後の値を取得
UPDATE orders
SET status = 'shipped', shipped_at = CURRENT_TIMESTAMP
WHERE id = 100
RETURNING id, status, shipped_at;

-- 削除した行をログに残す
DELETE FROM sessions
WHERE expires_at < CURRENT_TIMESTAMP
RETURNING id, user_id;

SQL Server の OUTPUT

SQL Server は OUTPUT 句で同等の機能を提供します。INSERTEDDELETED の 2 つの擬似テーブルを参照でき、UPDATE では 両方を同時に参照できるので「更新前後の差分」を 1 文で取得できます。

sql
-- SQL Server: 更新前後の値をログに残す
UPDATE orders
SET status = 'shipped'
OUTPUT
  DELETED.id,
  DELETED.status AS old_status,
  INSERTED.status AS new_status
WHERE id = 100;

-- OUTPUT INTO で監査テーブルに直接書き込み
DELETE FROM users
OUTPUT DELETED.* INTO users_archive
WHERE status = 'deleted';

MySQL は非対応

MySQL は 2026 年時点でも RETURNING / OUTPUT に相当する構文を持ちません。代替策として次のような手段があります。

  • INSERT の採番 id: LAST_INSERT_ID() 関数、またはドライバの返却値(lastInsertId / AUTO_INCREMENT
  • UPDATE / DELETE 後の値: 直前に SELECT ... FOR UPDATE で値を取得し、トランザクション内で書き換える
  • MariaDB を選ぶ: MariaDB は INSERT / DELETE / UPDATE (10.5+) で RETURNING をサポート

落とし穴: トリガと制約の順序

  • BEFORE トリガが値を書き換えた場合: RETURNING / INSERTED が返すのはトリガ適用の値。「クライアントが送った値」ではない点に注意
  • AFTER トリガの失敗: RETURNING が返ってきても、AFTER トリガで例外が出ればトランザクションはロールバックされる
  • OUTPUT INTO と FK: SQL Server の OUTPUT INTO は、ターゲットテーブルに外部キー・トリガ・チェック制約があると使えない制限がある

関連トピック