5.

SQL シーケンスの完全ガイド(Oracle SEQUENCE / PG SERIAL / MySQL AUTO_INCREMENT)

編集
この記事の要点
  • シーケンスは連番を発行する DB オブジェクト。主キー採番に使う
  • Oracle: CREATE SEQUENCE seq_name START WITH 1 INCREMENT BY 1seq.NEXTVAL / seq.CURRVAL
  • PostgreSQL: SERIAL / IDENTITY (10+)、内部は SEQUENCE
  • MySQL: AUTO_INCREMENT(テーブル属性、独立オブジェクトではない)
  • SQL Server: IDENTITY(1,1) / 独立した CREATE SEQUENCE も両方可
  • ギャップは仕様。ROLLBACK / CACHE 喪失で連番が飛ぶ → 連続番号が必要なら別設計

シーケンスとは

シーケンス (Sequence) は一意な連番を払い出す DB オブジェクトです。主キーの自動採番に使うのが代表的な用途。複数セッションから同時に NEXTVAL してもユニークな値が保証されます。

Oracle の SEQUENCE

-- 作成
CREATE SEQUENCE seq_users_id
    START WITH 1          -- 開始値
    INCREMENT BY 1        -- 増分(負も可、降順可)
    MINVALUE 1
    MAXVALUE 9999999999
    CACHE 20              -- メモリにキャッシュする個数
    NOCYCLE;              -- MAXVALUE に達したらエラー

-- 次の値を取得(毎回進む)
SELECT seq_users_id.NEXTVAL FROM dual;
-- → 1
-- → 2

-- 現在の値を確認(NEXTVAL を一度呼んだセッションのみ)
SELECT seq_users_id.CURRVAL FROM dual;

-- INSERT で使う
INSERT INTO users (id, name) VALUES (seq_users_id.NEXTVAL, 'Alice');

-- Oracle 12c+ は IDENTITY 列もサポート
CREATE TABLE users (
    id NUMBER GENERATED ALWAYS AS IDENTITY,
    name VARCHAR2(100)
);

PostgreSQL の SERIAL / IDENTITY

-- 旧来: SERIAL (内部で SEQUENCE を作る糖衣構文)
CREATE TABLE users (
    id   SERIAL PRIMARY KEY,    -- 内部で users_id_seq が作られる
    name VARCHAR(100)
);

-- PostgreSQL 10+: 標準 SQL の IDENTITY(推奨)
CREATE TABLE users (
    id   INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name VARCHAR(100)
);

-- 独立したシーケンスを作る場合
CREATE SEQUENCE seq_order_no
    START 1000
    INCREMENT BY 1
    MINVALUE 1000
    MAXVALUE 9999
    CYCLE;             -- MAXVALUE に達したら 1000 に戻る

-- 関数で操作
SELECT nextval('seq_order_no');   -- 次の値(進む)
SELECT currval('seq_order_no');   -- 現在の値
SELECT lastval();                  -- 直近の nextval 値
SELECT setval('seq_order_no', 5000);  -- 値を強制変更

-- INSERT 時に DEFAULT
INSERT INTO orders (no, customer) VALUES (DEFAULT, 'Bob');
INSERT INTO orders (no, customer) VALUES (nextval('seq_order_no'), 'Bob');

MySQL の AUTO_INCREMENT

MySQL は独立したシーケンスオブジェクトを持たず、テーブル属性として実装されています。

CREATE TABLE users (
    id   BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100)
);

-- 自動採番
INSERT INTO users (name) VALUES ('Alice');
INSERT INTO users (name) VALUES ('Bob');

-- 直前の値を取得
SELECT LAST_INSERT_ID();

-- 現在の AUTO_INCREMENT 値を確認・変更
SHOW CREATE TABLE users;
ALTER TABLE users AUTO_INCREMENT = 10000;

-- 1 テーブル 1 連番のみ。複雑な採番には不向き
-- → 「採番テーブル」を作って FOR UPDATE で取り回す手も

SQL Server の IDENTITY と SEQUENCE

-- IDENTITY (テーブル属性)
CREATE TABLE users (
    id   INT IDENTITY(1,1) PRIMARY KEY,  -- 開始 1、増分 1
    name NVARCHAR(100)
);
INSERT INTO users (name) VALUES (N'Alice');
SELECT SCOPE_IDENTITY();   -- 直前の IDENTITY 値

-- SEQUENCE オブジェクト (SQL Server 2012+)
CREATE SEQUENCE seq_invoice
    AS INT
    START WITH 1
    INCREMENT BY 1
    CACHE 100;

SELECT NEXT VALUE FOR seq_invoice;

-- INSERT で使用
INSERT INTO invoices (no, customer)
VALUES (NEXT VALUE FOR seq_invoice, 'Acme');

主な DB の比較

DB独立 SEQUENCE列属性取得関数
OracleCREATE SEQUENCEIDENTITY (12c+)seq.NEXTVAL / seq.CURRVAL
PostgreSQLCREATE SEQUENCESERIAL / IDENTITY (10+)nextval('seq')
MySQL / MariaDBCREATE SEQUENCE (MariaDB 10.3+ のみ)AUTO_INCREMENTLAST_INSERT_ID()
SQL ServerCREATE SEQUENCE (2012+)IDENTITYNEXT VALUE FOR seq
SQLite無し(rowid + AUTOINCREMENT)AUTOINCREMENTlast_insert_rowid()

CACHE / NOCACHE の意味

CACHE は連番をまとめてメモリに事前確保することで性能を上げる仕組みです。一方で、サーバクラッシュ時にキャッシュ分の番号が飛ぶ(消費済み扱い)欠点があります。

-- Oracle: CACHE 20 → 20 個まとめてメモリ確保
CREATE SEQUENCE seq_log_id CACHE 20;
-- 高速だがクラッシュ時に最大 19 番飛ぶ

-- 連番を絶対に飛ばしたくない場合
CREATE SEQUENCE seq_invoice_no NOCACHE ORDER;
-- ★ 性能は落ちる(毎回 Disk 書き)

-- PostgreSQL も同様
CREATE SEQUENCE seq_id CACHE 1;  -- キャッシュ無効化

-- どっちみち ROLLBACK でも番号は戻らない(仕様)

ギャップ(欠番)が発生するケース

  • ROLLBACK: NEXTVAL 後にトランザクションを ROLLBACK しても番号は戻らない
  • サーバ再起動: CACHE 中の未使用番号が飛ぶ
  • INSERT 失敗: 制約違反等で行が作られなくても消費済み
  • 並列実行: A セッションが 5、B セッションが 6 を取って A だけコミット成功 → 6 が飛ぶこともある

「請求書番号で欠番が許されない」等の業務要件には、シーケンスではなく採番テーブル + FOR UPDATE でアプリ制御する設計が必要です(性能は犠牲)。

-- 連番採番テーブル方式(連番保証あり)
CREATE TABLE number_pool (
    pool_name VARCHAR(50) PRIMARY KEY,
    next_val  BIGINT NOT NULL
);
INSERT INTO number_pool VALUES ('invoice', 1);

-- 採番(同一トランザクション内)
BEGIN;
SELECT next_val FROM number_pool
WHERE pool_name = 'invoice' FOR UPDATE;   -- ★ 行ロック
-- 取得した値を使い、+1 する
UPDATE number_pool SET next_val = next_val + 1
WHERE pool_name = 'invoice';
-- INSERT INTO invoices ...
COMMIT;
-- ROLLBACK 時は採番テーブルも戻るので連番が維持される

FAQ

Q: シーケンスの値をリセットしたい
A: Oracle は ALTER SEQUENCE ... RESTART START WITH 1(19c+)または DROP + CREATE。PG: ALTER SEQUENCE seq RESTART 1 / SELECT setval('seq', 1)。MySQL: ALTER TABLE t AUTO_INCREMENT = 1

Q: 複数テーブルで同じシーケンスを使える?
A: 独立シーケンス系(Oracle / PG / SQL Server)は可能。MySQL の AUTO_INCREMENT はテーブル固有なので不可。

Q: 取得した NEXTVAL を SELECT 後に INSERT で使うのは安全?
A: 同一セッション内なら安全。Oracle/PG の RETURNINGLAST_INSERT_ID() を使うのが定石。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 表(テーブル)
  2. 索引(インデックス)
  3. ビュー
  4. 制約
  5. 順序(シーケンス)
  6. シノニム
  7. トリガー
  8. パッケージ
  9. ストアド・ファンクション
  10. ストアド・プロシージャ
  11. ユーザー(USER)

最近更新/作成されたページ