让我们创建两个表。首府表包含每个州的首府,它们也是城市。通常,首府表应该从城市表中继承过来。
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) 将允许其它表包含城市名, 但是不包含首府名。这种情况下没有很好的绕开办法。
这些缺点很可能在将来的版本中修补,但同时你也需要考虑一下,继承是否对你的问题真正有用。