読者です 読者をやめる 読者になる 読者になる

PostgreSQL で継承したテーブルのキーを参照する

PostgreSQL 9.3.1 で確認。
まず実験に使うテーブルを作る。tbl_vips が tbl_users を継承している。

CREATE TABLE tbl_users (
  id serial PRIMARY KEY
, name varchar(64)
);

CREATE TABLE tbl_vips (
  asset integer
) INHERITS (tbl_users);

使ってみる。

INSERT INTO tbl_users (name) VALUES ('Terry');
INSERT INTO tbl_users (name) VALUES ('Bobby');
INSERT INTO tbl_vips (name, asset) VALUES ('Dolly', 20000);
INSERT INTO tbl_vips (name, asset) VALUES ('Betty', 32000);
SELECT * FROM tbl_users;
...
SELECT * FROM tbl_vips;
...

ここで、次のような bl_vips を参照するテーブルを作ろうとするとエラーになる。

CREATE TABLE tbl_vip_options (
  id serial PRIMARY KEY
, vip_id integer REFERENCES tbl_vips (id) ON DELETE CASCADE
, kani integer DEFAULT 0
, uni integer DEFAULT 0
);
ERROR:  there is no unique constraint matching given keys for referenced table "tbl_vips"

エラーメッセージから tbl_vips の主キー id に UNIQUE 制約を付与してやればよいと推測できる。

ALTER TABLE tbl_vips ADD UNIQUE (id);

新規でテーブルを作る場合は次のようにすればよい。

CREATE TABLE tbl_vips (
  asset integer
, UNIQUE (id)
) INHERITS (tbl_users);

こうしてから再び tbl_vip_options を作ると、今度はうまくいった。

INSERT INTO tbl_vip_options (vip_id, kani, uni) VALUES (3, 1, 1);
INSERT INTO tbl_vip_options (vip_id, kani, uni) VALUES (4, 1, 1);

SELECT u.name, o.kani, o.uni
FROM tbl_vip_options AS o
  LEFT OUTER JOIN tbl_vips AS u ON (u.id = o.vip_id);

問題発覚

ところが REFERENCES tbl_users (id) と、親のテーブルを指定しようとするとうまくいかない。tbl_users へ追加したデータは問題ないが、 tbl_vips のデータだとエラーになる。
調べていると Wikipedia にこんな記述を見つけた。

親テーブルに対する列の追加やCHECK制約の定義は自動的に子テーブルにも反映されるが、外部キーや一意性制約は継承をサポートしていない。

http://ja.wikipedia.org/wiki/PostgreSQL

どうやらこの方法には使えないようだ。別テーブルで管理する方法に切り替えよう。