| PostgreSQL 8.0.0 中文文件(轉譯自 PostgreSQL 中國 製作的簡體中文版本) | ||||
|---|---|---|---|---|
| Prev | Fast Backward | Chapter 5. 資料定義 | Fast Forward | Next |
讓我們建立兩個資料表。首府資料表包含每個州的首府,它們也是城市。通常,首府資料表應該從城市資料表中繼承過來。
CREATE TABLE cities (
name text,
population float,
altitude int -- (單位:英尺)
);
CREATE TABLE capitals (
state char(2)
) INHERITS (cities);在這種情況下,一行首府從它的父資料表,城市資料表中繼承所有屬性(名字,人口以及海拔)。 州首府有一個額外的屬性,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 的資料表。 許多我們已經討論過的命令 -- SELECT, UPDATE 和 DELETE -- 支援這個 "ONLY" 符號。
廢棄: 以前版本的 PostgreSQL 裡,預設是不訪問子資料表。 我們發現這樣是容易出錯的而且違背 SQL:1999 標準。在舊語法裡面,要訪問子資料表,您需要附加一個 * 到資料表名後面。例如
SELECT * from cities*;您仍然可以透過附加*明確聲明需要掃瞄子資料表, 也可以透過寫 "ONLY" 聲明明確聲明不掃瞄子資料表。 不過,從版本 7.1 開始,對那些不帶修飾的資料表名子的預設行為是同時掃瞄它的子資料表, 而以前的預設是正相反。要獲得老的預設行為, 把配置選項 SQL_Inheritance 關閉,也就是︰
SET SQL_Inheritance TO OFF;或者向您的 postgresql.conf 文件裡面加一行。
有時候您可能想知道某條行版本來自哪個資料表。在每個資料表裡我們都有一個系統屬性叫 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
一個資料表可以從多於一個父資料表中繼承,在這種情況下,它擁有它的父資料表們定義的字串的和 (加上任何為這個子資料表單獨定義的字串)。
繼承特性的一個嚴重的局限性是索引(包括唯一約束)和外鍵約束只施用於單個資料表, 而不包括它們的繼承的子資料表。這一點不管對引用資料表還是被引用資料表都是事實,因此,在上面的例子裡:
如果我們聲明 cities.name 為 UNIQUE 或者是一個 PRIMARY KEY, 那麼也不會阻止 capitals 資料表擁有重複了名字的 cities 資料行。 並且這些重複的行預設時在查詢 cities 資料表的時候會顯示出來。 實際上,預設時 capitals 將完全沒有唯一約束,因此可能包含帶有同名的多個行。 您應該給 capitals 增加唯一約束,但是這樣做也不會避免與 cities 的重複。
類似,如果我們聲明 cities.name REFERENCES 某些其它的資料表, 這個約束不會自動廣播到 capitals。在這種條件下,您可以透過手工給 capitals 增加同樣的 REFERENCES 約束來做到這點。
聲明其它一個資料表的字串為 REFERENCES cities(name) 將允許其它資料表包含城市名, 但是不包含首府名。這種情況下沒有很好的繞開辦法。
這些缺點很可能在將來的版本中修補,但同時您也需要考慮一下,繼承是否對您的問題真正有用。