设为首页 收藏本站
查看: 1110|回复: 0

[经验分享] PostgreSQL中继承

[复制链接]
发表于 2016-11-19 08:41:00 | 显示全部楼层 |阅读模式
继承
PostgreSQL 实现了表继承,这个特性对数据库设计人员来说是一个很有效的工具。SQL99 及以后的标准定义了类型继承特性,和我们在这里描述的很多特性有区别。

让我们从一个例子开始:假设我们试图制作一个城市数据模型。每个州都有许多城市,但是只有一个首府。我们希望能够迅速检索任何州的首府。这个任务可以通过创建两个表来实现,一个是州府表,一个是非州府表。不过,如果我们不管什么城市都想查该怎么办?继承的特性可以帮助我们解决这个问题。我们定义 capitals 表,它继承自 cities 表:

CREATE TABLE cities (
    name            text,
    population      float,
    altitude        int     -- 英尺
);

CREATE TABLE capitals (
    state           char(2)
) INHERITS (cities);在这种情况下,capitals 表继承它的父表 cities 中的所有属性。州首府有一个额外的 state 属性显示其所在的州。

在 PostgreSQL 里,一个表可以从零个或多个其它表中继承属性,而且一个查询既可以引用一个表中的所有行,也可以引用一个表及其所有后代表的行(后面这个是缺省行为)。比如,下面的查询查找所有海拔 500 英尺以上的城市名,包括州首府:

SELECT name, altitude
    FROM cities
    WHERE altitude > 500;使用 PostgreSQL 教程里面的数据,它返回:

   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  |     1953cities 前面的 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通过和 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对于 INSERT 或 COPY ,继承并不自动影响其后代表。在我们的例子里,下面的 INSERT 语句将会失败:

INSERT INTO cities (name, population, altitude, state)
VALUES ('New York', NULL, NULL, 'NY');我们可能希望数据被传递到 capitals 表里面去,但这是不会发生的:INSERT 总是插入明确声明的那个表。在某些情况下,我们可以使用规则进行重定向插入(参阅章35)。不过它不能对上面的例子有什么帮助,因为 cities 表并不包含 state 字段,因此命令在规则施加之前就会被拒绝掉。

所有父表的检查约束和非空约束都会自动被所有子表继承。不过其它类型的约束(唯一、主键、外键)不会被继承。

一个子表可以从多个父表继承,这种情况下它将拥有所有父表字段的总和,并且子表中定义的字段也会加入其中。如果同一个字段名出现在多个父表中,或者同时出现在父表和子表的定义里,那么这些字段就会被"融合",这样在子表里就只有一个这样的字段。要想融合,字段的数据类型必须相同,否则就会抛出一个错误。融合的字段将会拥有其父字段的所有检查约束,并且如果某个父字段存在非空约束,那么融合后的字段也必须是非空的。

表继承通常使用带 INHERITS 子句的 CREATE TABLE 语句定义。另外,一个已经用此方法定义的子表可以使用带 INHERIT 的 ALTER TABLE 命令添加一个新父表。注意:该子表必须已经包含新父表的所有字段且类型一致,此外新父表的每个约束的名字及其表达式都必须包含在此子表中。同样,一个继承链可以使用带 NO INHERIT 的 ALTER TABLE 命令从子表上删除。允许动态添加和删除继承链对基于继承关系的表分区很有用。

创建一个将要作为子表的新表的便利途径是使用带 LIKE 子句的 CREATE TABLE 命令。它将创建一个与源表字段相同的新表。如果源表中存在约束,那么应该指定 LIKE 的 INCLUDING CONSTRAINTS 选项,因为子表必须包含源表中的 CHECK 约束。

任何存在子表的父表都不能被删除,同样,子表中任何从父表继承的字段也不能被删除或修改。如果你想删除一个表及其所有后代,最简单的办法是使用 CASCADE 选项。

ALTER TABLE 会把所有数据定义和检查约束传播到后代里面去。另外,只有在使用 CASCADE 选项的情况下,才能删除父表的字段或者约束。ALTER TABLE 在重复字段融合和拒绝方面和 CREATE TABLE 的规则相同。

5.8.1. 警告
表访问权限并不会自动继承。因此,要么同时具有访问父表与所有子表的权限,要么必须使用 ONLY 表示法。所以在添加新子表的时候,请注意给它赋予适当的权限。

继承的一个严重局限性是索引(包括唯一约束)和外键约束只能用于单个表,而不能包括它们的子表(不管对引用表还是被引用表都是如此),因此,在上面的例子里:

即使我们声明 cities.name 为 UNIQUE 或 PRIMARY KEY 也不会阻止 capitals 表拥有重复名字的 cities 数据行。并且这些重复的行在查询 cities 表的时候会显示出来。实际上,缺省时 capitals 将完全没有唯一约束,因此可能包含带有同名的多个行。你应该给 capitals 增加唯一约束,但即使这样做也不能避免与 cities 的重复。

类似的,即使我们声明 cities.name 参照(REFERENCES)某些其它的表,这个约束也不会自动传播到 capitals 表。在这种条件下,你可以通过手工给 capitals 表增加同样的 REFERENCES 约束来做到这点。

声明一个其它表的字段为 REFERENCES cities(name) 将允许其它表包含城市名,但是不包含首府名。这种情况下没有很好的绕开办法。

这些缺点很可能在将来的版本中修补,但同时你也需要考虑一下,继承是否对你的问题真正有用。

【已废弃】在7.1以前的 PostgreSQL 版本里,缺省的行为是不在查询里包含子表。后来发现这么做很容易出错并且也违反了 SQL 标柱。你可以通过关闭 sql_inheritance 配置选项来兼容以前的行为。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-302376-1-1.html 上篇帖子: Dumping and Restoring PostgreSQL Database 下篇帖子: postgresql 修改表
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表