継承

PostgreSQL 8.0.0 文書
前のページ | 巻戻し | 第 5章データ定義 | 早送り | 次のページ

# 5.5. 継承

2つのテーブルを作ってみましょう。 capitalsテーブルで保持される州都は、市（cities）でもあります。 capitalsテーブルはcitiesテーブルから継承されるべきだというのが自然な流れでしょう。

    CREATE TABLE cities (
        name            text,
        population      float,
        altitude        int     -- (in ft)
    );

    CREATE TABLE capitals (
        state           char(2)
    ) INHERITS (cities);

この場合、capitalsの行は全ての属性(name（名前）、population（人口）、altitude（高度）)を親テーブルのcitiesから継承します。州都は外部の属性(state（州）)を持っていて、これは州を意味します。 PostgreSQLでは、テーブルは0個以上のテーブルから継承することができ、問い合わせは1つのテーブルの全ての行を参照することも、テーブルとその子孫全ての行を参照することも可能です。

> 注意: 継承の階層は非循環有向グラフです。

例えば、次の問い合わせは、州都を含む、高度が500フィート以上にある全ての市を見つけます。

    SELECT name, altitude
        FROM cities
        WHERE altitude > 500;

出力は以下の通りです。

       name    | altitude
    -----------+----------
     Las Vegas |     2174
     Mariposa  |     1953
     Madison   |      845

一方、次の問い合わせは、高度が500フィート以上にあり州都ではない全ての市を見つけます。

    SELECT name, altitude
        FROM ONLY cities
        WHERE altitude > 500;

       name    | altitude
    -----------+----------
     Las Vegas |     2174
     Mariposa  |     1953

ここで、citiesの前の"ONLY"は、この問い合わせはcitiesのみを対象とし、citiesを継承したテーブルは対象外としなければならないことを表します。 これまでに説明した多くのコマンド、`SELECT`、`UPDATE` や `DELETE` は、この"ONLY"という構文をサポートしています。

> 改善のために仕様変更された部分: PostgreSQLの以前のバージョンでは、デフォルトでは子テーブルにアクセスすることができませんでした。 これは間違いのもとであり、また標準SQL1999にも違反しています。 古い構文では、サブテーブルを得るためには`*`をテーブル名に付加していました。 例えば下記のようになります。

>     SELECT * from cities*;

> 現在でも`*`を付加することで子テーブルのスキャンを明確に指定したり、"ONLY"を書くことで子テーブルをスキャンしないことを明確にすることができます。 しかしバージョン7.1からは、何も指定されていないテーブル名のデフォルト動作では子テーブルもスキャンします。 逆に、以前のデフォルトはそうしないことでした。 以前のデフォルト動作で作業をしたい場合は`SQL_Inheritance`設定オプションを無効にしてください。 以下に例を示します。

>     SET SQL_Inheritance TO OFF;

> または、`postgresql.conf`ファイルに1行追加してください。

場合によっては、ある特定の行がどのテーブルからきたものか知りたいということがあるかもしれません。 それぞれのテーブルには`tableoid`という、元になったテーブルを示すシステム列があります。

    SELECT c.tableoid, c.name, c.altitude
    FROM cities c
    WHERE c.altitude > 500;

出力は以下の通りです。

     tableoid |   name    | altitude
    ----------+-----------+----------
       139793 | Las Vegas |     2174
       139793 | Mariposa  |     1953
       139798 | Madison   |      845

(この例を再生しても、おそらく異なる数値OIDが与えられるでしょう。) `pg_class`と結合することで、テーブルの実際の名前が判ります。

    SELECT p.relname, c.name, c.altitude
    FROM cities c, pg_class p
    WHERE c.altitude > 500 and c.tableoid = p.oid;

出力は以下の通りです。

     relname  |   name    | altitude
    ----------+-----------+----------
     cities   | Las Vegas |     2174
     cities   | Mariposa  |     1953
     capitals | Madison   |      845

テーブルは1つ以上の親テーブルから継承されることができます。その場合には、テーブルは親テーブルで定義されている列の和（さらに子テーブルで特別に宣言されているどのような列も）を持ちます。

継承機能の厳しい制限として、(一意性制約を含む)インデックス、および、外部キーは、そのテーブルのみに適用され、それを継承した子テーブルには適用されないことがあります。これは外部キーの参照側、被参照側でも同様に適用されません。 従って、上の例では

- もし、`cities`.`name`を`UNIQUE`または`PRIMARY KEY`と宣言しても、 `cities`テーブルの行を複製した行を、`capitals`テーブル内に持つことを禁止することにはなりません。 更に、これらの複製された行はデフォルトで`cities`テーブルへの問い合わせで現れるでしょう。 事実として、`capitals`テーブルはデフォルトで一意性制約を持っていませんし、同一の名前の複数の行を持つことが有り得ます。 `capitals`テーブルに一意性制約を追加できますが、これは`cities`テーブルと比較して複製を禁止することにはなりません。

- 同じように、もし`cities`.`name` `REFERENCES`他のテーブルとしても、 この制約は自動的に`capitals`に引き継がれるわけではありません。この場合は`capitals`テーブルに 同一の`REFERENCES`制約を手動で追加しなければいけません。

- 他のテーブルの列`REFERENCES cities(name)`を指定することは、他のテーブルが市の名前を持つことを 許可しますが、州都の名前を持つことを許可しません。この場合は次善策はありません。

これらの機能の不足は、今後のリリースで恐らく改善されるでしょう。しかし 継承が有用であるかどうかは、十分注意して決定してください。

前のページ | ホーム | 次のページ
システム列 | 上に戻る | テーブルの変更