PostgreSQL学习手册(三) 表的继承和分区
一、表的继承:
这个概念对于很多已经熟悉其他数据库编程的开发人员而言会多少有些陌生,然而它的实现方式和设计原理却是简单易懂,现在就让我们从一个简单的例子开始吧。
1. 第一个继承表:
CREATE TABLE cities ( --父表
name text,
population float,
altitude int
);
CREATE TABLE capitals ( --子表
state char(2)
) INHERITS (cities);
capitals表继承自cities表的所有属性。在PostgreSQL里,一个表可以从零个或多个其它表中继承属性,而且一个查询既可以引用父表中的所有行,也可以引用父表的所有行加上其所有子表的行,其中后者是缺省行为。
MyTest=# INSERT INTO cities values('Las Vegas', 1.53, 2174); --插入父表
INSERT 0 1
MyTest=# INSERT INTO cities values('Mariposa',3.30,1953); --插入父表
INSERT 0 1
MyTest=# INSERT INTO capitals values('Madison',4.34,845,'WI');--插入子表
INSERT 0 1
MyTest=# SELECT name, altitude FROM cities WHERE altitude > 500; --父表和子表的数据均被取出。
name | altitude
-----------+----------
Las Vegas | 2174
Mariposa | 1953
Madison | 845
(3 rows)
MyTest=# SELECT name, altitude FROM capitals WHERE altitude > 500; --只有子表的数据被取出。
name | altitude
---------+----------
Madison | 845
(1 row)
如果希望只从父表中提取数据,则需要在SQL中加入ONLY关键字,如:
MyTest=# SELECT name,altitude FROM ONLY cities WHERE altitude > 500;
name | altitude
-----------+----------
Las Vegas | 2174
Mariposa | 1953
(2 rows)
上例中cities前面的"ONLY"关键字表示该查询应该只对cities进行查找而不包括继承级别低于cities的表。许多我们已经讨论过的命令--SELECT,UPDATE和DELETE--支持这个"ONLY"符号。
在执行整表数据删除时,如果直接truncate父表,此时父表和其所有子表的数据均被删除,如果只是truncate子表,那么其父表的数据将不会变化,只是子表中的数据被清空。
MyTest=# TRUNCATE TABLE cities; --父表和子表的数据均被删除。
TRUNCATE TABLE
MyTest=# SELECT * FROM capitals;
name | population | altitude | state
------+------------+----------+-------
(0 rows)
2. 确定数据来源:
有时候你可能想知道某条记录来自哪个表。在每个表里我们都有一个系统隐含字段tableoid,它可以告诉你表的来源:
MyTest=# SELECT tableoid, name, altitude FROM cities WHERE altitude > 500;
tableoid | name | altitude
----------+-----------+----------
16532 | Las Vegas | 2174
16532 | Mariposa | 1953
16538 | Madison | 845
(3 rows)
以上的结果只是给出了tableoid,仅仅通过该值,我们还是无法看出实际的表名。要完成此操作,我们就需要和系统表pg_class进行关联,以通过tableoid字段从该表中提取实际的表名,见以下查询:
MyTest=# 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
(3 rows)
3. 数据插入的注意事项:
继承并不自动从INSERT或者COPY中向继承级别中的其它表填充数据。在我们的例子里,下面的INSERT语句不会成功:
INSERT INTO cities (name, population, altitude, state) VALUES ('New York', NULL, NULL, 'NY');
我们可能希望数据被传递到capitals表里面去,但是这是不会发生的:INSERT总是插入明确声明的那个表。
4. 多表继承:
一个表可以从多个父表继承,这种情况下它拥有父表们的字段的总和。子表中任意定义的字段也会加入其中。如果同一个字段名出现在多个父表中,或者同时出现在父表和子表的定义里,那么这些字段就会被"融合",这样在子表里面就只有一个这样的字段。要想融合,字段必须是相同的数据类型,否则就会抛出一个错误。融合的字段将会拥有它所继承的字段的所有约束。
CREATE TABLE parent1 (FirstCol integer);
CREATE TABLE parent2 (FirstCol integer, SecondCol varchar(20));
CREATE TABLE parent3 (FirstCol varchar(200));
--子表child1将同时继承自parent1和parent2表,而这两个父表中均包含integer类型的FirstCol字段,因此child1可以创建成功。
CREATE TABLE child1 (MyCol timestamp) INHERITS (parent1,parent2);
--子表child2将不会创建成功,因为其两个父表中均包含FirstCol字段,但是它们的类型不相同。
CREATE TABLE child2 (MyCol timestamp) INHERITS (parent1,parent3);
--子表child3同样不会创建成功,因为它和其父表均包含FirstCol字段,但是它们的类型不相同。
CREATE TABLE child3 (FirstCol varchar(20)) INHERITS(parent1);
5. 继承和权限:
表访问权限并不会自动继承。因此,一个试图访问父表的用户还必须具有访问它的所有子表的权限,或者使用ONLY关键字只从父表中提取数据。在向现有的继承层次添加新的子表的时候,请注意给它赋予所有权限。
继承特性的一个严重的局限性是索引(包括唯一约束)和外键约束只施用于单个表,而不包括它们的继承的子表。这一点不管对引用表还是被引用表都是事实,因此在上面的例子里,如果我们声明cities.name为UNIQUE或者是一个PRIMARY KEY,那么也不会阻止capitals表拥有重复了名字的cities数据行。 并且这些重复的行缺省时在查询cities表的时候会显示出来。实际上,缺省时capitals将完全没有唯一约束,因此可能包含带有同名的多个行。你应该给capitals增加唯一约束,但是这样做也不会避免与cities的重复。类似,如果我们声明cities.name REFERENCES某些其它的表,这个约束不会自动广播到capitals。在这种条件下,你可以通过手工给capitals 增加同样的REFERENCES约束来做到这点。
One Response