無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

5.8. 継承

PostgreSQL は、データベース設計者にとって便利なテーブルの継承を実装しています。 (SQL:1999以降は型の継承を定義していますが、ここで述べられている継承とは多くの点で異なっています。)

まず例から始めましょう。 市(cities)のデータモデルを作成しようとしていると仮定してください。 それぞれの州にはたくさんの市がありますが、州都(capitals)は1つのみです。 特定の州から州都を素早く検索したいとします。 これは、2つのテーブルを作成することにより実現できます。 1つは州都のテーブルで、もう1つは州都ではないテーブルです。 しかし、州都であるか否かに関わらない市に対するデータを問い合わせたときには何が起こるでしょうか? 継承はこの問題を解決できます。 cities から継承される capitals テーブルを定義するのです。

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

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

この場合、 capitals テーブルは、その親テーブルである cities テーブルの列をすべて 継承 します。 州都は1つの余分な列 state を持ち、州を表現します。

PostgreSQL では、1つのテーブルは、0以上のテーブルから継承することが可能です。 また、問い合わせはテーブルのすべての行、またはテーブルのすべての行と継承されたテーブルのすべての行のいずれかを参照できます。 後者がデフォルトの動作になります。 例えば次の問い合わせは、500フィートより上に位置している州都を含んだ、すべての市の名前を検索します。

SELECT name, altitude
    FROM cities
    WHERE altitude > 500;

PostgreSQL チュートリアルからのサンプルデータ( 項2.1 を参照してください)に対して、この問い合わせは、以下の結果を出力します。

   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 テーブルのみを対象にし cities 以下の継承の階層にあるテーブルは対象としないことを意味します。 これまで議論したコマンドの多く— SELECT UPDATE そして DELETE —が ONLY キーワードをサポートしています。

また、明示的に子孫テーブルが含まれていることを示すために、テーブル名の後ろに * を書くこともできます:

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

* の指定は、その動作がデフォルトである(あなたが sql_inheritance 構成オプションの設定を変更していない限り)ため必須ではありません。 しかしながら、 * を指定することは、追加のテーブルが検索されることを強調するのに有効でしょう。

場合によっては、ある特定の行がどのテーブルからきたものか知りたいということがあるかもしれません。 それぞれのテーブルには 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

継承は INSERT または COPY により、継承の階層にある他のテーブルにデータを自動的に伝播することはありません。 この例では、次の INSERT 文は失敗します。

INSERT INTO cities (name, population, altitude, state)
VALUES ('New York', NULL, NULL, 'NY');

データが、どうにかして capitals テーブルまで到達できればいいのですが、そのようにはなりません。 INSERT は、いつも指定されたテーブルに対してデータを挿入します。 ルール(詳細は 第38章 を参照してください)を使用して挿入を中継できる場合もあります。 しかし、ルールを使用しても上記のような場合には適用できません。 なぜなら、 cities テーブルには state 列は含んでいませんし、ルールが適用される前にコマンドは拒否されてしまうからです。

親テーブル上の検査制約と非NULL制約はその子テーブルに自動的に継承されます。 他の種類の制約(一意性制約、プライマリキー、外部キー制約)は継承されません。

テーブルは1つ以上の親テーブルから継承可能です。 この場合、テーブルは親テーブルで定義された列の和になります。 子テーブルで宣言された列は、これらの列に追加されることになります。 もし親テーブルに同じ名前の列がある場合、もしくは、親テーブルと子テーブルに同じ名前の列がある場合は、列が "統合" されて子テーブルではただ1つの列となります。 統合されるには列は同じデータ型を持っている必要があります。 異なるデータ型の場合にはエラーとなります。 統合された列は、元となったテーブルで列定義が持つすべての検査制約のコピーを持ちます。 そして、列定義のいずれかが非NULL制約を持てば、非NULLという印が付きます。

テーブル継承は、通常、 CREATE TABLE 文の INHERITS 句を使用して、子テーブルを作成する時に確立します。 他にも、互換性を持つ方法で定義済みのテーブルに新しく親子関係を付けることも可能です。 これには ALTER TABLE INHERIT 形式を使用します。 このためには、新しい子テーブルは親テーブルと同じ名前の列を持ち、その列の型は同じデータ型でなければなりません。 また、親テーブルと同じ名前、同じ式の検査制約を持っていなければなりません。 ALTER TABLE NO INHERIT 形式を使用して、同様に継承関係を子テーブルから取り除くことも可能です。 このような継承関係の動的追加、動的削除は、継承関係をテーブル分割( 項5.9 を参照)に使用している場合に有用です。

後で子テーブルとする予定の、互換性を持つテーブルを簡単に作成する方法の1つは、 CREATE TABLE LIKE 句を使用することです。 これは、元としたテーブルと同じ列を持つテーブルを新しく作成します。 新しい子テーブルが必ず親テーブルと一致する制約を持ち、互換性があるものとみなされるように、元となるテーブルで CHECK 制約が存在する場合は、 LIKE INCLUDING CONSTRAINTS オプションを指定すべきです。

子テーブルが存在する場合親テーブルを削除することはできません。 また、子テーブルでは、親テーブルから継承した列、または検査制約を削除することも変更することもできません。 テーブルとそのすべての子テーブルを削除したければ、 CASCADE オプションを付けて親テーブルを削除することが簡単な方法です。

ALTER TABLE は、列データ定義と検査制約の変更を継承の階層にあるテーブルに伝えます。 繰り返しになりますが、他のテーブルに依存する列の削除は CASCADE オプションを使用したときのみ可能となります。 ALTER TABLE は、重複列の統合時に適用される規則と CREATE TABLE 時に適用される拒否の規則に従います。

テーブルアクセス権限がどのように扱われるかに注意して下さい。 親テーブルへの問い合わせでは、それ以上アクセス権限を検査することなく自動的に子テーブルのデータにアクセスできます。 これによりデータが親テーブルに(も)あるように見えることが保たれます。 しかし、子テーブルへの直接のアクセスは自動的に許可されることはなく、追加の権限の付与が要求されるでしょう。

5.8.1. 警告

すべてのSQLコマンドが継承階層に対して動作できるとは限らないことに注意してください。 データの検索、データの変更、スキーマの変更のために使用されるコマンド(例えば SELECT UPDATE DELETE ALTER TABLE のほとんどの構文です。しかし INSERT ALTER TABLE ... RENAME は除きます。)は通常、デフォルトで子テーブルを含み、また、それを除外するための ONLY 記法をサポートします。 データベース保守およびチューニング(例えば REINDEX VACUUM )を行うコマンドは通常、個々の物理テーブルに対してのみ動作し、継承階層に対する再帰をサポートしません。 個々のコマンドのそれぞれの動作はそのマニュアルページ( 参照I, SQLコマンド )に記載されています。

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

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

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

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

これらの機能の不足は、今後のリリースでおそらく改善されるでしょう。 しかし当面、継承がアプリケーションにとって有用であるかどうかを判断する際に十分注意してください。

推奨しない設定: 7.1より前のリリースの PostgreSQL では、問い合わせにおいて子テーブルを含まないことがデフォルトでした。 これはエラーとなりやすく、また標準SQLにも抵触しています。 7.1より前の古い動作を行うようにするには、 sql_inheritance 設定オプションを無効にしてください。


powered by SEO.CUG.NET