Chapter 8. 継承

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

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

CREATE TABLE capitals (
    state           char(2)
) INHERITS (cities);
この場合、capitals の行は全ての属性(name(名前)、population(人口)、 altitude(高度))を親テーブルの cities から継承 します。名前の型は Postgres固有の可変長 ASCII 文字列である text型です。population の型は float で、 倍精度浮動小数点数のためのPostgres固有の 型です。州都には更に、state という州を示す属性が追加されます。 Postgresでは、テーブルはゼロ以上のテーブルから 継承することができ、 問い合わせはテーブルの全ての行、もしくはテーブルと その子孫全ての行を参照することができます。

Note: 継承の階級組織は非循環有向グラフです。

例えば、次の問い合わせは、州都を含む高度が 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     |
+----------+----------+
   

ここでは市の前の"ONLY"は、継承の階層の中の市の下にある テーブルではなく、cities のみで問い合わせが実行されるべきだということを 表しています。これまでに説明してきた沢山のコマンド(SELECT, UPDATE and DELETE)はこの "ONLY"構文をサポートしています。

場合によっては、ある特定のタプルがどのテーブルからきたものか知りたい ということがあるかもしれません。それぞれのテーブルには "TABLEOID"というシステムカラムがあり、オリジナルのテーブル を教えてくれます。

    SELECT c.tableoid, c.name, c.altitude
    FROM cities c
    WHERE c.altitude > 500;
   
これは以下を返します。
+---------+----------+----------+
|tableoid |name      | altitude |
+---------+----------+----------+
|37292    |Las Vegas | 2174     |
+---------+----------+----------+
|37280    |Mariposa  | 1953     |
+---------+----------+----------+
|37280    |Madison   | 845      |
+---------+----------+----------+
   
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 |
+---------+----------+----------+
|capitals |Las Vegas | 2174     |
+---------+----------+----------+
|cities   |Mariposa  | 1953     |
+---------+----------+----------+
|cities   |Madison   | 845      |
+---------+----------+----------+
   

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

SELECT * from cities*;
現在でも "*" を付加することで子テーブルのスキャンを明確に指定したり、 "ONLY"を書くことで子テーブルをスキャンしないことを明確に することができます。しかしバージョン 7.1 からは、なにも指定されていない テーブル名のデフォルト動作では子テーブルもスキャンします。逆に、以前 のデフォルトはそうしないことでした。以前のデフォルト動作で作業 をしたい場合は設定変更のオプション SQL_Inheritance to off をつけて下さい。下記が例 です。
SET SQL_Inheritance TO OFF;
もしくは postgresql.conf ファイルにこの行を 追加してください。