1. 程式人生 > >數據庫:表操作-完整性約束

數據庫:表操作-完整性約束

基礎 sig 表示 大表 highlight play 關聯 總結 符號

一、介紹

約束條件與數據類型的寬度一樣,都是可選參數

作用:用於保證數據的完整性和一致性

主要分為:

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


UNSIGNED        無符號
ZEROFILL        使用0填充

  說明:

1.    是否允許為空,默認null,可設置NOT null,字段不允許為空,必須賦值
2.字段是否有默認值,缺省的默認值是null,如果插入記錄時不給字段賦值,此字段使用默認值sex enum(‘male‘,‘female‘) not null default ‘male‘
age int unsigned NOT NULL defalut 20    必須為正值(無符號),不允許為空,默認是20
3. 是否是key
主鍵    PRIMARY key
外鍵    foreign    key
索引(index,unique)

  

二、not null 與default

是否可空,null表示空,非字符串

not null - 不可空

null- 可空

默認值,創建列時可以指定默認值,當插入數據時如果未主動設置,則自動添加默認值

==================not null====================
mysql> create table tt1(id int);
Query OK, 0 rows affected (0.01 sec)

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

mysql> insert into tt1 values();    # id字段默認可以插入為空
Query OK, 1 row affected (0.01 sec)


mysql> create table tt2(id int not null);
Query OK, 0 rows affected (0.01 sec)

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

mysql> insert into tt2(id) values();
ERROR 1136 (21S01): Column count doesn‘t match value count at row 1


==================default====================
#設置id字段有默認值後,則無論id字段是null還是not null,都可以插入空,插入空默認填入default指定的默認值

mysql> create table tt3(id int default 1);
Query OK, 0 rows affected (0.03 sec)

mysql> alter table tt3 modify id int not null default 1;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

==================綜合練習====================
mysql> create table student11( name varchar(20) not null, age int(3) unsigned not null default 18, sex enum(‘male‘,‘female‘) default ‘male‘, hobby set(‘play‘,‘study‘,‘read‘,‘music‘) default ‘play,music‘ );
Query OK, 0 rows affected (0.01 sec)

mysql> desc student11;
+-------+------------------------------------+------+-----+------------+-------+
| 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 |       |
+-------+------------------------------------+------+-----+------------+-------+
4 rows in set (0.00 sec)

mysql> insert into student11(name) values(‘mike‘);
Query OK, 1 row affected (0.01 sec)

mysql> select * from student11;
+------+-----+------+------------+
| name | age | sex  | hobby      |
+------+-----+------+------------+
| mike |  18 | male | play,music |
+------+-----+------+------------+
1 row in set (0.00 sec)

  

三、unique

============設置唯一約束 UNIQUE===============
方法一:
mysql> create table department11(
    -> id int,
    -> name varchar(20) unique,
    -> comment varchar(100)
    -> );
Query OK, 0 rows affected (0.01 sec)


方法二:
mysql> create table department12(
 id int, 
name varchar(20),
comment varchar(100)    # 別名

Query OK, 0 rows affected (0.01 sec)

mysql> insert into department11 values(1,‘IT‘,‘技術‘);
Query OK, 1 row affected (0.00 sec)

mysql> insert into department11 values(1,‘IT‘,‘技術‘);
ERROR 1062 (23000): Duplicate entry ‘IT‘ for key ‘name‘

  

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‘

  

四、PRIMARY key

PRIMARY key字段的值不為空且唯一

一個表中可以:

單列做主鍵

多列做主鍵(復合主鍵)

但一個表內只能有一個主鍵PRIMARY key

============單列做主鍵===============
#方法一:not null+unique
mysql> create table departmentt13(
    -> id int not null unique,
    -> name varchar(20) not null unique,
    -> comment varchar(10)
    -> );
Query OK, 0 rows affected (0.02 sec)


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

#方法二:在某一個字段後用primary key
mysql> create table department13(
    -> id int primary key,
    -> name varchar(20),
    -> comment varchar(10)
    -> );
Query OK, 0 rows affected (0.00 sec)

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

#方法三:在所有字段後單獨定義primary key
mysql> create table department14( id int, name varchar(20), comment varchar(10), constraint pk_name primary key(id));
Query OK, 0 rows affected (0.00 sec)


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

==================多列做主鍵================
mysql> create table service2( ip varchar(15), port char(5), service_name varchar(10) not null, primary key(ip,port) );
Query OK, 0 rows affected (0.01 sec)

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


mysql> insert into service2 values
    -> (‘172.16.45.10‘,‘3306‘,‘mysqld‘);
Query OK, 1 row affected (0.00 sec)

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

  

五、auto_increment

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

# 不指定id,則自動增長
mysql> create table student3(
    -> id int primary key auto_increment,
    -> name varchar(20),
    -> sex enum(‘male‘,‘female‘) default ‘male‘
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> desc student3;
+-------+-----------------------+------+-----+---------+----------------+
| 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    |                |
+-------+-----------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> insert into student3(name) values
    -> (‘mike‘),
    -> (‘jack‘);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from student3;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | mike | male |
|  2 | jack | male |
+----+------+------+
2 rows in set (0.00 sec)

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

mysql> insert into student3 values(5,‘wsb‘,‘female‘);
Query OK, 1 row affected (0.00 sec)

mysql> select * from student3;
+----+------+--------+
| id | name | sex    |
+----+------+--------+
|  1 | mike | male   |
|  2 | jack | male   |
|  4 | asb  | female |
|  5 | wsb  | 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 student3(name) values(‘egon‘);
Query OK, 1 row affected (0.01 sec)

mysql> select * from student3;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | egon | male |
+----+------+------+
row in set (0.00 sec)

  

# 在創建完表後,修改自增字段的起始值
mysql> create table student5(
    -> id int primary key auto_increment,
    -> name varchar(20),
    -> sex enum(‘male‘,‘female‘) default ‘male‘
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> alter table student5 auto_increment=3;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table student;


#也可以創建表時指定auto_increment的初始值,註意初始值的設置為表選項,應該放到括號外
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum(‘male‘,‘female‘) default ‘male‘
)auto_increment=3;

# 設置步長
    基於表級別
    create table t1(
        id int。。。
    )engine=innodb,auto_increment=2 步長=2 default charset=utf8

mysql自增的步長:
    show session variables like ‘auto_inc%‘;

    #基於會話級別
    set session auth_increment_increment=2 #修改會話級別的步長

    #基於全局級別的
    set global auth_increment_increment=2 #修改全局級別的步長(所有會話都生效)


#!!!註意了註意了註意了!!!
If the value of auto_increment_offset is greater than that of auto_increment_increment, the value of auto_increment_offset is ignored. 
翻譯:如果auto_increment_offset的值大於auto_increment_increment的值,則auto_increment_offset的值會被忽略 
比如:設置auto_increment_offset=3,auto_increment_increment=2



mysql> set global auto_increment_increment=5;
Query OK, 0 rows affected (0.00 sec)

mysql> set global auto_increment_offset=3;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like ‘auto_incre%‘; #需要退出重新登錄
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 5     |
| auto_increment_offset    | 3     |
+--------------------------+-------+

mysql> create table student7(
    -> id int primary key auto_increment,
    -> name varchar(20),
    -> sex enum(‘male‘,‘female‘) default ‘male‘
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> insert into student7(name) values(‘mike1‘),(‘mike2‘),(‘mike3‘);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from student7;
+----+-------+------+
| id | name  | sex  |
+----+-------+------+
|  3 | mike1 | male |
|  8 | mike2 | male |
| 13 | mike3 | male |
+----+-------+------+
3 rows in set (0.00 sec)

步長increment與起始偏移量offset:auto_increment_increment,auto_increment_offset

  

auto_increment時增加新內容

清空表:

delete from t1; #如果有自增id,新增的數據,仍然是以刪除前的最後一樣作為起始。

truncate table t1;數據量大,刪除速度比上一條快,且直接從零開始,

六 、foreign key
一 快速理解foreign key
#表類型必須是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,子表employee中對應的記錄跟著刪
mysql> delete from department where id=3;
mysql> select * from employee;
+----+-------+--------+
| id | name  | dpt_id |
+----+-------+--------+
|  1 | egon  |      1 |
|  2 | alex1 |      2 |
|  3 | alex2 |      2 |
|  4 | alex3 |      2 |
+----+-------+--------+


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

  

二 如何找出兩張表之間的關系

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

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

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


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

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

  

三 建立表之間的關系

# 一對多或稱為多對一
三張表:出版社,作者信息,書

一對多(或多對一):一個出版社可以出版多本書

關聯方式:foreign key
=====================多對一=====================

mysql> create table press(
    -> id int primary key auto_increment,
    -> name varchar(20)
    -> );
Query OK, 0 rows affected (0.11 sec)

mysql> 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
    -> );
Query OK, 0 rows affected (0.07 sec)

mysql> insert into press(name) values
    -> (‘北京工業地雷出版社‘),
    -> (‘人民音樂不好聽出版社‘),
    -> (‘知識產權沒有用出版社‘)
    -> ;
Query OK, 3 rows affected, 3 warnings (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 3

mysql> insert into book(name,press_id) values
    -> (‘九陽神功‘,1),
    -> (‘九陰真經‘,2),
    -> (‘九陰白骨爪‘,2),
    -> (‘獨孤九劍‘,3),
    -> (‘降龍十巴掌‘,2),
    -> (‘葵花寶典‘,3)
    -> ;
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

  

#多對多
三張表:出版社,作者信息,書

多對多:一個作者可以寫多本書,一本書也可以有多個作者,雙向的一對多,即多對多
  
關聯方式:foreign key+一張新的表

  

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


#這張表就存放作者表與書表的關系,即查詢二者的關系查這表就可以了
create table author2book(
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(‘egon‘),(‘alex‘),(‘yuanhao‘),(‘wpq‘);

#每個作者與自己的代表作如下
egon: 
九陽神功
九陰真經
九陰白骨爪
獨孤九劍
降龍十巴掌
葵花寶典
alex: 
九陽神功
葵花寶典
yuanhao:
獨孤九劍
降龍十巴掌
葵花寶典
wpq:
九陽神功


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

  

單張表:用戶表+相親關系表,相當於:用戶表+相親關系表+用戶表
多張表:用戶表+用戶與主機關系表+主機表


中間那一張存放關系的表,對外關聯的字段可以聯合唯一

  

# 一對一
兩張表:學生表和客戶表


一對一:一個學生是一個客戶,一個客戶有可能編程一個學校,即一對一的關系

關聯方式:foreign key+unique

  

#一定是student來foreign key表customer,這樣就保證了:
#1 學生一定是一個客戶,
#2 客戶不一定是學生,但有可能成為一個學生


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
(‘李飛機‘,‘31811231‘,13811341220),
(‘王大炮‘,‘123123123‘,15213146809),
(‘守榴彈‘,‘283818181‘,1867141331),
(‘吳坦克‘,‘283818181‘,1851143312),
(‘贏火箭‘,‘888818181‘,1861243314),
(‘戰地雷‘,‘112312312‘,18811431230)
;


#增加學生
insert into student(class_name,customer_id) values
(‘脫產3班‘,3),
(‘周末19期‘,4),
(‘周末19期‘,5)
;

  

例一:一個用戶只有一個博客

    用戶表:
    id  name
   egon
   alex
   wupeiqi


    博客表   
           fk+unique
    id url name_id
 xxxx   1
 yyyy   3
 zzz    2



例二:一個管理員唯一對應一個用戶
    用戶表:
    id user  password
 egon    xxxx
 alex    yyyy

    管理員表:
       fk+unique
    id user_id password
  1      xxxxx
  2      yyyyy

  

  

數據庫:表操作-完整性約束