postgresql有个特有的功能,它就是表继承,这是它。下面来研究一下这个“特异功能”。
1. 建立父表和继承表:
create table employee
( id int not null,
employee_name varchar(64),
salary int check(salary>0),
primary key(id)
);
CREATE INDEX idx_employee_01 ON employee(employee_name);
create table employee_info
( depart_id int,
job_title varchar(64)
)inherits(employee);
查询继承表:
select * from employee_info;
可以看到id, emplyee_name, salary这3个字段给继承下来。
往employee_info表插入数据:
insert into employee_info
( id,
employee_name,
salary,
depart_id,
job_title
)values
(1,
'张三',
10000,
1001,
'IT manager'),
(2,
'李四',
20000,
1001,
'IT engineer')
;
再执行查询,结果如下:
可以看到,employee_info 完美地继承了父表employee的字段。
2. 查看父表和继承表的结构
父表:
dbsimple=# \d+ employee;
再看继承表:
dbsimple=# \d+ employee_info;
对比父表和继承表,可以看到主键和约束条件和索引没有被继承下来。
如果需要继承主键和约束条件,索引等,则需要在创建的时候加上Including all ;在建表的时候,发现多了"merging constraint"。
dbsimple=#drop table employee_info;
dbsimple=#create table employee_info
( like employee including all
) inherits (employee);
再次查看继承表建表信息:
dbsimple=# \d+ employee_info;
这次我们可以看到主键,约束和索引都被继承了下来。
除继承父表之外,创建继承表时可以增加自己的字段,这里在继承表增加depart_id和job_title两个字段。
alter table employee_info add column depart_id int;
alter table employee_info add column job_title varchar(64);
3. 继承只是继承表结构,数据不会继承,也就是说,父表插入的数据,子表是不存在。
往父表employee插入一条数据:
insert into employee
( id,
employee_name,
salary
)values
(1,
'王五',
15000);
结果只看到父表的字段和数据。
查询继承表:
没有看到父表插入的数据。
4. 删除掉父表的约束employee_pkey,发现继承表c1的约束还是存在的 。
dbsimple=#alter table employee drop constraint employee_pkey;
dbsimple=# \d+ employee;
父表的主键被删除了。
dbsimple=# \d+ employee_info;
而继承表的主键还存在。
5. 在查询父表数据的时候,对应的继承表数据也被查询出来,但字段仅是父表创建的字段 。但是查询继承表就不会查询父表 的数据。
dbsimple=# explain select * from employee;
dbsimple=# explain select * from employee_info;
在查询父表数据,如果不要继承表的数据,可以加上only:
dbsimple=# select * from only employee;
6. 修改父表和继承表的数据,对应能查找到的数据也跟随着发生更新。
dbsimple=#update employee
set salary=30000
where id=2
;
查询继承表:
继承表id为2的员工salary也变成了3000.
同样,更新继承表的数据,父表查询也会查到更新后的数据。
7. 修改父表的表结构,继承表也跟随着变化。
dbsimple=# alter table employee add column join_date date check(join_date>='2022-06-01');
dbsimple=# update employee set join_date='2022-06-10';
dbsimple=# select * from employee_info;
dbsimple=# \d+ employee_info;
8. 通过继承表修改继承的字段,会被拒绝。
dbsimple=# alter table employee_info drop column join_date;
9. 父表字段的attislocal属性为false的时候 .删掉父表的字段,继承表上的列不会被删除。
dbsimple=# create table employee_external(like employee)inherits(employee);
dbsimple=# \d+ employee_external;
dbsimple=# select attname,attislocal from pg_attribute where attrelid='employee_external'::regclass;
继承表employee_info的字段english_nam的attislocal值为True。
dbsimple=# create table employee_base()inherits(employee);
继承表employee_info的字段english_nam的attislocal值为false。
删除父表的english_name字段。
dbsimple=# alter table employee drop column english_name;
dbsimple=#\d+ employee;
dbsimple=#\d+ employee_external;
可以看到,employee_externa表字段english_name的attislocal值为True,没有被删除。
dbsimple=#\d+ employee_base;
可以看到,employee_base表字段english_name的attislocal值为False,字段被删除。
在父表再次增加字段english_name;
dbsimple=# alter table employee add column english_name varchar(64);
字段可以被增加。
10. 删除父表。当继承表存在的时候是不能直接删除父表。需要加上 cascade参数。
dbsimple=# drop table employee;
dbsimple=# drop table employee cascade;
把关联的继承表一起删除。
11. 当在父表上查询数据的时候,想要知道那些出自于主表,哪些出自于继承表。可以利用tableoid,来标识数据来自于那一个表,然后再通过tableoid在pg_class表中找到对用的表 。
select tableoid,* from only employee;
select tableoid,* from employee;
select tableoid,* from employee_info;
11. 解除继承。父表的记录都被保存(包括之前来源于继承表的),继承表的字段也只保留之前继承过来的字段,而继承表自己建的字段被删除,同时继承表的所有记录也被清空。
dbsimple=# alter table employee_external no inherit employee;
dbsimple=# select * from employee_external;
dbsimple=# select * from employee;
12. 多表继承。一个表可以从多个父表继承,这种情况下它会拥有所有父表的字段。 如果同一个字段名出现在多个父表中,或者同时出现在父表和继承表表的定义里,那么这些字段就会被"融合",这样在子表里面就只有一个这样的字段。要想融合,字段必须是相同的数据类型,否则就会抛出一个错误。融合的字段将会拥有它所继承的字段的所有约束。继承表可以增加自己的字段。
create table employee
( id int not null,
employee_id int,
employee_name varchar(64),
salary int check(salary>0),
primary key(id)
);
create table employee_base
( id int not null,
employee_id int,
salary int check(salary>0),
join_date date,
primary key(id)
);
create table employee_external
(phone varchar(20))inherits (employee,employee_base)
;
dbsimple=# \d+ employee_external;
13. 继承和权限. 表访问权限并不会自动继承。因此,一个试图访问父表的用户还必须具有访问它的所有子表的权限,或者使用ONLY关键字只从父表中提取数据。