一 : 外鍵操作
外鍵: foreign key
, 外面的鍵(鍵不在自己表中): 如果一張表中有一個(gè)字段(非主鍵)指向另外一張表的主鍵,那么將該字段稱之為外鍵.
① : 增加外鍵
外鍵可以在創(chuàng)建表的時(shí)候或者創(chuàng)建表之后增加(但是要考慮數(shù)據(jù)的問(wèn)題).
(1) : 在創(chuàng)建表的時(shí)候創(chuàng)建外鍵
一張表可以有多個(gè)外鍵
創(chuàng)建表的時(shí)候增加外鍵: 在所有的表字段之后,使用foreign key
(外鍵字段) references
外部表(主鍵字段)
創(chuàng)建語(yǔ)句
create table my_foreign1(
id int primary key auto_increment,
name varchar(20) not null comment '學(xué)生姓名',
c_id int comment '班級(jí)id', -- 普通字段
-- 增加外鍵
foreign key(c_id) references my_class(id)
)charset utf8;
表結(jié)構(gòu)
外鍵 : 要求字段本身必須先是一個(gè)索引(普通索引),如果字段本身沒(méi)有索引,外鍵會(huì)先創(chuàng)建一個(gè)索引,然后才會(huì)創(chuàng)建外鍵本身
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| c_id | int(11) | YES | MUL | NULL | |
+-------+-------------+------+-----+---------+----------------+
查看創(chuàng)建語(yǔ)句
show create table my_foreign1
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| my_foreign1 | CREATE TABLE `my_foreign1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL COMMENT '學(xué)生姓名',
`c_id` int(11) DEFAULT NULL COMMENT '班級(jí)id',
PRIMARY KEY (`id`),
KEY `c_id` (`c_id`),
CONSTRAINT `my_foreign1_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `my_class` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------------+----------------------------------------------------------------------
其中如果本身字段沒(méi)有索引,外鍵創(chuàng)建索引 -> KEY 'c_id' ('c_id')
my_foreign1_ibfk_1
為外鍵的名字
( 2 ) : 在新增表之后增加外鍵,修改表結(jié)構(gòu)
Alter table 表名 add [constraint 外鍵名字] foreign key(外鍵字段) references 父表(主鍵字段);
創(chuàng)建一個(gè)表
create table my_foreign2(
id int primary key auto_increment,
name varchar(20) not null comment '學(xué)生姓名',
c_id int comment '班級(jí)id' -- 普通字段
)charset utf8;
增加外鍵
-- 增加外鍵
alter table my_foreign2 add
-- 指定外鍵名
constraint student_class_1
-- 指定外鍵字段
foreign key(c_id)
-- 引用父表主鍵
references my_class(id);
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| c_id | int(11) | YES | MUL | NULL | |
+-------+-------------+------+-----+---------+----------------+
② : 修改與刪除外鍵
外鍵不可修改: 只能先刪除后新增.
Alter table 表名 drop foreign key 外鍵名; -- 一張表中可以有多個(gè)外鍵,但是名字不能相同
注 :
外鍵刪除不能通過(guò)查看表結(jié)構(gòu)體現(xiàn),應(yīng)該通過(guò)查看表創(chuàng)建語(yǔ)句查看.
alter table my_foreign1 drop foreign key my_foreign1_ibfk_1;
+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| my_foreign1 | CREATE TABLE `my_foreign1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL COMMENT '學(xué)生姓名',
`c_id` int(11) DEFAULT NULL COMMENT '班級(jí)id',
PRIMARY KEY (`id`),
KEY `c_id` (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------------+-------------------------------------
二 : 外鍵的作用
外鍵默認(rèn)的作用有兩點(diǎn) :
① 對(duì)于子表約束 :
子表數(shù)據(jù)進(jìn)行寫(xiě)操作(增和改)的時(shí)候, 如果對(duì)應(yīng)的外鍵字段在父表找不到對(duì)應(yīng)的匹配: 那么操作會(huì)失敗.(約束子表數(shù)據(jù)操作)
insert into my_foreign2 values(null,'思思',4); -- 沒(méi)有4班級(jí)
insert into my_foreign2 values(null,'可可',1);
insert into my_foreign2 values(null,'娜娜',2);
insert into my_foreign2 values(null,'雪芙',2);
結(jié)果
父表中沒(méi)有4班,所以插入不成功
+----+--------+------+
| id | name | c_id |
+----+--------+------+
| 2 | 可可 | 1 |
| 3 | 娜娜 | 2 |
| 4 | 雪芙 | 2 |
+----+--------+------+
② 對(duì)于父表約束 :
對(duì)父表約束: 父表數(shù)據(jù)進(jìn)行寫(xiě)操作(刪和改: 都必須涉及到主鍵本身), 如果對(duì)應(yīng)的主鍵在子表中已經(jīng)被數(shù)據(jù)所引用, 那么就不允許操作
update my_class set id = 4 where id = 1; -- 失敗: id=1記錄已經(jīng)被學(xué)生引用
update my_class set id = 4 where id = 3; -- 可以: 沒(méi)有引用
查看結(jié)果
+----+---------+------+
| id | name | room |
+----+---------+------+
| 1 | PHP0710 | A203 |
| 2 | PHP0810 | B205 |
| 4 | PHP0910 | C206 |
三 : 外鍵條件
① : 外鍵要存在 : 首先必須保證表的存儲(chǔ)引擎是innodb(默認(rèn)的存儲(chǔ)引擎),如果不是innodb存儲(chǔ)引擎,那么外鍵可以創(chuàng)建成功,但是沒(méi)有約束效果.
② : 外鍵字段的字段類型(列類型)必須與父表的主鍵類型完全一致
③ : 一張表中的外鍵名字不能重復(fù).
④ : 增加外鍵的字段(數(shù)據(jù)已經(jīng)存在),必須保證與父表主鍵要求對(duì)應(yīng)
新增加的外鍵的字段 3
在父表中不存在,無(wú)法建立連接
insert into my_foreign1 values(null,'雨晴',3);
my_class表
+----+---------+------+
| id | name | room |
+----+---------+------+
| 1 | PHP0710 | A203 |
| 2 | PHP0810 | B205 |
| 4 | PHP0910 | C206 |
+----+---------+------+
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`web13`.`#sql-66_90`, CONSTRAINT `#sql-66_90_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `my_class` (`id`))
四 : 外鍵約束
所謂外鍵約束: 就是指外鍵的作用.
上述外鍵的作用是默認(rèn)的,其實(shí)可以通過(guò)對(duì)外鍵的需求,進(jìn)行定制操作
三種約束模式 : 都是針對(duì)父表的約束
① : District 嚴(yán)格模式(默認(rèn)的),父表不能刪除或者更新一個(gè)已經(jīng)被子表數(shù)據(jù)引用的記錄.
② : Cascade 級(jí)聯(lián)模式: 父表的操作, 對(duì)應(yīng)子表關(guān)聯(lián)的數(shù)據(jù)也跟著被刪除
③ : Set null 置空模式: 父表的操作之后,子表對(duì)應(yīng)的數(shù)據(jù)(外鍵字段)被置空
通常的一個(gè)合理的做法(約束模式): 刪除的時(shí)候子表置空, 更新的時(shí)候子表級(jí)聯(lián)操作
-- 創(chuàng)建外鍵: 指定模式: 刪除置空,更新級(jí)聯(lián)
create table my_foreign3(
id int primary key auto_increment,
name varchar(20) not null,
c_id int,
-- 增加外鍵
foreign key(c_id)
-- 引用表
references my_class(id)
-- 指定刪除模式
on delete set null
-- 指定更新默認(rèn)
on update cascade)charset utf8;
show create table my_foreign3;
+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| my_foreign3 | CREATE TABLE `my_foreign3` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`c_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c_id` (`c_id`),
CONSTRAINT `my_foreign3_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `my_class` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------------+------------------------------------------
更新操作 : 級(jí)聯(lián)更新
+----+--------+------+
| id | name | c_id |
+----+--------+------+
| 1 | 思思 | 1 |
| 2 | 美美 | 1 |
| 3 | 晴晴 | 1 |
| 4 | 欣欣 | 2 |
| 5 | 娜娜 | 2 |
+----+--------+------+
+----+---------+------+
| id | name | room |
+----+---------+------+
| 1 | PHP0710 | A203 |
| 2 | PHP0810 | B205 |
| 4 | PHP0910 | C206 |
+----+---------+------+
更新父表主鍵
update my_class set id = 3 where id = 1;
再次查看變化
+----+--------+------+
| id | name | c_id |
+----+--------+------+
| 1 | 思思 | 3 |
| 2 | 美美 | 3 |
| 3 | 晴晴 | 3 |
| 4 | 欣欣 | 2 |
| 5 | 娜娜 | 2 |
+----+--------+------+
刪除操作 : 置空
刪除父表的主鍵
delete from my_class where id = 2;
查看字表的變化
+----+--------+------+
| id | name | c_id |
+----+--------+------+
| 1 | 思思 | 3 |
| 2 | 美美 | 3 |
| 3 | 晴晴 | 3 |
| 4 | 欣欣 | NULL |
| 5 | 娜娜 | NULL |
+----+--------+------+
刪除置空的前提條件: 外鍵字段允許為空(如果不滿足條件,外鍵無(wú)法創(chuàng)建)
五 : 聯(lián)合查詢
聯(lián)合查詢 : 將多次查詢(多條語(yǔ)句)在記錄上進(jìn)行拼接(字段不會(huì)增加)
Select 語(yǔ)句1
Union [union選項(xiàng)]
Select語(yǔ)句2...
Union選項(xiàng): 與select選項(xiàng)一樣有兩個(gè)
All: 保留所有(不管重復(fù))
Distinct: 去重(整個(gè)重復(fù)): 默認(rèn)的
默認(rèn)去重
-- 聯(lián)合查詢
select * from my_class
union -- 默認(rèn)去重
select * from my_class;
結(jié)果
+----+---------+------+
| id | name | room |
+----+---------+------+
| 3 | PHP0710 | A203 |
| 4 | PHP0910 | C206 |
+----+---------+------+
不去重
select * from my_class
union all -- 不去重
select * from my_class;
結(jié)果
+----+---------+------+
| id | name | room |
+----+---------+------+
| 3 | PHP0710 | A203 |
| 4 | PHP0910 | C206 |
| 3 | PHP0710 | A203 |
| 4 | PHP0910 | C206 |
聯(lián)合查詢只要求字段數(shù)一樣,跟數(shù)據(jù)類型無(wú)關(guān)
select id,c_name,room from my_class
union all -- 不去重
select name,number,id from my_student;
+--------+-----------+------+
| id | name | room |
+--------+-----------+------+
| 3 | PHP0710 | A203 |
| 4 | PHP0910 | C206 |
| 思思 | class0001 | 1 |
| 可可 | class0002 | 2 |
| 娜娜 | class0003 | 3 |
| 美美 | class0004 | 4 |
| 彩彩 | class0005 | 5 |
| 琪琪 | class0006 | 6 |
| 琪琪 | class0006 | 7 |
| 琪琪 | class0006 | 8 |
+--------+-----------+------+
聯(lián)合查詢的意義
- 1.?查詢同一張表,但是需求不同: 如查詢學(xué)生信息, 男生身高升序, 女生身高降序.
- 2.?多表查詢: 多張表的結(jié)構(gòu)是完全一樣的,保存的數(shù)據(jù)(結(jié)構(gòu))也是一樣的.
多表查詢?cè)黾有?可以給十萬(wàn)量級(jí)的表進(jìn)行分表,成萬(wàn)級(jí)別,再分表成千級(jí)別,進(jìn)行聯(lián)合查詢,增加效率.
聯(lián)合查詢中 Order by使用
需求 : 要求男生升序,女生降序
注意 1 : 在聯(lián)合查詢中 : order by 不能直接使用,需要對(duì)查詢語(yǔ)句使用括號(hào)才行
注意2 : 若要orderby生效: 必須搭配limit: limit使用限定的最大數(shù)即可.
(select * from my_student where sex = '男' order by age asc limit 9999999)
union
(select * from my_student where sex = '女' order by age desc limit 9999999);
+----+-----------+--------+------+--------+------+------+
| id | number | name | sex | height | c_id | age |
+----+-----------+--------+------+--------+------+------+
| 5 | class0005 | 彩彩 | 男 | 166 | 3 | 7 |
| 2 | class0002 | 可可 | 男 | 182 | 1 | 10 |
| 1 | class0001 | 思思 | 男 | 184 | 3 | 16 |
| 4 | class0004 | 美美 | 男 | 172 | 3 | 18 |
| 7 | class0006 | 琪琪 | 女 | 168 | 2 | 24 |
| 3 | class0003 | 娜娜 | 女 | 156 | 1 | 19 |
| 6 | class0006 | 琪琪 | 女 | 168 | 2 | 19 |
| 8 | class0006 | 琪琪 | 女 | 168 | 2 | 16 |
+----+-----------+--------+------+--------+------+------+
六 : 子查詢
子查詢 : sub query
,查詢是在某個(gè)查詢結(jié)果之上進(jìn)行的.(一條select語(yǔ)句內(nèi)部包含了另外一條select語(yǔ)句).
子查詢有兩種分類方式: 按位置分類; 按結(jié)果分類
按位置分類: 子查詢(select語(yǔ)句)在外部查詢(select語(yǔ)句)中出現(xiàn)的位置
- From子查詢: 子查詢跟在from之后
- Where子查詢: 子查詢出現(xiàn)where條件中
- Exists子查詢: 子查詢出現(xiàn)在exists里面
按結(jié)果分類: 根據(jù)子查詢得到的數(shù)據(jù)進(jìn)行分類(理論上講任何一個(gè)查詢得到的結(jié)果都可以理解為二維表)
- 標(biāo)量子查詢: 子查詢得到的結(jié)果是一行一列
- 列子查詢: 子查詢得到的結(jié)果是一列多行
- 行子查詢: 子查詢得到的結(jié)果是多列一行(多行多列)
上面幾個(gè)出現(xiàn)的位置都是在where之后
表子查詢: 子查詢得到的結(jié)果是多行多列(出現(xiàn)的位置是在from之后)
① : 標(biāo)量子查詢
需求: 知道班級(jí)名字為PHP0710,想獲取該班的所有學(xué)生.
1. 確定數(shù)據(jù)源: 獲取所有的學(xué)生
Select * from my_student where c_id = ?;
2. 獲取班級(jí)ID: 可以通過(guò)班級(jí)名字確定
Select id from my_class where c_name = ‘PHP0710’;
select * from my_student where c_id = (select id from my_class where name = 'PHP0710');
或者
select * from my_student having c_id = (select id from my_class where c_name = 'PHP0710');
+----+-----------+--------+------+--------+------+------+
| id | number | name | sex | height | c_id | age |
+----+-----------+--------+------+--------+------+------+
| 1 | class0001 | 思思 | 男 | 184 | 3 | 16 |
| 4 | class0004 | 美美 | 男 | 172 | 3 | 18 |
| 5 | class0005 | 彩彩 | 男 | 166 | 3 | 7 |
+----+-----------+--------+------+--------+------+------+
② : 列子查詢
需求: 查詢所有在讀班級(jí)的學(xué)生(班級(jí)表中存在的班級(jí))
1. 確定數(shù)據(jù)源: 學(xué)生
Select * from my_student where c_id in (?);
2. 確定有效班級(jí)的id: 所有班級(jí)id
Select id from my_class;
select * from my_student where c_id in(select id from my_class);
+----+-----------+--------+------+--------+------+------+
| id | number | name | sex | height | c_id | age |
+----+-----------+--------+------+--------+------+------+
| 1 | class0001 | 思思 | 男 | 184 | 3 | 16 |
| 4 | class0004 | 美美 | 男 | 172 | 3 | 18 |
| 5 | class0005 | 彩彩 | 男 | 166 | 3 | 7 |
+----+-----------+--------+------+--------+------+------+
在mysql中有還有幾個(gè)與in
類似的條件: all, some, any
- =Any ==== in; -- 其中一個(gè)即可
- Any ====== some;?-- any跟some是一樣
- =all ==== 為全部
select * from my_student where c_id =any(select id from my_class);
mysql> select * from my_student where c_id =some(select id from my_class);
結(jié)果
+----+-----------+--------+------+--------+------+------+
| id | number | name | sex | height | c_id | age |
+----+-----------+--------+------+--------+------+------+
| 1 | class0001 | 思思 | 男 | 184 | 3 | 16 |
| 4 | class0004 | 美美 | 男 | 172 | 3 | 18 |
| 5 | class0005 | 彩彩 | 男 | 166 | 3 | 7 |
+----+-----------+--------+------+--------+------+------+
select * from my_student where c_id =all(select id from my_class);
結(jié)果
Empty set (0.00 sec)
否定結(jié)果
!=any 與 !=some
c_id不等于 任意一個(gè)就成立,!=all
全都不等于才成立
select * from my_student where c_id !=any(select id from my_class); -- 所有結(jié)果(null除外)
select * from my_student where c_id !=some(select id from my_class); -- 所有結(jié)果(null除外)
select * from my_student where c_id !=all(select id from my_class); -- 2(null除外)
③ : 行子查詢
行子查詢: 返回的結(jié)果可以是多行多列(一行多列)
需求: 要求查詢整個(gè)學(xué)生中,年齡最大且身高是最高的學(xué)生.
1. 確定數(shù)據(jù)源
Select * from my_student where age = ? And height = ?;
2. 確定最大的年齡和最高的身高;
Select max(age),max(height) from my_student;
select * from my_student where
-- (age,height)稱之為行元素
(age,height) = (select max(age),max(height) from my_student);
④ : 表子查詢
表子查詢: 子查詢返回的結(jié)果是多行多列的二維表: 子查詢返回的結(jié)果是當(dāng)做二維表來(lái)使用
需求: 找出每一個(gè)班最高的一個(gè)學(xué)生.
1. 確定數(shù)據(jù)源: 先將學(xué)生按照身高進(jìn)行降序排序
Select * from my_student order by height desc;
2. 從每個(gè)班選出第一個(gè)學(xué)生
Select * from my_student group by c_id; -- 每個(gè)班選出第一個(gè)學(xué)生
select * from (select * from my_student order by height desc) as student group by c_id;
⑤Exists子查詢
Exists: 是否存在的意思, exists子查詢就是用來(lái)判斷某些條件是否滿足(跨表), exists是接在where之后: exists返回的結(jié)果只有0和1.
需求: 查詢所有的學(xué)生: 前提條件是班級(jí)存在
- 確定數(shù)據(jù)源
Select * from my_student where ?; - 確定條件是否滿足
Exists(Select * from my_class); -- 是否成立
select * from my_student where
exists(select * from my_class where id = 1);