テーブルに行番号のような、データを一意に特定するための列を作りたいことはよくあります。このようなときに使われるのがシーケンスです。
デフォルトでは、シーケンスは1から始まり、1ずつカウントアップされていきます。ID列など他の行と値を重複させたくないときに使うことができます。
PostgreSQL では、CREATE SEQUENCE 文によってシーケンスを作成することができます。
CREATE SEQUENCE seqtest;
とすれば、seqtest という名前のシーケンスが作成されます。
行番号などとして使える数を生成するには、nextval 関数を使い、引数にはシーケンス名を文字列として渡します。
SELECT nextval('seqtest');
とすれば、シーケンスがカウントアップされ、新しい番号が返されます。
テーブルの行番号として使うには、INSERT 文の値として nextval 関数を使います。例えば、
CREATE TABLE test(id INTEGER, val VARCHAR(50));
として作ったテーブルにデータを追加するときに、
INSERT INTO test VALUES (nextval('seqtest'), 'abcde');
のようにして使います。
nextval 関数は、INSERT 文と SELECT 文を組み合わせて複数行を追加するときにも同じように使えます。
CREATE TABLE test2 (x VARCHAR(10));
INSERT INTO test2 VALUES ('a'), ('b'), ('c'), ('d'), ('e');
として5行のデータを test2 に作成した後、
INSERT INTO test SELECT nextval('seqtest'), x FROM test2;
とすると、test には5行のデータが追加され、id 列には順次、カウントアップされた値が入ります。
PostgreSQL には、SERIAL 型、BIGSERIAL 型という特殊なデータ型があり、これを列の型として使うと、nextval 関数を使わなくても、行番号を連番にできます。例えば、
CREATE TABLE test3 (id SERIAL, val VARCHAR(50));
としてデーブルを作ります。
INSERT で、id 列に値を指定しない、あるいは値を DEFAULT とすると、カウントアップされた値が id 列に入ります。つまり、
INSERT INTO test3 (val) VALUES ('abc');
INSERT INTO test3 (id, val) VALUES (DEFAULT, 'xyz');
のようにします。ただし、INSERT と SELECT を組み合わせるときは DEFAULT キーワードが使えないので、
INSERT INTO test3 (val) SELECT x FROM test2;
のようにします。
シーケンスでも SERIAL 型でも、それらが自動生成する番号は一意ですが、それらの機能を使わずに INSERT したり、あるいはデータを UPDATE したりすれば、行番号が重複してしまうことがあります。例えば、上の例で定義したテーブルに対して
INSERT INTO test3 VALUES (3, 'z');
UPDATE test SET id = 2 WHERE id = 4;
といった処理は、シーケンスとは関係なく実行されてしまいます。
nextval 関数で作成されたデータは必ず連番になりますが、テーブルに格納されるデータが連番になるとは限らないことにも注意しましょう。
例えば、DELETE で行を削除すれば、当然、その削除された行番号が欠番になります。また、シーケンスは特定のテーブルに関連づけられているわけではありませんから、他のテーブルでの INSERT や、あるいは INSERT と無関係な場所でnextval を呼び出した場合もそのときに生成された番号が使われなくなります。
トランザクション機能を使っていて、ROLLBACK により INSERT をキャンセルした場合も、シーケンスの加算はキャンセルされないため、やはり欠番が発生します。INSERT 対象のテーブルに何らかの制約があり、INSERT がエラーになった場合も、nextval 関数は実行されてシーケンスがカウントアップされるため、そこで生成された番号が欠番となります。
シーケンスの現在値は currval 関数で確認できます。
SELECT currval('seqtest');
とすることで、最後に使われた値が表示されます。
setval 関数を使って現在値を変更することもできます。
シーケンスは、Oracle や DB2 などの RDBMS でも利用できます。
CREATE SEQUENCE によって作成するところはほぼ同じですが、値の参照方法は RDBMS の種類によってまったく異なりますので注意してください。
MySQL にはシーケンスがありませんが、代わりに、INTEGER 型の列の属性として AUTO_INCREMENT を指定することで、PostgreSQL の SERIAL 型とほぼ同じように使うことができます。
解説:松田神一
© EDUCO All Rights Reserved.