MySQL基礎(二):表完整性約束 ,表關係的建立(重點)

下面是小凰凰的簡介,看下吧!
💗人生態度:珍惜時間,渴望學習,熱愛音樂,把握命運,享受生活
💗學習技能:網絡 -> 雲計算運維 -> python全棧( 當前正在學習中)
💗您的點贊、收藏、關注是對博主創作的最大鼓勵,在此謝過!
有相關技能問題可以寫在下方評論區,我們一起學習,一起進步。
後期會不斷更新python全棧學習筆記,秉着質量博文爲原則,寫好每一篇博文。

一、表完整性約束

1、大致介紹

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

作用:用於保證數據的完整性和一致性 主要分爲

PRIMARY KEY (PK)    標識該字段爲該表的主鍵,可以唯一的標識記錄
FOREIGN KEY (FK)    標識該字段爲該表的外鍵
NOT NULL    標識該字段不能爲空
UNIQUE KEY (UK)    標識該字段的值是唯一的
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 default 20 年齡必須爲正值(無符號) 不允許爲空 默認是20
3. 是否是key
主鍵 primary key
外鍵 foreign key
索引 (index,unique...)

2、not null與default

(1)not null
==================not null====================
mysql> create table t1(id int); #id字段默認可以插入空
mysql> desc t1;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
mysql> insert into t1 values(); #可以插入空


mysql> create table t2(id int not null); #設置字段id不爲空
mysql> desc t2;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
mysql> insert into t2 values(); #不能插入空
ERROR 1364 (HY000): Field 'id' doesn't have a default value
(2)default
==================default====================
#設置id字段有默認值後,則無論id字段是null還是not null,都可以插入空,插入空默認填入default指定的默認值
mysql> create table t3(id int default 1);
mysql> alter table t3 modify id int not null default 1;



==================綜合練習====================
mysql> create table student(
    -> name varchar(20) not null,
    -> age int(3) unsigned default 18, # not null一般不與default連用!這裏可以添加not null,但是因爲有default了因此就可以不加了
    -> 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                    | YES  |     | 18         |       |
| sex   | enum('male','female')              | YES  |     | male       |       |
| hobby | set('play','study','read','music') | YES  |     | play,music |       |
+-------+------------------------------------+------+-----+------------+-------+
mysql> insert into student(name) values('egon');
mysql> select * from student;
+------+-----+------+------------+
| name | age | sex  | hobby      |
+------+-----+------+------------+
| egon |  18 | male | play,music |
+------+-----+------+------------+

3、unique

(1)唯一約束
============設置唯一約束 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'
(2)聯合唯一約束+非空(相當於複合主鍵)
======================== 設置聯合唯一約束 ===========================
create table service(
ip varchar(15) not null,
port char(5) not null,
service_name varchar(10) not null,
unique(ip,port)
);
# 注意聯合唯一約束加非空約束就相當於複合主鍵。注意是複合主鍵不是聯合主鍵!

4、primary key

從約束角度看primary key字段的值不爲空且唯一,即它的約束效果就等於not null+unique,那麼它本身相比not null+unique肯定也有優勢:

主鍵primary key是innodb存儲引擎組織數據的依據,innodb稱之爲索引組織表,一張表中必須有且只有一個主鍵。主鍵的主要作用是索引!

(1)單列主鍵

注意:innodb存儲引擎中一個表必須要有主鍵,如果一個表沒有主鍵,那麼會從上倒下依次查找一個not null且unique的字段爲主鍵,如果沒有這樣一個字段,自動創建一個6字節的指針作爲索引

============單列做主鍵============================================
# 方法一: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)
(2)複合主鍵

這裏要區別一下聯合主鍵和複合主鍵:聯合主鍵體現在多個表上,複合主鍵體現在一個表中的多個字段
複合主鍵應用場景:像ip+port,ip是可以重複的,因爲端口可以不同。端口可以重複,因爲ip可以不同。像這種情況下,主鍵需要兩個字段才能唯一,不重複,這個就需要複合主鍵

======================== 多列做主鍵(複合主鍵)=========================
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'

5、auto_increment

(1)設置自增字段

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

insert插入時,可以指定字段,insert into student(name) values ('huahua')

# 不指定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
    -> ('egon'),
    -> ('alex')
    -> ;

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


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

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

mysql> select * from student;
+----+------+--------+
| id | name | sex    |
+----+------+--------+
|  1 | egon | male   |
|  2 | alex | male   |
|  4 | asb  | female |
|  7 | 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 student(name) values('egon');
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | egon | male |
+----+------+------+
1 row in set (0.00 sec)
(2)指定自增的起始偏移量及步長
1. 表級指定 # 無論是否重新連接mysql,都只對該表生效
# 創建表時指定auto_increment的初始值,注意初始值的設置爲表選項,應該放到括號外
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
)auto_increment=3; # 指定該表的自增初始值,這個位置是表選項的書寫位置
注意:'表選項好像沒有自增步長。因此表級無法指定自增步長!'

2. 會話級指定 # 對當前mysql連接的所有表生效,下次重新連接mysql,恢復原樣
show session variables like 'auto_inc%';
set session auto_increment_offset=3; # 修改會話級別的自增初始值
set session auto_increment_increment=2; # 修改會話級別的自增步長

3. 全局指定 # 無論是否重新連接mysql。自增初始值和自增步長都是全局指定的這個大小。
show variables like 'auto_incre%';
set global auto_increment_offset=3; # 修改全局級別的自增初始值
set global auto_increment_increment=5; # 修改全局級別的自增步長

注意:
如果auto_increment_offset的值大於auto_increment_increment的值,則auto_increment_offset的值會被忽略 ,這相當於第一步步子就邁大了,扯着了蛋

(3)常見的表選項
# 表選項就是,創建一個表的時候,對該表的整體設定,主要有如下幾個:
charset = 要使用的字符編碼,

engine = 要使用的存儲引擎(也叫表類型),

auto_increment = 設定當前表的自增長字段的初始值,默認是1

comment = '該表的一些說明文字'

6、foreign key、級聯更新及刪除

(1)快速理解foreign key

員工信息表有三個字段:工號 姓名 部門id
還應該有個部門表:部門id,部門name,部門員工。
部門表和員工信息表之間怎麼建立關係呢?就是通過部門id建立關係的。因此部門id就是員工信息表的外鍵

#表類型必須是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,'egon',1),
(2,'alex1',2),
(3,'alex2',2),
(4,'alex3',2),
(5,'李坦克',3),
(6,'劉飛機',3),
(7,'張火箭',3),
(8,'林子彈',3),
(9,'加特林',3)
;


#刪父表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 |
+----+-------+--------+

注意:因爲員工信息表中有部門id,因此部門表應該先create!不然會報錯

(2)級聯更新、級聯刪除
constraint fk_name foreign key(dpt_id) # 聲明誰是外鍵 
references department(id) # 外鍵和那個表的那個字段關聯,該字段可以不是那個表的主鍵,但必須是unique的
on delete cascade # 級聯刪除
on update cascade # 級聯更新 

假如不要級聯更新刪除語句,那麼因爲外鍵約束,部門表中的部門無法刪除、部門id無法修改,因爲部門id在成員信息表中也有。你如果刪除了部門,成員信息表中的部門id是不會刪除的,就會信息不同步!因此需要採用級聯更新與刪除,部門id一變,成員信息表中相應成員的部門id也跟着變,部門刪除,部門下的所有員工信息也從成員信息表中刪除!保障有外鍵關聯的兩個表的內容的同步、準確!

二、建立表之間的關係

1、如何找出兩張表之間的關係

#多對一:
記住:一對多和多對一都是一樣的。
站在成員角度看:成員與部門是多對一
站在部門角度看:部門與成員是一對多
'建立關係方法:需要在多的一方的表中添加外鍵約束,設置級聯更新、刪除!'

#多對多
兩個表是雙向的多對一,即作者與圖書的關係,作者可以著有多本圖書,圖書可有多個作者
'建立關係方法:需要定義一個這兩張表的關係表來專門存放二者的關係'

#一對一:
兩個表是雙向的一對一,用戶與博客的關係,一個用戶只有一個自己的CSDN博客,自己的這個CSDN博客的用戶也只有自己。注意這裏是自己的csdn博客,而不是csdn博客平臺!
'建立關係方法:選取用戶表添加博客id外鍵字段(博客從屬於用戶,因此選擇用戶表添加外鍵字段),將用戶表的博客id外鍵字段設置成unique,且博客表中的博客id字段也需要unique,這樣才能保證一對一!'

2、建立表之間的關係

(1)多對一實操
#一對多或稱爲多對一
三張表:出版社,作者信息,書

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

關聯方式: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) unique, # 這裏的name需要指定unique,因爲如果可以重複,那麼我就可以重複指定某本書,並指定不同的出版社!這就變成了多對多關係!
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) value # 因爲書和出版社是多對一,因此一本書只能有一個出版社。所以插入數據時左側書籍沒有重複的,右側出版社可以重複
('九陽神功',1),
('九陰真經',2),
('九陰白骨爪',2),
('獨孤九劍',3),
('降龍十巴掌',2),
('葵花寶典',3)
;
(2)多對多實操
多對多:一個作者可以寫多本書,一本書也可以有多個作者,雙向的一對多,即多對多
  
關聯方式:foreign key+一張新的表
=====================多對多=====================
create table author(
id int primary key auto_increment,
name varchar(20)
);

'book表就省略不寫了!它必須是要有的!這裏只是懶得寫'

#這張表就存放作者表與書表的關係,即查詢二者的關係查這表就可以了
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');

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


2 alex: 
      1 九陽神功
      6 葵花寶典

3 yuanhao:
      4 獨孤九劍
      5 降龍十巴掌
      6 葵花寶典

4 wpq:
      1 九陽神功


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)
;
(3)一對一實操
一對一:一個學生是一個客戶,一個客戶有可能變成一個學校,即一對一的關係

關聯方式:foreign key+unique
#一定是student來foreign key表customer,這樣就保證了:
#1 學生一定是一個客戶,
#2 客戶不一定是學生,但有可能成爲一個學生


create table customer(
id int primary key auto_increment, # id必須唯一,primary key就是唯一的
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,因此customer表中的id必須唯一,這樣才能保證一對一!
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)
;

三、修改表

語法:
1. 修改表名
      ALTER TABLE 表名 RENAME 新表名;

2. 增加字段
      ALTER TABLE 表名 ADD 字段名  數據類型 [完整性約束條件…]; # 默認添加都在最後
      
      ALTER TABLE 表名 ADD 字段名  數據類型 [完整性約束條件…]  FIRST; # 在最前面添加一個字段
      
      ALTER TABLE 表名 ADD 字段名  數據類型 [完整性約束條件…]  AFTER 字段名; # 在某個字段後,添加一個新的字段

3. 刪除字段
      ALTER TABLE 表名 DROP 字段名;

4. 修改字段
      ALTER TABLE 表名 MODIFY  字段名 數據類型 [完整性約束條件…];

四、複製表

MariaDB [db1]> select * from service;
+----+------+--------------+
| ip | port | service_name |
+----+------+--------------+
|  2 | 55   |              |
|  4 | 77   |              |
|  6 | 99   |              |
+----+------+--------------+
如上所示select * from service;執行出來也是一個表的樣子。'這其實是一個存在於內存中的虛擬表。因此我們可以基於此複製表。'

'複製表結構+記錄 ( 主鍵、外鍵和索引不會複製)'
mysql> create table new_service select * from service;

五、刪除表

DROP TABLE 表名;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章