ファイヤープロジェクト
継承
2004-10-30T17:00+09:00   matsu
PostgreSQLではテーブル間で継承関係を作成できるらしいので試してみた.
似ているが若干構造が異なるテーブルがいくつかあったり,実際にモデル化すると親子関係にあるテーブルがある場合がある.このような場合に,あるテーブルの定義を継承しつつ,いくつかの付加属性を加えるといったテーブル定義ができると便利である.そこで,継承を使用したテーブル定義を試してみた.まず,親となるテーブルを作成する.
firstdb=> CREATE TABLE parent (
firstdb(>   id integer primary key,
firstdb(>   name text not null
firstdb(> );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 'parent_pkey' for table 'parent'
CREATE
このテーブルparentの定義を継承したテーブルchildを作成する.
firstdb=> CREATE TABLE child (
firstdb(>   optional integer
firstdb(> ) inherits (parent);
CREATE
このように,テーブル間の継承関係を指定するには,子テーブル定義時にinheritsで使用する.
CREATE TABLE 子テーブル(
...
) inherits (親テーブル);
これらのテーブルにデータを投入してみる.
firstdb=> INSERT INTO parent VALUES (1, 'hoge');
INSERT 1008327 1
firstdb=> INSERT INTO parent VALUES (2, 'fuga');
INSERT 1008328 1
firstdb=> INSERT INTO child VALUES (1, 'foo', 10);
INSERT 1008332 1
firstdb=> INSERT INTO child VALUES (2, 'var');
INSERT 1008333 1
このように子テーブルは親の属性id,nameを継承していることがわかる.親から継承するのは属性だけでなく,制約も継承する.たとえば以下は親の属性nameのNOT NULL制約に違反しているのでエラーになる.
firstdb=> INSERT INTO child VALUES (3);
ERROR:  ExecAppend: Fail to add null value in not null attribute name
また,当然ながら親テーブルには属性optionはないので以下はエラーになる.
firstdb=> INSERT INTO parent VALUES (1, 'hoge' 10);
ERROR:  parser: parse error at or near "10"
継承を使用してテーブルを作成すると,テーブル定義が若干楽になるだけではなく,選択の際にも効果がある.すなわち親テーブルに対する検索の範囲は子テーブルにも及ぶ.以下では親テーブルに対してSELECTしたのに,子テーブルのレコードまで出力される例である.
firstdb=> SELECT * FROM parent;
  1 | hoge
  2 | fuga
  1 | foo
  2 | var
親テーブルのみを検索範囲としたい場合は
FROM ONLY テーブル名
というように,FROMの後にONLYをつける.
firstdb=> SELECT * FROM ONLY parent;
  1 | hoge
  2 | fuga
当然ながら,子テーブルを検索範囲とした場合は親テーブルは検索範囲外である.
firstdb=> SELECT * FROM child;
  1 | foo  |       10
  2 | var  |         
想像どおり,選択による検索範囲が上記のようなので,更新の場合にもそのようになる.すなわち親テーブルに対するUPDATE文なのに,子テーブルまで更新される.
firstdb=> UPDATE parent SET id=id+10;
UPDATE 4
firstdb=> SELECT * FROM parent;
 11 | hoge
 12 | fuga
 11 | foo
 12 | var
親テーブルのみを対象にしたい場合はやはりONLYをつける.
firstdb=> UPDATE ONLY parent SET id=id-10;
UPDATE 2
firstdb=> SELECT * FROM parent;
  1 | hoge
  2 | fuga
 11 | foo
 12 | var
DELETEについても同様である.
firstdb=> DELETE FROM parent WHERE id%2=0;
DELETE 2
firstdb=> SELECT * from parent;
  1 | hoge
 11 | foo
firstdb=> DELETE FROM ONLY parent WHERE id%2=1;
DELETE 1
firstdb=> SELECT * from parent;
 11 | foo
他のテーブルに継承されているテーブルをいきなり削除することはできない.
firstdb=> DROP TABLE parent;
ERROR:  Relation "child" inherits from "parent"
このような場合は継承している側から順に削除する.
firstdb=> DROP TABLE child;
DROP
firstdb=> DROP TABLE parent;
DROP
matsu(C)
Since 2002
Mail to matsu