進擊のpython
數據庫——約束條件
+-------+---------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | char(6) | YES | | NULL | |
| sex | enum('male','female') | YES | | NULL | |
| hobby | set('sing','dance','Rap') | YES | | NULL | |
+-------+---------------------------+------+-----+---------+-------+
這個表你很熟悉吧,這其中的Null和Default就是約束條件
那其實不光有這些約束條件,在規定int的時候的unsigned也是約束條件
那本節就是針對約束條件來進行展開的
not null與default
Null是指該數據可以為空,Default是該參數的默認值,就好像python中的默認參數一樣
那我們現在就針對這個進行操作
create table t8(id int,name char(6),sex enum('male','female') not null default "male");
mysql> create table t8(
->
-> id int,
->
-> name char(6),
->
-> sex enum('male','female') not null default "male"
->
-> );
Query OK, 0 rows affected (0.57 sec)
mysql> desc t8;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | char(6) | YES | | NULL | |
| sex | enum('male','female') | NO | | male | |
+-------+-----------------------+------+-----+---------+-------+
3 rows in set (0.06 sec)
那現在開始進行傳值:
mysql> insert into t8(id,name) values(1,'ponny');
Query OK, 1 row affected (0.37 sec)
mysql> select * from t8;
+------+-------+------+
| id | name | sex |
+------+-------+------+
| 1 | ponny | male |
+------+-------+------+
1 row in set (0.00 sec)
那你就可以看到,這個sex這個屬性,在我沒有進行傳值的時候,庫中使用的就是默認值
unique
那null和default我們都了解完畢之后,接下來我們就開始對key進行研究
key有一個約束條件叫做unique,叫做唯一性約束,本意就是這個鍵不能重復
我們可能都默認的傳數據使得每一個值都不唯一,但其實不限制,是可以重復的
那為了不讓數據重復,我們就有需要加上約束(對原表進行操作,練習命令):
mysql> alter table t8 change id id int unique;
Query OK, 0 rows affected (0.89 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc t8;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| name | char(6) | YES | | NULL | |
| sex | enum('male','female') | NO | | male | |
+-------+-----------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
這樣id的值就不會重復了,院線數據中有個id=1的數據,我們看看再存1可不可以
mysql> insert into t8(id,name) values(1,'tom');
ERROR 1062 (23000): Duplicate entry '1' for key 'id'
如果有還添加就會出現這樣的報錯
那除了這樣的唯一,還有一種叫做聯合唯一的東西
什么叫做聯合唯一呢?舉個例子:
A:name:ponny id:2
B:name:tom id:2
這兩個數據中某一部分相等,但是整體不同,這就是整體唯一所帶來的效果
多數據中只有一個唯一限制,其實就是聯合限制
primary key
primary key 主鍵
他的約束就比較干凈利落,相當於 not null unique 還記得表的默認引擎是什么嗎?innodb對吧
在innodb引擎對主鍵是有規定的:一張表必須有一個主鍵 不對啊!前面的表都沒有主鍵啊!不是也能創建成功嗎?
是這樣的,MySQL數據庫是有一種機制,在創建表的時候,他會先看看有沒有規定主鍵
沒有規定?ok,再去找有沒有符合 not null unique 這種約束的,把第一個出現這種約束的當做主鍵
也沒有?ok,那這樣的話,MySQL就會自己偷偷地再創建一個字段,當做主鍵
但是最后一種情況很明顯,擴大了內存,畢竟自己偷偷地又創建了一個字段
同時,倒數第二種情況意味着你要同樣的表查兩遍,就會降低速度(一點速度也是速度啊!!!!)
所以說,就可以看出來,還是要規定主鍵的!!!
那主鍵其實也是有兩種的:
單列主鍵
一般情況下都是id設為主鍵,先記着,后面再說為什么
create table t9(id int primary key,name char(5));
mysql> create table t9(id int primary key,name char(5));
Query OK, 0 rows affected (1.00 sec)
mysql> desc t9;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | char(5) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.08 sec)
就可以看到,這個key的類型是PRI,也就是主鍵的意思,同時也看到null是NO
至於為空和唯一,就自己試試好吧~~
復合主鍵
復合主鍵就像聯合唯一那樣,單個數據可以相同但是總體數據不能相同,改造一下t9表:
mysql> alter table t9 add sex enum('famale','male');
Query OK, 0 rows affected (1.44 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table t9 add tel int;
Query OK, 0 rows affected (0.88 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc t9;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | char(5) | YES | | NULL | |
| sex | enum('famale','male') | YES | | NULL | |
| tel | int(11) | YES | | NULL | |
+-------+-----------------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
現在我想id和tel設為復合主鍵,肯定有同學要這么寫:
alter table t9 add primary key (id,tel);
執行之后會出現什么情況呢???
mysql> alter table t9 add primary key (id,tel);
ERROR 1068 (42000): Multiple primary key defined
這個錯誤就大概是你有多個主鍵,所以不行這么操作
復合主鍵講究的是,同時創建,對於這種情況,操作方法就是先把原先的主鍵刪掉,再創建復合主鍵
alter table t9 drop primary key;
mysql> alter table t9 drop primary key;
Query OK, 0 rows affected (1.69 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc t9;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| name | char(5) | YES | | NULL | |
| sex | enum('famale','male') | YES | | NULL | |
| tel | int(11) | YES | | NULL | |
+-------+-----------------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
然后再創建復合主鍵:
alter table t9 add primary key(id,tel);
mysql> alter table t9 add primary key(id,tel);
Query OK, 0 rows affected (1.49 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc t9;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | char(5) | YES | | NULL | |
| sex | enum('famale','male') | YES | | NULL | |
| tel | int(11) | NO | PRI | 0 | |
+-------+-----------------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
這是有表修改的方法,也可以在創建表的時候直接定義復合主鍵:
create table t10(
id int,
name char(6),
tel int,
primary key(id,tel)
);
# 橫着寫會,豎着寫就不會了????
mysql> create table t10(
->
-> id int,
->
-> name char(6),
->
-> tel int,
->
-> primary key(id,tel)
->
-> );
Query OK, 0 rows affected (1.11 sec)
mysql> desc t10;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | 0 | |
| name | char(6) | YES | | NULL | |
| tel | int(11) | NO | PRI | 0 | |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.01 sec)
正好借着新建的這個表來驗證一下復合主鍵的特性:
insert into t10(id,tel) values(1,1);
insert into t10(id,tel) values(2,1);
insert into t10(id,tel) values(1,2);
insert into t10(id,tel) values(2,1);
mysql> insert into t10(id,tel) values(1,1);
Query OK, 1 row affected (0.54 sec)
mysql>
mysql> insert into t10(id,tel) values(2,1);
Query OK, 1 row affected (0.05 sec)
mysql>
mysql> insert into t10(id,tel) values(1,2);
Query OK, 1 row affected (0.12 sec)
mysql>
mysql> insert into t10(id,tel) values(2,1);
ERROR 1062 (23000): Duplicate entry '2-1' for key 'PRIMARY'
mysql> select * from t10;
+----+------+-----+
| id | name | tel |
+----+------+-----+
| 1 | NULL | 1 |
| 1 | NULL | 2 |
| 2 | NULL | 1 |
+----+------+-----+
3 rows in set (0.00 sec)
前面的都添加成功了,而傳入(2,1)的值提示的是,已經有了對吧~所以沒有添加進去
auto_increment
自增約束
創建表格的時候,其實都默認的寫了一個字段 id
那你有沒有想過這個id是干什么用的?其實這個id是用來標志這是第幾條記錄的
那既然是標識是第幾條記錄的,那我們有沒有一種方法,讓它自動生成而不用我們自己寫?
我們想要的效果是每插入一條記錄,他就自動的加一,這是最好的對吧,所以自增就出現了
那一般約束條件都是直接在類型后面直接加對吧
create table t11(id int auto_increment);
mysql> create table t11(id int auto_increment);
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
他給我報了一個錯誤,什么錯誤呢?表類型錯誤,說一個表只能有一個自增,而且他還必須是鍵
我們現在學過哪幾種建?一個是unique,一個是primary key
前面也提過,id最好設置為主鍵,所以上面的命令應該再優化一下:
create table t11(id int primary key auto_increment);
mysql> create table t11(id int primary key auto_increment);
Query OK, 0 rows affected (0.99 sec)
mysql> desc t11;
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.01 sec)
那我再添加一個名字的字段(自己用指令添加)
那既然是自增長的 也就意味着我可以不用傳id值,他會自動幫我處理
mysql> insert into t11(name) values('ponny'),('Tom');
Query OK, 2 rows affected (0.39 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t11;
+----+-------+
| id | name |
+----+-------+
| 1 | ponny |
| 2 | Tom |
+----+-------+
2 rows in set (0.00 sec)
和我們想要的效果是一樣的~達到了自己添加,id自動增長,從1開始,每次增長1個
id可以不寫,那我要是非要寫呢?可不可以添加成功呢?
mysql> insert into t11(id,name) values(5,"Jerry");
Query OK, 1 row affected (0.40 sec)
mysql> select * from t11;
+----+-------+
| id | name |
+----+-------+
| 1 | ponny |
| 2 | Tom |
| 5 | Jerry |
+----+-------+
3 rows in set (0.00 sec)
是可以添加成功的,那么我接下來再自增會出現什么情況呢?
mysql> insert into t11(name) values('ponny'),('Tom');
Query OK, 2 rows affected (0.38 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t11;
+----+-------+
| id | name |
+----+-------+
| 1 | ponny |
| 2 | Tom |
| 5 | Jerry |
| 6 | ponny |
| 7 | Tom |
+----+-------+
5 rows in set (0.00 sec)
你會發現他不是在斷的地方進行自增,而是以最后一組記錄的id來進行的自增
還有個問題,我能不能指定他的起始,指定他一次增多少呢?
你別說,MySQL還真的提供了這個方法,我們可以先看一下他的默認設置
show variables like 'auto_inc%'
其中like就是模糊匹配,現在不說,這個%的意思是我要的是auto_inc開頭的
當然,如果你能把increment全部拼出來,就不需要這個%了
mysql> show variables like 'auto_inc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
+--------------------------+-------+
2 rows in set (0.00 sec)
可以看到兩條設置 increment:步長;offset:起始位置
可以看到后面都是1,代表着,從1增加,每次增加1
那既然能拿到,就能夠設置,在設置上也有兩種操作
分別是:set session 和 set global
set session 只對當次有效
set global 一直有效
設置步長:set global auto_increment_increment=5;
設置起始位置這就有說法了!
起始位置其實叫做起始偏移量,就相當於我已經走出去一步了,所以不應該超過步長才對
但是可以小於等於步長,也就意味着,如果設置超過了,起始位置就無效了
設置起始:set global auto_increment_offset=3;
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_inc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
+--------------------------+-------+
2 rows in set (0.00 sec)
設置之后你發現,誒?怎么沒變呢??原因是我們應該更新一下,就是退了重進
當我重進一下就變成了:
mysql> show variables like 'auto_inc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 5 |
| auto_increment_offset | 3 |
+--------------------------+-------+
2 rows in set (0.00 sec)
那我們試一下:
mysql> insert into t11(name) values("da"),("daw");
Query OK, 2 rows affected (0.07 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t11;
+----+-------+
| id | name |
+----+-------+
| 1 | ponny |
| 2 | Tom |
| 5 | Jerry |
| 6 | ponny |
| 7 | Tom |
| 8 | da |
| 13 | daw |
+----+-------+
7 rows in set (0.00 sec)
看,是不是從8直接到13了~
這里有一個現象:
mysql> delete from t11;
Query OK, 7 rows affected (0.48 sec)
mysql> select * from t11;
Empty set (0.00 sec)
mysql> insert into t11(name) values('sa'),('de');
Query OK, 2 rows affected (0.38 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t11;
+----+------+
| id | name |
+----+------+
| 18 | sa |
| 23 | de |
+----+------+
2 rows in set (0.00 sec)
你會發現,即使刪掉了,他還是會繼續自增,這不是我們想要的效果
這個時候你說啊~我自己個給id也行,是也行,但是我們還是沒有解決刪干凈這個問題
所以新的命令就出現了truncate t11;
mysql> truncate t11;
Query OK, 0 rows affected (0.54 sec)
mysql> insert into t11(name) values('sa'),('de');
Query OK, 2 rows affected (0.07 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t11;
+----+------+
| id | name |
+----+------+
| 3 | sa |
| 8 | de |
+----+------+
2 rows in set (0.00 sec)
這是不是才是真正的達到了我們的要求啊~
通過這個例子我們可以看出,刪表不建議delete,而應該使用truncate
delete的使用往往是跟着where連用的~
foreign key
在實際操作中,並不是只有一個表的,比如一個公司
員工要在各個部門上班,各個部門又有各個部門的信息
那講道理你不能把員工信息和部門信息放在一張表里吧
姓名 | 部門 | 部門負責人 | 部門電話 | ... |
---|---|---|---|---|
Tom | 研發 | Alisa | 135XXXXXXXX | ... |
Jerry | 產品 | John | 173XXXXXXXX | ... |
Jevious | 產品 | John | 173XXXXXXXX | ... |
Ponny | 研發 | Alisa | 135XXXXXXXX | ... |
Daddy | 事務 | Kin | 186XXXXXXXX | ... |
就可以看出來,同一張表格里相同信息多不多?多!
而且還有問題,部門負責人永遠都是XXX?不會換人?要是換人,這些數據都要改
而且 XXX一直都在XXX部門?也不一定吧,要是部門一改,那后面所有都要改
要是照這種表結構,這就十分的麻煩~我們可以怎么做呢?我們可以把表拆開
姓名 | ... |
---|---|
Tom | ... |
Jerry | ... |
Jevious | ... |
Ponny | ... |
Daddy | ... |
部門 | 部門負責人 | 部門電話 | ... |
---|---|---|---|
研發 | Alisa | 135XXXXXXXX | ... |
產品 | John | 173XXXXXXXX | ... |
事務 | Kin | 186XXXXXXXX | ... |
上面提出的問題就已經完美解決了,但是這兩個表格聯系上了嗎?很明顯沒有,而且員工確實應該有部門
那我們表格就可以這么設置:
姓名 | 部門ID | ... |
---|---|---|
Tom | 1 | ... |
Jerry | 2 | ... |
Jevious | 2 | ... |
Ponny | 1 | ... |
Daddy | 3 | ... |
部門ID | 部門 | 部門負責人 | 部門電話 | ... |
---|---|---|---|---|
1 | 研發 | Alisa | 135XXXXXXXX | ... |
2 | 產品 | John | 173XXXXXXXX | ... |
3 | 事務 | Kin | 186XXXXXXXX | ... |
這樣是不是就通過部門id 讓兩個表有了聯系
但是同理也出來了,如果還有個擴展表格,比如部門負責人信息,也像部門這樣分離出來
id取得也是1 2 3 ,那員工表里面的部門id的1 2 3指的是部門表還是部門信息表?
是不是沒有硬性規定說我的這個部門id就是來自於部門這個表
所以我們需要給他個硬性規定,foreign key 外鍵就出現了
create table staff(
id int primary key,
name char(10),
department_id int,
foreign key (department_id) references department(id)
);
但是你要是綁定的前提是不是得有這張表啊:
create table department(
id int primary key,
name char(5),
leader char(10),
tel char(11)
);
mysql> create table department(
-> id int primary key,
-> name char(5),
-> leader char(10),
-> tel char(11)
-> );
Query OK, 0 rows affected (0.74 sec)
mysql> create table staff(
-> id int primary key,
-> name char(10),
-> department_id int,
-> foreign key (department_id) references department(id)
-> );
Query OK, 0 rows affected (0.52 sec)
mysql> show tables;
+-------------+
| Tables_in_t |
+-------------+
| department |
| staff |
+-------------+
2 rows in set (0.05 sec)
表建好了,就是寫入記錄,其實還是一樣,要先寫被關聯的表
你想啊,你不先寫被關聯的表,你關聯誰啊?,所以我們先對被關聯的表進行賦值
insert into department values
(1,'研發','Alisa','135XXXXXXXX'),
(2,'產品','John','173XXXXXXXX'),
(3,'事務','Kin','186XXXXXXXX');
mysql> insert into department values
->
-> (1,'研發','Alisa','135XXXXXXXX'),
->
-> (2,'產品','John','173XXXXXXXX'),
->
-> (3,'事務','Kin','186XXXXXXXX')
-> ;
Query OK, 3 rows affected (0.23 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from department;
+----+--------+--------+-------------+
| id | name | leader | tel |
+----+--------+--------+-------------+
| 1 | 研發 | Alisa | 135XXXXXXXX |
| 2 | 產品 | John | 173XXXXXXXX |
| 3 | 事務 | Kin | 186XXXXXXXX |
+----+--------+--------+-------------+
3 rows in set (0.01 sec)
建立主表
insert into staff values
(1,'Tom',1),
(2,'Jerry',2),
(3,'Jevious',2),
(4,'Ponny',1),
(5,'Daddy',3);
mysql> insert into staff values
->
-> (1,'Tom',1),
->
-> (2,'Jerry',2),
->
-> (3,'Jevious',2),
->
-> (4,'Ponny',1),
->
-> (5,'Daddy',3);
Query OK, 5 rows affected (0.41 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from staff;
+----+---------+---------------+
| id | name | department_id |
+----+---------+---------------+
| 1 | Tom | 1 |
| 2 | Jerry | 2 |
| 3 | Jevious | 2 |
| 4 | Ponny | 1 |
| 5 | Daddy | 3 |
+----+---------+---------------+
5 rows in set (0.00 sec)
代碼都是根據需求來的,假設有一天,事務部解散了,數據要怎么辦呢?
很明顯要先刪掉員工表里department_id=3的,而不應該先去刪department這個表
因為先刪department,就會讓staff表里的關聯到事務的記錄的最后一項變得沒有意義
(這部分的描述要是不理解可以自己實際操作,刪掉 事務 部門)
那,我這要想解散一個部門還要多表聯動?這是兩個表,這表要是多點,也就牽一發動全身
所以有沒有什么好辦法,能讓解散變得簡單點呢?我刪掉部門,和這個關聯的都刪掉
實際上,在外鍵的設定上還有幾個參數沒介紹:
on delete cascade
刪除同步
on update cascade
更新同步
那我們重新建立:
create table staff(
id int primary key,
name char(10),
department_id int,
foreign key (department_id) references department(id) on delete cascade on update cascade
);
其他的都跟上面一樣,那我們來試試可不可以直接刪部門!
mysql> delete from department where id = 3;
Query OK, 1 row affected (0.41 sec)
mysql> select * from staff;
+----+---------+---------------+
| id | name | department_id |
+----+---------+---------------+
| 1 | Tom | 1 |
| 2 | Jerry | 2 |
| 3 | Jevious | 2 |
| 4 | Ponny | 1 |
+----+---------+---------------+
4 rows in set (0.00 sec)
mysql> select * from department;
+----+--------+--------+-------------+
| id | name | leader | tel |
+----+--------+--------+-------------+
| 1 | 研發 | Alisa | 135XXXXXXXX |
| 2 | 產品 | John | 173XXXXXXXX |
+----+--------+--------+-------------+
2 rows in set (0.00 sec)
這是不是我們想要的效果完美
那我們再試試修改:
mysql> update department set id=3 where id = 2;
Query OK, 1 row affected (0.43 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from department;
+----+--------+--------+-------------+
| id | name | leader | tel |
+----+--------+--------+-------------+
| 1 | 研發 | Alisa | 135XXXXXXXX |
| 3 | 產品 | John | 173XXXXXXXX |
+----+--------+--------+-------------+
2 rows in set (0.00 sec)
mysql> select * from staff;
+----+---------+---------------+
| id | name | department_id |
+----+---------+---------------+
| 1 | Tom | 1 |
| 2 | Jerry | 3 |
| 3 | Jevious | 3 |
| 4 | Ponny | 1 |
+----+---------+---------------+
4 rows in set (0.00 sec)
當我將部門的編號修改之后,看,原關聯表也進行了修改!這就是最完美的關聯!
但是!!!!
!!!!!!
不推薦使用外鍵!
為什么?因為這么寫無異於將兩個表耦合在一起了,對於擴展來說是十分不友好的
我們應該做的,是讓兩個表的邏輯相關聯,通過代碼邏輯讓其產生聯系,而讓每個表都是獨立的個體
所以不建議這樣做出硬性關聯!