5.5. 继承 #
让我们创建两个表。capitals 表包含也是城市的州首府。自然,capitals 表应当继承自 cities。
CREATE TABLE cities (
name text,
population float,
altitude int -- (in ft)
);
CREATE TABLE capitals (
state char(2)
) INHERITS (cities);
在这种情况下,capitals 的一行从其父表 cities 继承所有属性(name、population 和 altitude)。属性 name 的类型是 text,这是 PostgreSQL 的原生类型,用于变长字符串。属性 population 的类型是
float,这是 PostgreSQL 的原生类型,用于双精度浮点数。州首府有一个额外的属性 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”记法。
在某些情况下,你可能想知道某个特定行来自哪个表。每个表中有一个叫
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 设为 off,例如,
SET SQL_Inheritance TO OFF;
or add a line in your postgresql.conf file.
继承特性的一个限制是索引(包括唯一约束)和外键约束只适用于单个表,不适用于其继承子表。因此在上面的例子中,指定另一个表的列 REFERENCES cities(name)
将允许另一个表包含城市名但不能包含首府名。这个缺陷可能在将来的某个版本中修复。