python 之 数据库(字段的约束条件,表之间的关系)
10.6 约束条件
10.61 not null 、default
create table t15( id int, name char(16) not null, sex enum('male','female','other') not null default "male" ); #alter table t15 modify name char(16) not null; insert into t15(id,name) values (1,'egon1'), (2,'egon2'), (3,'egon3'); mysql> desc t15; +-------+-------------------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------------------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | char(16) | NO | | NULL | | | sex | enum('male','female','other') | NO | | male | | +-------+-------------------------------+------+-----+---------+-------+ mysql> select * from t15; +------+-------+------+ | id | name | sex | +------+-------+------+ | 1 | egon1 | male | | 2 | egon2 | male | | 3 | egon3 | male | +------+-------+------+
10.62 unique
mysql中存在一种专门的数据结构,叫 key,又称为索引,通过该数据结构可以减少 i/o 次数,从而加速查询效率 index key : 只有加速查询的效果,没有约束的功能 unique key:不仅有加速查询的效果,还附加了一种约束的功能 primary key:不仅有加速查询的效果,还附加了一种约束的功能,并且innodb存储引擎会按照主键字段的值 来组织表中所有的数据,所以一种inndob表中必须有、而且只能有一个主键,通常为该表的id字段
unique:限制字段的值的唯一性,单从约束角度去看:唯一性约束
#单列唯一 create table t16( id int unique, name char(16) ); # 联合唯一(不能完全相同) create table server( id int unique, ip char(15), port int, unique(ip,port) ); mysql> desc server; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | YES | UNI | NULL | | | ip | char(15) | YES | MUL | NULL | | | port | int(11) | YES | | NULL | | +-------+----------+------+-----+---------+-------+ insert into server values(1,'1.1.1.1',3306),(2,'1.1.1.1',3307),(3,'1.1.1.2',3306); mysql> select * from server; +------+---------+------+ | id | ip | port | +------+---------+------+ | 1 | 1.1.1.1 | 3306 | | 2 | 1.1.1.1 | 3307 | | 3 | 1.1.1.2 | 3306 | +------+---------+------+
10.63 primary key
primary key:单单从约束角度去看,primary key就等同于 not null + unique 强调: 1、一张表中必须有,并且只能有一个主键 2、一张表中都应该有一个id字段,而且应该把id字段做成主键
create table t17( id int primary key, name char(16), age int, sex char(6) )engine=innodb; #联合主键(不完全相同,但不能为空) create table t19( ip char(15), port int, primary key(ip,port) ); mysql> desc t19; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | ip | char(15) | NO | PRI | | | | port | int(11) | NO | PRI | 0 | | +-------+----------+------+-----+---------+-------+
10.64 auto_increment
只能给被约束成key的字段加自增属性,默认起始位置是1,步长也为1
# primary key auto_increment create table t20( id int primary key auto_increment, name char(16) )engine=innodb; mysql> insert t20(name) values('egon1'); mysql> insert t20(name) values('egon2'); mysql> select * from t20; +----+-------+ | id | name | +----+-------+ | 1 | egon1 | | 2 | egon2 | +----+-------+
10.7 表关系
10.71 多对一(foreign key)
1、把所有数据都存放于一张表的弊端:
-
表的组织结构复杂不清晰
-
浪费空间
-
扩展性极差
2、寻找表与表之间的关系的方法: 举例:emp表 dep表 步骤一: part1: 1、先站在左表emp的角度 2、去找左表emp的多条记录能否对应右表dep的一条记录
part2: 1、站在右表dep的角度 2、去找右表dep的多条记录能否对应左表emp的一条记录 3、如何实现? 在emp表中新增一个dep_id字段,该字段指向dep表的id字段
4、foreign key会带来什么样的效果?
约束1:在创建表时,先建被关联的表dep,才能建关联表emp
create table dep( id int primary key auto_increment, dep_name char(10), dep_comment char(60) ); mysql> desc dep; +-------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | dep_name | char(10) | YES | | NULL | | | dep_comment | char(60) | YES | | NULL | | +-------------+----------+------+-----+---------+----------------+ create table emp( id int primary key auto_increment, name char(16), gender enum('male','female') not null default 'male', dep_id int, foreign key(dep_id) references dep(id) ); mysql> desc emp; +--------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | char(16) | YES | | NULL | | | gender | enum('male','female') | NO | | male | | | dep_id | int(11) | YES | MUL | NULL | | +--------+-----------------------+------+-----+---------+----------------+
约束2:在插入记录时,必须先插被关联的表dep,才能插关联表emp
insert into dep(dep_name,dep_comment) values ('sb教学部','sb辅导学生学习,教授python课程'), ('外交部','形象大使'), ('nb技术部','nb技术能力有限部门'); mysql> select * from dep; +----+-------------+-------------------------------------------+ | id | dep_name | dep_comment | +----+-------------+-------------------------------------------+ | 1 | sb教学部 | sb辅导学生学习,教授python课程 | | 2 | 外交部 | 形象大使 | | 3 | nb技术部 | nb技术能力有限部门 | +----+-------------+-------------------------------------------+ insert into emp(name,gender,dep_id) values ('alex','male',1), ('egon','male',2), ('lxx','male',1), ('wxx','male',1), ('wenzhou','female',3); mysql> select * from emp; +----+---------+--------+--------+ | id | name | gender | dep_id | +----+---------+--------+--------+ | 1 | alex | male | 1 | | 2 | egon | male | 2 | | 3 | lxx | male | 1 | | 4 | wxx | male | 1 | | 5 | wenzhou | female | 3 | +----+---------+--------+--------+
约束3:更新与删除都需要考虑到关联与被关联的关系(不能直接改变dep表的id) 解决方案:
1、先删除关联表emp,再删除被关联表dep,准备重建 mysql> drop table emp; mysql> drop table dep; 2、重建:新增功能:同步更新,同步删除 create table dep( #先建被参照的表 id int primary key auto_increment, dep_name char(10), dep_comment char(60)); create table emp( id int primary key auto_increment, name char(16), gender enum('male','female') not null default 'male', dep_id int, foreign key(dep_id) references dep(id) on update cascade on delete cascade); insert into dep(dep_name,dep_comment) values ('sb教学部','sb辅导学生学习,教授python课程'), ('外交部','形象大使'), ('nb技术部','nb技术能力有限部门'); mysql> select * from dep; +----+------------------+------------------------------ | id | dep_name | dep_comment | +----+------------------+------------------------------ | 1 | sb教学部 | sb辅导学生学习,教授python课程 | | 2 | 外交部 | 形象大使 | | 3 | nb技术部 | nb技术能力有限部门 | +----+------------------+------------------------------- insert into emp(name,gender,dep_id) values ('alex','male',1), ('egon','male',2), ('lxx','male',1), ('wxx','male',1), ('wenzhou','female',3); mysql> select * from emp; +----+------------------+--------+--------+ | id | name | gender | dep_id | +----+------------------+--------+--------+ | 1 | alex | male | 1 | | 2 | egon | male | 2 | | 3 | lxx | male | 1 | | 4 | wxx | male | 1 | | 5 | wenzhou | female | 3 | +----+------------------+--------+--------+ # 同步删除 mysql> delete from dep where id=1; mysql> select * from dep; +----+------------------+------------------ | id | dep_name | dep_comment | +----+------------------+------------------ | 2 | 外交部 | 形象大使 | | 3 | nb技术部 | nb技术能力有限部门 | +----+------------------+------------------ mysql> select * from emp; +----+------------------+--------+--------+ | id | name | gender | dep_id | +----+------------------+--------+--------+ | 2 | egon | male | 2 | | 5 | wenzhou | female | 3 | +----+------------------+--------+--------+ #同步更新 mysql> update dep set id=200 where id =2; mysql> select * from dep; +-----+------------------+---------------- | id | dep_name | dep_comment | +-----+------------------+---------------- | 3 | nb技术部 | nb技术能力有限部| | 200 | 外交部 | 形象大使 | +-----+------------------+---------------- mysql> select * from emp; +----+------------------+--------+--------+ | id | name | gender | dep_id | +----+------------------+--------+--------+ | 2 | egon | male | 200 | | 5 | wenzhou | female | 3 | +----+------------------+--------+--------+
10.72 多对多(foreign key)
1、什么是多对多 两张表之间是一个双向的多对一关系,称之为多对多 2、如何实现? 建立第三张表,该表中有一个字段是fk左表的id,还有一个字段是fk右表的id
create table author( id int primary key auto_increment, name char(16)); create table book( id int primary key auto_increment, bname char(16), price int); insert into author(name) values ('egon'), ('alex'), ('wxx'); mysql> select * from author; +----+------+ | id | name | +----+------+ | 1 | egon | | 2 | alex | | 3 | wxx | +----+------+ insert into book(bname,price) values ('python从入门到入土',200), ('葵花宝典切割到精通',800), ('九阴真经',500), ('九阳神功',100); mysql> select * from book; +----+-----------------------------+-------+ | id | bname | price | +----+-----------------------------+-------+ | 1 | python从入门到入土 | 200 | | 2 | 葵花宝典切割到精通 | 800 | | 3 | 九阴真经 | 500 | | 4 | 九阳神功 | 100 | +----+-----------------------------+-------+ create table author2book( id int primary key auto_increment, author_id int, book_id int, foreign key(author_id) references author(id) on update cascade on delete cascade, foreign key(book_id) references book(id) on update cascade on delete cascade); insert into author2book(author_id,book_id) values (1,3),(1,4),(2,2),(2,4),(3,1),(3,2),(3,3),(3,4); mysql> select * from author2book; +----+-----------+---------+ | id | author_id | book_id | +----+-----------+---------+ | 1 | 1 | 3 | | 2 | 1 | 4 | | 3 | 2 | 2 | | 4 | 2 | 4 | | 5 | 3 | 1 | | 6 | 3 | 2 | | 7 | 3 | 3 | | 8 | 3 | 4 | +----+-----------+---------+
10.73 一对一(unique+foreign key)
一对一:左表的一条记录唯一对应右表的一条记录,反之也一样 create table customer( #先建被参照的表 id int primary key auto_increment, name char(20) not null, qq char(10) not null, phone char(16) not null); create table student( id int primary key auto_increment, class_name char(20) not null, customer_id int unique, #该字段一定要是唯一的,一对一 foreign key(customer_id) references customer(id) #外键的字段一定要保证unique on delete cascade on update cascade); insert into customer(name,qq,phone) values ('李飞机','31811231',13811341220), ('王大炮','123123123',15213146809), ('守榴弹','283818181',1867141331), ('吴坦克','283818181',1851143312), ('赢火箭','888818181',1861243314), ('战地雷','112312312',18811431230); mysql> select * from customer; +----+-----------+-----------+-------------+ | id | name | qq | phone | +----+-----------+-----------+-------------+ | 1 | 李飞机 | 31811231 | 13811341220 | | 2 | 王大炮 | 123123123 | 15213146809 | | 3 | 守榴弹 | 283818181 | 1867141331 | | 4 | 吴坦克 | 283818181 | 1851143312 | | 5 | 赢火箭 | 888818181 | 1861243314 | | 6 | 战地雷 | 112312312 | 18811431230 | +----+-----------+-----------+-------------+ insert into student(class_name,customer_id) values ('python',3),('java',4),('c++',5); mysql> select * from student; +----+-------------+-------------+ | id | class_name | customer_id | +----+-------------+-------------+ | 1 | python | 3 | | 2 | java | 4 | | 3 | c++ | 5 | +----+-------------+-------------+