1020.表-继承

对一个表的查询可以(默认也是)引用一个表的所有行或者该表的所有行加上它所有的后代表,使用ONLY可以只查询指定的表

每个表中的系统列tableoid可以告诉我们行来自于哪个表(pg_class可以进一步关联)

父表上的所有检查约束和非空约束都将自动被它的后代所继承(指定NO INHERIT子句除外;其他约束不继承)

子表存在时,父表不能被删除。子表的列或者检查约束继承于父表时,它们也不能被删除或修改。(可以使用CASCADE)

PG中有继承表,城市清单表(名称、人口、海拔)可以被特殊的省会城市表(名称、人口、海拔、所属省)继承。

CREATE TABLE cities (

    name            text,

    population      float,

    altitude        int     -− in feet

);

CREATE TABLE capitals (

    state          char(2)

) INHERITS (cities);

在这种情况下,capitals表继承了它的父表cities的所有列。省会城市还有一个额外的列state用来表示它所属的省。

在PostgreSQL中,一个表可以从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;

写*不是必需的,因为这种行为总是默认的。不过,为了兼容可以修改默认值的较老版本,现在仍然支持这种语法。

在某些情况下,我们可能希望知道一个特定行来自于哪个表。

每个表中的系统列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

另一种得到同样效果的方法是使用regclass别名类型, 它将象征性地打印出表的 OID:

SELECT c.tableoid::regclass, c.name, c.altitude

FROM cities c

WHERE c.altitude > 500;

继承不会自动地将来自INSERT或COPY命令的数据传播到继承层次中的其他表中。在我们的例子中,下面的INSERT语句将会失败:

INSERT INTO cities (name, population, altitude, state)

VALUES ('Albany', NULL, NULL, 'NY');

我们也许希望数据能被以某种方式被引入到capitals表中,但是这不会发生:INSERT总是向指定的表中插入。

在某些情况下,可以通过使用一个规则(见第 40 章)来将插入动作重定向。但是这对上面的情况并没有帮助,因为cities表根本就不包含state列,因而这个命令将在触发规则之前就被拒绝。

父表上的所有检查约束和非空约束都将自动被它的后代所继承,除非显式地指定了NO INHERIT子句。其他类型的约束(唯一、主键和外键约束)则不会被继承。

一个表可以从超过一个的父表继承,在这种情况下它拥有父表们所定义的列的并集。任何定义在子表上的列也会被加入到其中。

如果在这个集合中出现重名列,那么这些列将被“合并”,这样在子表中只会有一个这样的列。重名列能被合并的前提是这些列必须具有相同的数据类型,否则会导致错误。可继承的检查约束和非空约束会以类似的方式被合并。

例如,如果合并成一个合并列的任一列定义被标记为非空,则该合并列会被标记为非空。如果检查约束的名称相同,则他们会被合并,但如果它们的条件不同则合并会失败。

表继承通常是在子表被创建时建立,使用CREATE TABLE语句的INHERITS子句。一个已经被创建的表也可以另外一种方式增加一个新的父亲关系,使用ALTER TABLE的INHERIT变体。

要这样做,新的子表必须已经包括和父表相同名称和数据类型的列。子表还必须包括和父表相同的检查约束和检查表达式。

相似地,一个继承链接也可以使用ALTER TABLE的 NO INHERIT变体从一个子表中移除。动态增加和移除继承链接可以用于实现表划分。

一种创建一个未来将被用做子女的新表的方法是在CREATE TABLE中使用LIKE子句。这将创建一个和源表具有相同列的新表。如果源表上定义有任何CHECK约束,LIKE的INCLUDING CONSTRAINTS选项可以用来让新的子表也包含和父表相同的约束。

当有任何一个子表存在时,父表不能被删除。当子表的列或者检查约束继承于父表时,它们也不能被删除或修改。如果希望移除一个表和它的所有后代,一种简单的方法是使用CASCADE选项删除父表

ALTER TABLE将会把列的数据定义或检查约束上的任何变化沿着继承层次向下传播。同样,删除被其他表依赖的列只能使用CASCADE选项。ALTER TABLE对于重名列的合并和拒绝遵循与CREATE TABLE同样的规则。

原文地址:https://www.cnblogs.com/bufuzhou/p/14238745.html