5.5. 繼承

讓我們創建兩個表。首府表包含每個州的首府,它們也是 城市。通常,首府表應該從城市表中繼承過來。

CREATE TABLE cities (
    name            text,
    population      float,
    altitude        int     -- (單位:英尺)
);

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

在這種情況下,一行首府從它的父表,城市表中繼承所有屬性(名字, 人口以及海拔)。name 的類型是 text,它是 PostgreSQL 的本生類型,用于變長 ASCII 字串。population 的類型是floatPostgreSQL 用于雙精度浮點數的本生類型。 州首府有一個額外的屬性,state,顯示它們所在的州。在 PostgreSQL 裡, 一個表可以從零個或多個其它表中繼承屬性,而且一個查詢既可以 引用一個表中的所有行,也可以引用一個表的所有行加上所有其 後代表的行。

注意: 繼承層次實際上是有向開環圖。

比如,下面的查詢查找所有海拔 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 的表.許多我們已經討論過的命令 -- SELECTUPDATEDELETE -- 支持這個 "ONLY" 符號.

有時候你可能想知道某條行版本來自哪個表.在每個表裡我們都有一個系統屬性叫 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

廢棄: 以前版本的 PostgreSQL 裡,缺省是不訪問 子表.我們發現這樣是容易出錯的而且違背 SQL99 標準.在舊語法裡面,要訪問 子表,你需要附加一個 * 到表名後面.例如

SELECT * from cities*;

你仍然可以通過附加*明確聲明需要掃描子表, 也可以通過寫 "ONLY" 聲明明確聲明不掃描子表. 不過,從版本 7.1 開始,對那些不帶修飾的表名子的缺省行為是 同時掃描它的子表,而以前的缺省是正相反.要獲得老的缺省行為, 把配置選項 SQL_Inheritance 關閉,也就是︰

SET SQL_Inheritance TO OFF;

或者向你的 postgresql.conf 文件裡面加一行.

繼承特性的一個局限性是索引(包括唯一約束)和外鍵約束只施用于 單個表,而不包括它們的繼承的子表.因此,在上面的例子裡, 聲明另外一個表的字段 REFERENCES cities(name) 將允許其它表包含城市名但不含首府名.這個缺陷可能在未來的 某個版本中得到修補.