MySQL表的完整性約束

一 介紹

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

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

PRIMARY KEY (PK)    標識該字段爲該表的主鍵,能夠惟一的標識記錄
FOREIGN KEY (FK)    標識該字段爲該表的外鍵
NOT NULL    標識該字段不能爲空
UNIQUE KEY (UK)    標識該字段的值是惟一的
AUTO_INCREMENT    標識該字段的值自動增加(整數類型,並且爲主鍵)
DEFAULT    爲該字段設置默認值

UNSIGNED 無符號
ZEROFILL 使用0填充

  說明:python

  

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...)

二 not null與default

  是否可空,null表示空,非字符串
  not null - 不可空
  null - 可空mysql

  

​   默認值,建立列時能夠指定默認值,當插入數據時若是未主動設置,則自動添加默認值
​   create table tb1(
​     nid int not null defalut 2,
​     num int not null
​   );nginx

  先說一點:在咱們插入數據的時候,能夠這麼寫insert into tb1(nid,num) values(1,‘chao’);就是在插入輸入的時候,指定字段插入數據,若是我在只給num插入值,能夠這樣寫insert into tb1(num) values('chao');還能夠插入數據的時候,指定插入數據字段的順序:把nid和num換個位置,可是對應插入的值也要換位置。注意:即使是你只給一個字段傳值了,那麼也是生成一整條記錄,這條記錄的其餘字段的值若是能夠爲空,那麼他們就都是null空值,若是不能爲空,就會報錯。sql

==================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



==================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 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('chao');
mysql> select * from student;
+------+-----+------+------------+
| name | age | sex  | hobby      |
+------+-----+------+------------+
| chao|  18 | male | play,music |
+------+-----+------+------------+

  注意一點:若是是非嚴格模式,int類型不傳值的話會默認爲0,由於null不是int類型的,字段是int類型,因此他會自動將null變爲0數據庫

三 unique

  獨一無二,惟一屬性:id,身份證號等session

  是一種key,惟一鍵,是在數據類型以外的附加屬性,其實還有加速查詢的做用,後面再講這個。數據結構

============設置惟一約束 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'
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字段的值不爲空且惟一,那咱們直接使用not null+unique不就能夠了嗎,要它幹什麼?sqlserver

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

  

  一個表中能夠:

    單列作主鍵
    多列作主鍵(複合主鍵或者叫作聯合主鍵)

unique key和primary key都是MySQL的特殊類型,不只僅是個字段約束條件,還稱爲索引,能夠加快查詢速度,這個索引功能咱們後面再講,如今只講一下這些key做爲約束條件的效果。

    關於主鍵的強調內容:
        1.一張表中必須有,而且只能由一個主鍵字段:innodb引擎下存儲表數據的時候,會經過你的主鍵字段的數據來組織管理全部的數據,將數據作成一種樹形結構的數據結構,幫你較少IO次數,提升獲取定位數據、獲取數據的速度,優化查詢。
            解釋:若是咱們在一張表中沒有設置primary key,那麼mysql在建立表的時候,會按照順序從上到下遍歷你設置的字段,直到找到一個not null unique的字段,自動識別成主鍵pri,經過desc能夠看到,這樣是否是很差啊,因此咱們在建立表的時候,要給他一個主鍵,讓他優化的時候用,若是沒有pri也沒有not null unique字段,那麼innodb引擎下的mysql被逼無奈,你沒有設置主鍵字段,主鍵又有不爲空且惟一的約束,又不能擅自給你的字段加上這些約束,那麼沒辦法,它只能給你添加一個隱藏字段來幫你組織數據,若是是這樣,你想一想,主鍵是否是幫咱們作優化查詢用的啊,這個優化是咱們能夠經過主鍵來查詢數據:例如:若是咱們將id設置爲主鍵,當咱們查一個id爲30的數據的時候,也就是select * from tb1 where id=30;這個查詢語句的速度很是快,不須要遍歷前面三十條數據,就好像咱們使用的字典似的,找一個字,不須要一頁一頁的翻書,能夠首先看目錄,而後看在哪一節,而後看在哪一頁,一步步的範圍,而後很快就找到了,這就像咱們說的mysql的索引(主鍵、惟一鍵)的工做方式,一步一步的縮小範圍來查找,幾步就搞定了,因此經過主鍵你可以快速的查詢到你所須要的數據,因此,若是你的主鍵是mysql幫你加的隱藏的字段,你查詢數據的時候,就不能將這個隱藏字段做爲條件來查詢數據了,就不能享受到優化後的查詢速度了,對麼
        
        2.一張表裏面,一般都應該有一個id字段,並且一般把這個id字段做爲主鍵,固然你非要讓其餘的字段做爲主鍵也是能夠的,看你本身的設計,建立表的時候,通常都會寫create table t1(id int primary key);id int primary key這個東西在建表的時候直接就寫上
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)
============單列作主鍵===============
#方法一: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)
聯合主鍵
        和聯合惟一是相似的,
        mysql> create table t10(
            ->id int,
            ->port int,
            ->primary key(id,port)
            -> );
        Query OK, 0 rows affected (0.45 sec)

        mysql> desc t10;
        +-------+---------+------+-----+---------+-------+
        | Field | Type    | Null | Key | Default | Extra |
        +-------+---------+------+-----+---------+-------+
        | id    | int(11) | NO   | PRI | 0       |       | 
        | port  | int(11) | NO   | PRI | 0       |       |
        +-------+---------+------+-----+---------+-------+
        2 rows in set (0.10 sec)
      
        看key,兩個都寫的是pri,兩個聯合起來做爲主鍵,他們兩個做爲一個主鍵,不能再有其餘的主鍵了,也就是在建立表的時候,只能出現一次primary key方法。
        有同窗說,老師,我不寫primary key行不,只寫一個not null unique字段,固然行,可是咱們應該這樣作嗎,是否是不該該啊,因此之後設置主鍵的時候,就使用primary key來指定
==================多列作主鍵================
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'

五 auto_increment

  以前咱們插入數據的時候,id也須要本身來寫,是否是很麻煩啊,咱們是否是想,只要有一條記錄就直接插入進去啊,不須要考慮說,你如今存儲到第多少條數據了,對不對,因此出現了一個叫作auto_increment的屬性

  約束字段爲自動增加,被約束的字段必須同時被key約束,也就是說只能給約束成key的字段加自增屬性,默認起始位置爲1,步長也爲1.

#不指定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)
#在建立完表後,修改自增字段的起始值
mysql> create table student(
    -> id int primary key auto_increment,
    -> name varchar(20),
    -> sex enum('male','female') default 'male'
    -> );

mysql> alter table student auto_increment=3;

mysql> show create table student;
.......
ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

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

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

mysql> show create table student;
.......
ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8


#也能夠建立表時指定auto_increment的初始值,注意初始值的設置爲表選項,應該放到括號外
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
)auto_increment=3;




#設置步長
sqlserver:自增步長
    基於表級別
    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 | 1     |
| auto_increment_offset    | 1     |
+--------------------------+-------+



create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
);

mysql> insert into student(name) values('egon1'),('egon2'),('egon3');
mysql> select * from student;
+----+-------+------+
| id | name  | sex  |
+----+-------+------+
|  3 | egon1 | male |
|  8 | egon2 | male |
| 13 | egon3 | male |
+----+-------+------+

六 foreign key

  一 快速理解foreign key(外鍵其實就是標明表和表之間的關係,表和表之間若是有關係的話就三種:一對一,多對一,多對多,咱們挨個看看~)

    員工信息表有三個字段:工號 姓名 部門

    公司有3個部門,可是有1個億的員工,那意味着部門這個字段須要重複存儲,部門名字越長,越浪費

    那這就體現出來了三個缺點:

      1.表的組織結構不清晰:員工的信息、部門的信息等等都摻在一張表裏面。

      2.浪費空間,每一條信息都包含員工和部門,多個員工從屬一個部門,也須要每一個員工的信息裏都包含着部門的信息,浪費硬盤空間。

      3.擴展性極差:若是想修改一個部門的信息,好比修改部門名稱,那麼這個包含員工和部門信息的表中的全部的包含這個部門信息的數據都須要進行修改,那麼修改起來就很是麻煩,這是很是致命的缺點。

    解決方法:(畫一個excel表格來表示一下效果~~)

      咱們徹底能夠定義一個部門表,解耦和

      咱們雖然將部門表提出來了,可是員工表自己是和部門有聯繫的,你光把部門信息提出來仍是不夠的,還須要創建關聯

      而後讓員工信息表關聯該表,如何關聯,即foreign key 

      img

    在解釋一下:數據要拆到不一樣表裏面存着,你要站在兩個表的角度來看二者之間的關係,你站在部門表的角度看,一個部門包含多個員工,站在員工表看,多個員工屬於一個部門,以咱們上課來舉個例子看:如今的多個老師能夠講一個課程python,那麼老師對於課程表來講就是多對一個關係,那這是否是就是最終關係呢,咱們還須要站在課程表的角度來看,多個課程能不能被一個老師教啊,這個看業務場景,你看我們學校就不行,講python的只能講python,可是咱們上的小學,初中,高中是否是多個課程能夠被一個老師教啊,因此從老男孩的業務來看,課程表對老師表是一對一的,即使是你多個老師能夠講這一門課程,可是這一門可能對應的那幾個老師只能講這一門,不能講其餘的課程,因此他們只是單純的多對一的關係,多個老師對應一門課程,可是小學、初中、高中的業務,多個老師能夠教一門課程,一樣這多個老師每一個老師又能夠教多門課程,那麼從課程表角度來看,多個課程也能從屬一個老師,因此是多對多的關係:看下圖

    img

  二 一對多的關係  

    咱們在看看員工和部門這個多對一的關係表:

    img

    若是咱們沒有作強制的約束關係,那麼在員工表裏面那個部門id能夠隨便寫,即使是部門表裏面沒有這個id號,它也是能夠寫的,可是這樣寫就錯了,由於業務不容許,而且這個數據徹底沒用,根本就不存在這個部門,哪裏來的這個部門的員工呢,對不對,因此要作一個硬性的關係,你員工裏面的部門id必定要來自於部門表的id字段。怎麼來作這個硬性關係呢,經過外鍵foreign key,怎麼叫外鍵,就是跟外部的一個表進行關聯,創建這種硬性的關係,就叫作外鍵,就像咱們上面這兩個表似的,左邊的員工表有一個字段(部門id字段)來自於右邊的部門表,那麼咱們就能夠經過數據庫在員工表的部門id字段加上一個foreign key,外鍵關聯到右邊部門表的id字段,這樣就創建了這種硬性的關係了,以前咱們是看着兩張表之間有關係,可是沒有作強制約束,仍是兩張普通的表,操做其中任何一個,另一個也沒問題,可是加上了這種強制關係以後,他們兩個的操做也就都關聯起來了,具體操做看下面的代碼:

    img

    部門表是被關聯的表,員工表是關聯表,也就是員工表要關聯部門表,對吧,若是咱們先建立員工表,在建立員工表的時候加外鍵關係,就會報錯,看效果:

    img

    因此咱們應該先創建部門表,也就是被關聯的表,由於關聯表中的字段的數據是來根據被關聯表的被關聯字段的數據而來的。

    img

    而後看一下表結構:

    img

    表建立好了,若是咱們直接給員工表插入幾條數據,那麼會報錯,由於,你的部門尚未呢,你的員工表裏面的那個dep_id外鍵字段的數據從何而來啊?看效果:

    img

    而後咱們先插入部門的數據,而後再插入員工的數據:

    img

    而後查看一下數據:

    img

    數據沒問題了,可是你有沒有發現一個問題,就是員工表的id從6開始的,由於咱們前面插入了5條數據,失敗了,雖然失敗了,可是id自動增加了。

    因此有引出一個問題,若是想讓id從頭開始,咱們能夠把這些數據刪掉,用delete的刪除是沒用的,須要用truncate來刪除,這是清空表的意思。

    看一下delete:

    img

    delete不是用來清空表的,是用來刪除一些你想刪除的符合某些條件的數據,通常用在delete from tb1 where id>20;這樣的,若是要清空表,讓id置零,使用truncate

    再看一下truncate:

    img

    而後查看一下數據看看:

    img

    ok,你們練習一下吧~~~~

  

    咱們來看一下,若是對關聯的表進行修改的話會有什麼效果,首先咱們先修改一下部門表的id字段中的某個數據,將id的值改一下

    img

    報錯了,那咱們改一改員工表裏面的外鍵字段dep_id,改它的值來試試:

    img

    仍是報錯了!我靠,那我試試刪除一下試試,解散一個部門,刪除他的數據:

    img

    報錯了!不讓你刪除,由於你刪除以後,員工表裏面的以前屬於這個部門的記錄找不到對應的部門id了,就報錯了

    那我刪除一下員工表裏面關於這個要被解散的部門的員工數據,按理說是否是應該沒問題啊,來看看效果:

    img

    刪除成功了,徹底沒問題啊,那麼關於這個部門的全部員工數據都被刪除了,也就是說,你這個部門下面沒有任何員工了,沒有了限制了至關於,因此咱們嘗試一下看看如今能不能刪除部門表裏面的這個部門了

    img

    ok~能夠刪除了

    雖然咱們修改部門表或者員工表裏面的部門id,可是咱們能夠刪除,可是刪除這個被關聯表部門表的數據的時候因爲有關聯關係的存在,因此刪除的時候也很麻煩,要先將關聯數據刪除,才能刪除被關聯的表的數據。

    剛纔咱們刪除了教學部這個部門,當咱們想解散這個部門的時候,首先想到的是什麼,是否是咱們的部門表,想直接操做部門表進行刪除,對吧,想修改部門的id號,是否是首先想到的也是操做部門表進行修改,把部門的id修改了,可是咱們因爲關聯關係的存在,不得不考慮關聯表中的數據,對不對,因此操做就變得很麻煩了,有沒有簡單的方法呢?咱們想作的是否是說,我想刪除一個部門,直接刪除部門表裏面的數據就好了,是否是達到這個效果,刪除一個部門的時候,與這個部門關聯的全部的員工表的那些數據都跟着刪除,或者我更新部門表中一個部門的id號,那麼關聯的員工表中的關聯字段的部門id號跟着自動更新了,

    img

  

    看一下解決辦法:

    首先咱們把以前的兩個表刪除了,能先刪除部門表嗎?若是刪了部門表,你的員工表是否是找不到對應關係了,你說會不會報錯啊,因此先刪除員工表:

      1.先刪除關聯表,再刪除被關聯表,而後咱們從新創建兩個表,而後建表的時候說一下我們的解決方案。

      img

      2.重建表,咱們如今要解決的問題是:咱們要達到一個在作某個表(被關聯表)更新或者刪除操做的時候,關聯表的數據同步的進行更新和刪除的效果,因此咱們在建表的時候,能夠加上兩個功能:同步更新和同步刪除:看看如何實現:在創建關聯關係的時候,加上這兩句: on delete cascade和 on update cascade

        img

      而後把咱們之間的表和數據都插入進去:而後再進行更新刪除操做:

        img

      而後咱們再直接刪除部門表裏面的數據的時候,你看看結果:

        img

      成功了,而且員工表裏面關聯部門表id的數據也都刪除了,是否是達到了咱們剛纔想要實現的效果呀

      下面咱們來看一下更新操做,咱們以前說更新一個部門的id號,注意一個問題昂,我更新部門的名稱,你說有影響嗎?確定沒有啊,由於我員工表並非關聯的部門的名稱字段,而是關聯的部門的id字段,你改部門名稱不要緊,我經過你的id照樣找到你,可是你若是改了id號,那麼我員工表裏面的id號和你不匹配了,我就無法找到你,全部當你直接更新部門的id的時候,我就給你報錯了,大哥,你想改的是關聯字段啊,考慮一下關聯表的數據們的感覺行不行。咱們來看一下加上 on update cascade以後的效果:

      img

      將部門id爲2的部門的id改爲了200,徹底ok,員工表裏面以前關聯id爲2的部門的數據都改爲了關聯id爲200的數據了。說明同步更新也是沒問題的。

  咱們總結一下foreign key的下面幾個約束做用:

    一、先要創建被關聯的表才能創建關聯表

    二、在插入數據記錄的時候,要先想被關聯表中插入數據,才能往關聯表裏面插入數據

    三、更新或者刪除數據的時候,都須要考慮關聯表和被關聯表的關係

      解決方案:

        a.刪除表的時候,先刪除關聯表,再刪除被關聯表

        b.重建表的時候,在加外鍵關聯的時候加上這兩句:on delete cascade 和 on update cascade

  

表類型必須是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) #這句話的意思是constraint 是聲明咱們要創建一個約束啦,fk_name是約束的名稱,foreign key是約束的類型,總體的意思是,我要建立一個名爲fk_name的外鍵關聯啦,這個constraint就是一個聲明的做用,在建立外鍵的時候不加constraint fk_name也是沒問題的。先理解一下就好了,後面咱們會細講的。
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,'chao',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 | chao  |      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 | chao  |      1 |
|  3 | alex2 |  22222 |
|  4 | alex3 |  22222 |
|  5 | alex1 |  22222 |
+----+-------+--------+

  一對多的內容大體就說完了,咱們看一下多對多的關係

  三 多對多關係

    咱們上面大體提了一下多對多的關係,下面咱們經過一個例子來細講一下,這個例子就用-->書和出版社的關係來看吧:

    img

    上面是一對多沒問題,咱們再來看看書和做者的關係:

    img

    一本書能夠有多個做者,一個做者可不能夠寫多本書,二者之間是否是站在誰的角度去看都是一個一對多的關係啊,那這就是多對多的關係,那咱們建立表的時候,須要將兩個表都加一個foreign key的字段,可是你添加字段的時候,你想一想,能直接給兩個表都這一個foreign key字段嗎,兩個誰先建立,誰後建立,是否是都不行啊,兩個表的建立是否是都依賴着另一張表啊,因此咱們以前的加外鍵字段的方式對於這種多對多的關係是否是就很差用啦,怎麼辦,咱們須要經過第三張表來緩和一下二者的關係,經過第三張表來建立雙方的關係

    咱們先建立書表和做者表,而後建立第三張表,第三張表就須要有一個字段外鍵關聯書表,還有一個字段外鍵關聯做者表

    img

    而後咱們若是想查一下alex出了哪些書,你能夠怎麼查,想一下,首先在author做者表裏面找一個alex的id是多少,alex的id爲2,而後找一個第三張表裏面author_id爲2的數據中book的id,而後拿着這些book的id去book表裏面找對應的book名稱,你就可以知道alex這個做者出了哪幾本書了,對不對,這就是一個多表查詢的一個思路

    來咱們建立一下試試看(學了foreign key,這個東西是否是很簡單啊,兩個foreign key嘛~~)

    img

    img

    創建前兩張表,插入數據,創建第三張表

    而後給第三張表插入一些數據:

    img

    查看一下數據:

    img

    數據就建立好了,多對多就講完了~~~~

  

  四 一對一關係

    咱們來以我們學校的學生來舉例:

    最開始你只是一個客戶,可能還處於諮詢考慮的階段,尚未轉化爲學生,也有的客戶已經轉換爲學生了,說白了就是你交錢了,哈哈

    那咱們來建兩個表:客戶表和學生表

    img

    客戶表裏面存着客戶的信息,學生表裏面存着客戶轉換爲學生以後的學生信息,那麼這兩個表是什麼關係呢?你想一下,學生是否是從客戶轉換過來的,那麼一個學生能對應多個用戶的信息嗎?固然是不能的,那麼一個客戶能對應多個學生的信息嗎,固然也是不能的,那麼他們兩個就是一對一的關係,那這個關係該怎麼創建呢?咱們知道經過外鍵能夠創建關係,若是在客戶表裏面加外鍵關聯學生表的話,那說明你的學生表必須先被建立出來,這樣確定是不對的,由於你的客戶表先有的,才能轉換爲學生,那若是在學生表加外鍵關聯客戶表的話,貌似是能夠的,不過一個學生只對應一個客戶,那麼這個關係怎麼加呢,外鍵咱們知道是一對多的,那怎麼搞?咱們能夠把這個關聯字段設置成惟一的,不就能夠了嗎,我既和你有關聯,我還不能重複,那就作到了我和你一對一的關聯關係。

    img

    

  表關係的總結  

分析步驟:
#一、先站在左表的角度去找
是否左表的多條記錄能夠對應右表的一條記錄,若是是,則證實左表的一個字段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
('九陽神功',1),
('九陰真經',2),
('九陰白骨爪',2),
('獨孤九劍',3),
('降龍十巴掌',2),
('葵花寶典',3)[![複製代碼](https://common.cnblogs.com/images/copycode.gif)](javascript:void(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');

#每一個做者與本身的表明做以下
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)
;

  中間那一張存放關係的表,對外關聯的字段能夠聯合惟一

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

一對一:一個學生是一個客戶,一個客戶有可能變成一個學校,即一對一的關係

關聯方式: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
    1    egon
    2    alex
    3    wupeiqi


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



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

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

  瞭解:未來大家接觸某一些大型項目的時候,儘可能不要給表創建外鍵關係,由於外鍵直接在數據庫級別就變成耦合的了,那麼咱們要拓展或者刪除或者更改某些數據庫或者數據表的時候,拓展起來就比較難,咱們能夠本身從本身的程序代碼的邏輯層面上將這些關聯關係創建好,有不少公司就是這麼作的,利於拓展,若是咱們加了不少的foreign key ,那麼當你想刪除一個表的時候,可能會牽一髮而動全身,瞭解一下就能夠了

  查看全部外鍵的名稱的方法: select REFERENCED_TABLE_SCHEMA,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME,table_name,CONSTRAINT_NAME from information_schema.key_column_usage; #包含咱們建立外鍵的時候,mysql幫咱們自動生成的外鍵名稱。

  外鍵這個key的名稱咱們能夠經過constraint來指定:

  刪除外鍵關聯,添加外鍵字段並添加外鍵關聯:

mysql> desc e3;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| id    | int(11)  | NO   | PRI | NULL    | auto_increment |
| xx    | char(11) | YES  |     | NULL    |                |
| ee_id | int(11)  | YES  | MUL | NULL    |                |
+-------+----------+------+-----+---------+----------------+
3 rows in set (0.10 sec)
mysql> alter table e3 drop ee_id;  #直接刪除外鍵字段是不能夠的
ERROR 1553 (HY000): Cannot drop index 'ee_id': needed in a foreign key constraint
mysql> alter table e3 drop foreign key e3_ibfk_1; #經過上面的方法找到這個表的外鍵字段,而後先解除外鍵字段的關係,才能刪除外鍵字段
Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> desc e3;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| id    | int(11)  | NO   | PRI | NULL    | auto_increment |
| xx    | char(11) | YES  |     | NULL    |                |
| ee_id | int(11)  | YES  | MUL | NULL    |                |
+-------+----------+------+-----+---------+----------------+
3 rows in set (0.10 sec)
#解除了外鍵關係以後,是能夠隨意插入數據的,就沒有了外鍵的約束
#可是表結構的key那一項裏面仍是顯示MUL,不過不要緊,已經沒有外鍵約束的效果了,你們能夠插入一條原來那個關聯表的字段中不存在的數據來試一試,確定是沒問題的,我沒有保存下來,就不給你們演示啦,而後而後咱們就能夠刪除這個外鍵字段了
mysql> alter table e3 drop ee_id;
Query OK, 0 rows affected (0.65 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc e3;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| id    | int(11)  | NO   | PRI | NULL    | auto_increment |
| xx    | char(11) | YES  |     | NULL    |                |
+-------+----------+------+-----+---------+----------------+
2 rows in set (0.10 sec)#看添加外鍵字段和外鍵關聯:首先建立一個e2表,包含一個id字段,別忘了id字段最少也要是unique屬性,primary key固然最好啦

mysql> alter table e3 add ee_id int;
Query OK, 0 rows affected (0.64 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> alter table e3 add foreign key(ee_id) references e2(id);
Query OK, 0 rows affected (0.83 sec)
Records: 0 Duplicates: 0 Warnings: 0

#添加關聯刪除和關聯更新的操做:當刪除主表數據的時候,從表中有關的數據都跟着刪除,當主表的關係字段修改的時候,從表對應的關係字段的值也更着更新。

  alter table 從表 add foreign key(從表字段) references 主表(主表字段) on delete cascade on update cascade;

#另外,可以做爲主表(也就是多對一關係的那個一表的被關聯的那個字段)的關係字段的約束最少要是惟一的unique屬性。

    

    外鍵約束有三種約束模式(都是針對父表的約束):

    模式一: district 嚴格約束(默認的 ),父表不能刪除或者更新已經被子表數據引用的記錄

    模式二:cascade 級聯模式:父表的操做,對應的子表關聯的數據也跟着操做 。

    模式三:set null:置空模式,父表操做以後,子表對應的數據(外鍵字段)也跟着被置空。

    一般的一個合理的約束模式是:刪除的時候子表置空;更新的時候子表級聯。

    指定模式的語法:foreign key(外鍵字段)references 父表(主鍵字段)on delete 模式 on update 模式;

    注意:刪除置空的前提條件是 外鍵字段容許爲空,否則外鍵會建立失敗。

    外鍵雖然很強大,可以進行各類約束,可是外鍵的約束下降了數據的可控性和可拓展性。一般在實際開發時,不多使用外鍵來約束。

做業:

    將下面的角色關係在數據庫中建立好,而且插入一些數據進去,自行看看該如何設計,其實下面感受已經給你寫出來了都。

    img

相關文章
相關標籤/搜索