1. 程式人生 > >mysql 表完整性約束

mysql 表完整性約束

ict open let xtra 字符串 none java 財務 oms

約束關鍵字

PRIMARY KEY (PK) 標識該字段為該表的主鍵,可以唯一的標識記錄
FOREIGN KEY (FK) 標識該字段為該表的外鍵
NOT NULL 標識該字段不能為空
UNIQUE KEY (UK) 標識該字段的值是唯一的
AUTO_INCREMENT 標識該字段的值自動增長(整數類型,而且為主鍵)
DEFAULT 為該字段設置默認值
UNSIGNED 無符號
ZEROFILL 使用0填充

not null與default

是否可空,null表示空,非字符串,not null - 不可空,null - 可空;default默認值,創建列時可以指定默認值,當插入數據時如果未主動設置,則自動添加默認值

技術分享圖片
mysql> create table student(
-> name varchar(20) not null,
-> age int(2) unsigned not null default 18,
-> sex enum(male,female) default male,
-> hobby set(play,study,read,music) default play,music
-> );
mysql> desc student;
+-------+------------------------------------+------+-----+------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------------------------+------+-----+------------+-------+
| name | varchar(20
) | NO | | NULL | | | age | int(3) unsigned | NO | | 18 | | | sex | enum(male,female) | YES | | male | | | hobby | set(play,study,read,music) | YES | | play,music | | +-------+------------------------------------+------+-----+------------+-------+ mysql> insert into student(name) values(
jack); mysql> select * from student; +------+-----+------+------------+ | name | age | sex | hobby | +------+-----+------+------------+ | jack | 18 | male | play,music | +------+-----+------+------------+
View Code

unique

技術分享圖片
============設置唯一約束 UNIQUE===============
#方法一:
create table department1(
id int,
name varchar(20) unique,
comment varchar(100)
);

#方法二:
create table department2(
id int,
name varchar(20),
comment varchar(100),
constraint uk_name unique(name)
);


mysql> insert into department1 values(1,IT,技術);
Query OK, 1 row affected (0.00 sec)
mysql> insert into department1 values(1,IT,技術);
ERROR 1062 (23000): Duplicate entry IT for key name
View Code

not null+unique

mysql> create table t1(id int not null unique);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t1;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)

聯合唯一

技術分享圖片
create table service(
id int primary key auto_increment,
name varchar(20),
host varchar(15) not null,
port int not null,
unique(host,port) #聯合唯一
);

mysql> insert into service values
-> (1,nginx,192.168.0.10,80),
-> (2,haproxy,192.168.0.20,80),
-> (3,mysql,192.168.0.30,3306)
-> ;
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> insert into service(name,host,port) values(nginx,192.168.0.10,80);
ERROR 1062 (23000): Duplicate entry 192.168.0.10-80 for key host
View Code

primary key

primary key字段的值不為空且唯一,直接使用not null+unique不就可以了嗎,要它幹什麽?因為主鍵primary key是innodb存儲引擎組織數據的依據,innodb稱之為索引組織表,一張表中必須有且只有一個主鍵。

單列主鍵

技術分享圖片
============單列做主鍵===============
#方法一:not null+unique
create table department1(
id int not null unique, #主鍵
name varchar(20) not null unique,
comment varchar(100)
);

mysql> desc department1;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | NO | UNI | NULL | |
| comment | varchar(100) | YES | | NULL | |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)

#方法二:在某一個字段後用primary key
create table department2(
id int primary key, #主鍵
name varchar(20),
comment varchar(100)
);

mysql> desc department2;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
| comment | varchar(100) | YES | | NULL | |
+---------+--------------+------+-----+---------+-------+
rows in set (0.00 sec)

#方法三:在所有字段後單獨定義primary key
create table department3(
id int,
name varchar(20),
comment varchar(100),
constraint pk_name primary key(id); #創建主鍵並為其命名pk_name

mysql> desc department3;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
| comment | varchar(100) | YES | | NULL | |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)
View Code

多列主鍵

技術分享圖片
==================多列做主鍵================
create table service(
ip varchar(15),
port char(5),
service_name varchar(10) not null,
primary key(ip,port)
);


mysql> desc service;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| ip | varchar(15) | NO | PRI | NULL | |
| port | char(5) | NO | PRI | NULL | |
| service_name | varchar(10) | NO | | NULL | |
+--------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> insert into service values
-> (172.16.45.10,3306,mysqld),
-> (172.16.45.11,3306,mariadb)
-> ;
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> insert into service values (172.16.45.10,3306,nginx);
ERROR 1062 (23000): Duplicate entry 172.16.45.10-3306 for key PRIMARY
View Code

auto_increment

約束字段為自動增長,被約束的字段必須同時被key約束

技術分享圖片
#不指定id,則自動增長
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum(male,female) default male
);

mysql> desc student;
+-------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| sex | enum(male,female) | YES | | male | |
+-------+-----------------------+------+-----+---------+----------------+
mysql> insert into student(name) values
-> (jack),
-> (toms)
-> ;

mysql> select * from student;
+----+------+------+
| id | name | sex |
+----+------+------+
| 1 | jack | male |
| 2 | toms | male |
+----+------+------+


#也可以指定id
mysql> insert into student values(4,lurs,female);
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values(7,rust,female);
Query OK, 1 row affected (0.00 sec)

mysql> select * from student;
+----+------+--------+
| id | name | sex |
+----+------+--------+
| 1 | jack | male |
| 2 | toms | male |
| 4 | lurs | female |
| 7 | rust | female |
+----+------+--------+


#對於自增的字段,在用delete刪除後,再插入值,該字段仍按照刪除前的位置繼續增長
mysql> delete from student;
Query OK, 4 rows affected (0.00 sec)

mysql> select * from student;
Empty set (0.00 sec)

mysql> insert into student(name) values(ysb);
mysql> select * from student;
+----+------+------+
| id | name | sex |
+----+------+------+
| 8 | ysb | male |
+----+------+------+

#應該用truncate清空表,比起delete一條一條地刪除記錄,truncate是直接清空表,在刪除大表時用它
mysql> truncate student;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into student(name) values(jack);
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex |
+----+------+------+
| 1 | jack | male |
+----+------+------+
1 row in set (0.00 sec)
View Code

foreign key(外鍵約束)

  MySQL通過外鍵約束來保證表與表之間的數據的完整性和準確性, 外鍵的使用條件:

  • 兩個表必須是InnoDB表,MyISAM表暫時不支持外鍵(據說以後的版本有可能支持,但至少目前不支持);
  • 外鍵列必須建立了索引,MySQL 4.1.2以後的版本在建立外鍵時會自動創建索引,但如果在較早的版本則需要顯示建立;
  • 外鍵關系的兩個表的列必須是數據類型相似,也就是可以相互轉換類型的列,比如int和tinyint可以,而int和char則不可以;

外鍵定義語法

[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
該語法可以在 CREATE TABLE 和 ALTER TABLE 時使用,如果不指定CONSTRAINT symbol,MYSQL會自動生成一個名字。
ON DELETE、ON UPDATE表示事件觸發限制,可設參數:
RESTRICT(限制外表中的外鍵改動)
CASCADE(跟隨外鍵改動)
SET NULL(設空值)
SET DEFAULT(設默認值)
NO ACTION(無動作,默認的)

簡單示例

#表類型必須是innodb存儲引擎,且被關聯的字段,即references指定的另外一個表的字段,必須保證唯一
create table department(
id int primary key,
name varchar(20) not null
)engine=innodb;

#dpt_id外鍵,關聯父表(department主鍵id),同步更新,同步刪除
create table employee(
id int primary key,
name varchar(20) not null,
dpt_id int,
constraint fk_name foreign key(dpt_id)
references department(id)
on delete cascade
on update cascade 
)engine=innodb;


#先往父表department中插入記錄
insert into department values
(1,財務部),
(2,運營部),
(3,銷售部);


#再往子表employee中插入記錄
insert into employee values
(1,jack,1),
(2,rusa,2),
(3,susa,2),
(4,toms,3),
(5,qion,3),
;


#刪父表department,子表employee中對應的記錄跟著刪
mysql> delete from department where id=3;
mysql> select * from employee;
+----+-------+--------+
| id | name | dpt_id |
+----+-------+--------+
| 1 | jack | 1 |
| 2 | rusa | 2 |
| 3 | susa | 2 |
+----+-------+--------+


#更新父表department,子表employee中對應的記錄跟著改
mysql> update department set id=22222 where id=2;
mysql> select * from employee;
+----+-------+--------+
| id | name | dpt_id |
+----+-------+--------+
| 1 | jack | 1 |
| 3 | susa | 2 |
| 4 | toms | 2 |
| 5 | rusa | 2 |
+----+-------+--------+

表與表之間常見的關系

#站在左表的角度去找
是否左表的多條記錄可以對應右表的一條記錄,如果是,則證明左表的一個字段foreign key 右表一個字段(通常是id)

#站在右表的角度去找
是否右表的多條記錄可以對應左表的一條記錄,如果是,則證明右表的一個字段foreign key 左表一個字段(通常是id)

#總結:

#多對一:
如果只有步驟1成立,則是左表多對一右表
如果只有步驟2成立,則是右表多對一左表

#多對多
如果步驟1和2同時成立,則證明這兩張表時一個雙向的多對一,即多對多,需要定義一個這兩張表的關系表來專門存放二者的關系

#一對一:
如果1和2都不成立,而是左表的一條記錄唯一對應右表的一條記錄,反之亦然。這種情況很簡單,就是在左表foreign key右表的基礎上,將左表的外鍵字段設置成unique即可

一對多

技術分享圖片
=========================多對一=================

一對多(或多對一):一個出版社可以出版多本書,關聯方式:foreign key
================================================
create table press(
id int primary key auto_increment,
name varchar(20)
);

create table book(
id int primary key auto_increment,
name varchar(20),
press_id int not null,
foreign key(press_id) references press(id)
on delete cascade
on update cascade
);


insert into press(name) values
(北京工業出版社),
(人民音樂出版社),
(機械工業出版社)
;

insert into book(name,press_id) values
(python,1),
(java,2),
(c,2),
(ruby,3),
(c#,3)
;
View Code

多對多

技術分享圖片
======================多對多=======================
三張表:出版社,作者信息,書
多對多:一個作者可以寫多本書,一本書也可以有多個作者,雙向的一對多,即多對多
關聯方式:foreign key+一張新的表

===================================================
create table author(
id int primary key auto_increment,
name varchar(20)
);


#這張表就存放作者表與書表的關系,即查詢二者的關系查這表就可以了
create table author_book(
id int not null unique auto_increment,
author_id int not null,
book_id int not null,
constraint fk_author foreign key(author_id) references author(id)
on delete cascade
on update cascade,
constraint fk_book foreign key(book_id) references book(id)
on delete cascade
on update cascade,
primary key(author_id,book_id)
);


#插入四個作者,id依次排開
insert into author(name) values(jack),(rusa),(susa),(toms);

#每個作者與自己的代表作如下
1 jack: 
1 pythom
2 ruby


2 rusa: 
1 c#
6 c

3 susa:
4 js
5 html
6 java

4 toms:
3 vb


insert into author2book(author_id,book_id) values
(1,1),
(1,2),
(2,1),
(2,6),
(3,4),
(3,5),
(3,6),
(4,1)
View Code

一對一

技術分享圖片
=======================一對一===============================
兩張表:學生表和客戶表
一對一:一個學生是一個客戶,一個客戶有可能變成一個學校,即一對一的關系
關聯方式:foreign key+unique
一定是student來foreign key表customer,這樣就保證了:
學生一定是一個客戶,
客戶不一定是學生,但有可能成為一個學生
============================================================

create table customer(
id int primary key auto_increment,
name varchar(20) not null,
qq varchar(10) not null,
phone char(16) not null
);


create table student(
id int primary key auto_increment,
class_name varchar(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
(jack,31811231,13811341220),
(rusa,123123123,15213146809),
(toms,283818181,1867141331),
(jiek,283818181,1851143312),
(alie,888818181,1861243314),
(heli,112312312,18811431230)
;


#增加學生
insert into student(class_name,customer_id) values
(python,3),
(java,4),
(js,5)
;
View Code

mysql 表完整性約束