继承 ======= OushuDB 实现了表继承,这个特性对数据库设计人员来说是一个很有效的工具。 让我们从一个例子开始:假设我们试图制作一个城市数据模型。每个州都有许多城市,但是只有一个首府。我们希望能够迅速检索任何州的首府。这个任务可以通过创建两个表来实现,一个是首府表,一个是非首府表。不过,如果我们不管什么城市都想查该怎么办? 继承的特性可以帮助我们解决这个问题。我们定义capitals表,它继承自cities表: :: CREATE TABLE cities ( name text, population float, altitude int -- in feet ); CREATE TABLE capitals ( state char(2) ) INHERITS (cities); 在这种情况下,capitals表继承它的父表cities 中的所有属性。州首府有一个额外的state属性显示其所在的州。 在 OushuDB 里,一个表可以从零个或多个其它表中继承属性,而且一个查询既可以引用一个表中的所有行,也可以引用一个表及其所有后代表的行(后面这个是缺省行为)。比如,下面的查询查找所有海拔 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 而不包括其后代。许多我们已经讨论过的命令(SELECT, UPDATE 和 DELETE)都支持ONLY关键字。 有时候你可能想知道某个行来自哪个表。在每个表里我们都有一个tableoid 系统属性可以告诉你源表是谁: :: SELECT c.tableoid, c.name, c.altitude FROM cities c WHERE c.altitude > 500; 结果如下(你可能会得到不同的 OID): :: tableoid | name | altitude ----------+-----------+---------- 139793 | Las Vegas | 2174 139793 | Mariposa | 1953 139798 | Madison | 845 对于INSERT或COPY,继承并不自动影响其后代表。在我们的例子里,下面的INSERT语句将会失败: :: INSERT INTO cities (name, population, altitude, state) VALUES ('New York', NULL, NULL, 'NY'); 我们可能希望数据被传递到capitals表里面去,但这是不会发生的:INSERT总是插入明确声明的那个表。在某些情况下,我们可以使用规则进行重定向插入。不过它对上面的例子没有什么帮助,因为cities表并不包含state列,因此命令在规则施加之前就会被拒绝掉。 .. note:: MAGMA表和HORC表都支持INHERITS操作和ONLY关键字。 所有父表的检查约束和非空约束都会自动被所有子表继承。不过其它类型的约束不会被继承。 一个子表可以从多个父表继承,这种情况下它将拥有所有父表列的总和,并且子表中定义的列也会加入其中。如果同一个列名出现在多个父表中,或者同时出现在父表和子表的定义里,那么这些列就会被"合并",这样在子表里就只有一个这样的列。要想合并,列的数据类型必须相同,否则就会抛出一个错误。并合的列将会拥有其父列的所有检查约束,并且如果某个父列存在非空约束,那么合并后的列也必须是非空的。 表继承通常使用带INHERITS子句的CREATE TABLE语句定义。另外,一个已经用此方法定义的子表可以使用带INHERIT的ALTER TABLE 命令添加一个新父表。注意:该子表必须已经包含新父表的所有列且类型一致,此外新父表的每个约束的名字及其表达式都必须包含在此子表中。同样,一个继承链可以使用带NO INHERIT的ALTER TABLE命令从子表上删除。允许动态添加和删除继承链对基于继承关系的表分区(参见 `分区表 <./data-definition-partition-tables.html>`_ )很有用。 创建一个将要作为子表的新表的便利途径是使用带LIKE子句的 CREATE TABLE命令。它将创建一个与源表列相同的新表。如果源表中存在约束,那么应该指定LIKE的INCLUDING CONSTRAINTS 选项,因为子表必须包含源表中的CHECK约束。 任何存在子表的父表都不能被删除,同样,子表中任何从父表继承的列或约束也不能被删除或修改。如果你想删除一个表及其所有后代,最简单的办法是使用CASCADE选项删除父表。 ALTER TABLE会把所有数据定义和检查约束传播到后代里面去。另外,只有在使用CASCADE选项的情况下,才能删除依赖于其他表的列。ALTER TABLE在重复字段合并和拒绝方面与CREATE TABLE的规则相同。 .. note:: HMAGMA表和HORC表都支持继承。 警告 -------- 表的访问权限不会被自动继承。因此,一个用户访问父表时必须有其所有子表的访问权限或必须使用ONLY记号。当对一个现存的继承关系中加入一个新子表时,请仔细地赋予它所需的所有权限。