內容概要
- 外鍵
- 表與表之間關系
- 一對多
- 多對多
- 一對一
- 沒有關系
- 操作表的SQL語句(ALTER)
- SQL 查詢關鍵字
- 查詢語句之 where
- 查詢語句之分組 group by
- 分組后篩選 having
- 去重 distinct
- 排序 order by
- 限制查詢數據條數 limit
- 正則查詢 regexp
- 聚合函數函數 max min sum avg count
- 連接字段 concat
內容詳細
外鍵
什么是外鍵?
用於建立表與表之間聯系的字段,也是一種約束條件,
在 SQL 語句中,建立外鍵的關鍵字是 :
foreign key(本表字段名) references 被關聯的表名(id)
foreign key(dep_id) references dep(id)
為什么要有外鍵?
假設有這樣一張員工信息數據表:
![image-20220221151359232]
上面這張表有以下缺陷:
- 1、表的重點不突出,到底是員工表還是部門表
- 2、表中部門和部門信息兩個字段的數據很多在重復
- 3、表的拓展性極差,只要教學部改一個名字,整張表都要跟着改掉,牽一發而動全身
如何建立外鍵?
解決以上表的缺陷:
將上述一張表拆分成兩張表,然后通過給一個表添加一個外鍵字段,將兩張表聯系起來

外鍵字段>>>:部門編號
其實就是用來標識表與表之間的數據關系
簡單的理解為該字段可以讓你去到其他表中查找數據
表與表之間關系
表關系總共就四種:
一對多、多對多、一對一、沒有關系
判斷表關系的方式:換位思考
補充:級聯更新,級聯刪除,也就是兩表之間的數據改動可以進行同步
on update cascade # 級聯更新
on delete cascade, # 級聯刪除
1.一對多
以員工和部門表為例
先站在員工表的基礎之上
問:一個員工信息能否對應多個部門信息
答:不可以
再站在部門表的基礎之上
問:一個部門信息能否對應多個員工信息
答:可以
結論:一個可以一個不可以 那么表關系就是"一對多"
員工表是多 部門表是一
"""
針對一對多的表關系 外鍵字段建在多的一方
"""
# 表關系沒有'多對一'一說 都是'一對多'
使用SQL語句建立真正意義上的表關系:
注意:先創建不含外鍵字段的基本表,再添加外鍵字段
# 先創建被關聯的表 部門表
create table dep(
id int primary key auto_increment,
dep_name varchar(32),
dep_desc varchar(254)
);
# 再創建含有外鍵的表 員工信息表
create table emp(
id int primary key auto_increment,
name varchar(32),
age int,
dep_id int,
foreign key(dep_id) references dep(id)
);
2.多對多關系
注意:多對多關系的表需要建立第三個表來存放兩表之間的對應關系
以書籍表與作者表為例
先站在書籍表的基礎之上
問:一個書籍信息能否對應多個作者信息
答:可以
再站在作者表的基礎之上
問:一個作者信息能否對應多個書籍信息
答:可以
結論:兩個都可以 那么表關系就是"多對多"
# 多對多表關系 需要單獨開設第三張表存儲(並且第三張表可以不綁定)
# 先創建兩張多對多關系的表
create table book(
id int primary key auto_increment,
title varchar(32),
price float(6,2)
);
create table author(
id int primary key auto_increment,
name varchar(32),
age int
);
# 創建第三張表存放兩表之間的對應關系
create table book2author(
id int primary key auto_increment,
author_id int,
book_id int,
foreign key(author_id) references author(id)
on update cascade # 級聯更新
on delete cascade, # 級聯刪除
foreign key(book_id) references book(id)
on update cascade # 級聯更新
on delete cascade # 級聯刪除
);
3.一對一表關系
一對一與一對多的區別是,一對一外鍵字段必須唯一
作者表與作者詳情表
先站在作者表的基礎之上
問:一個作者信息能否對應多個作者詳情信息
答:不可以
再站在作者詳情表的基礎之上
問:一個作者詳情信息能否對應多個作者信息
答:不可以
結論:兩個都不可以
那么表關系可能是"一對一"或者"沒有關系"
# 外鍵字段建在任何一方都可以 但是推薦建在查詢頻率較高的表中
SQL 語句創建:
# 表一
create table author(
id int primary key auto_increment,
name varchar(32),
age int,
author_id int unique, # 一對一與一對多的區別是,一對一外鍵字段必須唯一
foreign key(author_id) references author_detail(id)
on update cascade # 級聯更新
on delete cascade # 級聯刪除
);
# 表二
create table author_detail(
id int primary key auto_increment,
phone varchar(32),
address varchar(32)
);
**補充: **
1.在創建表的時候 需要先創建被關聯表(沒有外鍵字段的表)
2.在插入新數據的時候 應該先確保被關聯表中有數據
3.在插入新數據的時候 外鍵字段只能填寫被關聯表中已經存在的數據
4.在修改和刪除被關聯表中的數據的時候 無法直接操作
如果想要數據之間自動修改和刪除需要添加額外的配置
由於外鍵有實質性的諸多約束 當表特別多的時候外鍵的增多反而會增加耦合程度
所以在實際開發項目中 有時候並不會使用外鍵創建表關系
而是通過SQL語句層面 建立邏輯意義上的表關系
eg:操作員工表的sql執行完畢之后 立刻跟着執行操作部門的sql
操作表的SQL語句(ALTER)
show tables;
desc 表名;
create table t1(id int);
alter table t1 change id nid int;
drop table t1;
語法:
1. 修改表名
ALTER TABLE 表名
RENAME 新表名;
2. 增加字段
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…],
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…] FIRST;
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…] AFTER 字段名;
3. 刪除字段
ALTER TABLE 表名
DROP 字段名;
4. 修改字段 # modify只能改字段數據類型完整約束,不能改字段名,但是change可以!
ALTER TABLE 表名
MODIFY 字段名 數據類型 [完整性約束條件…];
ALTER TABLE 表名
CHANGE 舊字段名 新字段名 舊數據類型 [完整性約束條件…];
SQL 查詢關鍵字
數據准備:
# 數據准備
create table emp(
id int primary key auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一個部門一個屋子
depart_id int
);
#插入記錄
#三個部門:教學,銷售,運營
insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
('jason','male',18,'20170301','張江第一帥形象代言',7300.33,401,1), #以下是教學部
('tom','male',78,'20150302','teacher',1000000.31,401,1),
('kevin','male',81,'20130305','teacher',8300,401,1),
('tony','male',73,'20140701','teacher',3500,401,1),
('owen','male',28,'20121101','teacher',2100,401,1),
('jack','female',18,'20110211','teacher',9000,401,1),
('jenny','male',18,'19000301','teacher',30000,401,1),
('sank','male',48,'20101111','teacher',10000,401,1),
('哈哈','female',48,'20150311','sale',3000.13,402,2),#以下是銷售部門
('呵呵','female',38,'20101101','sale',2000.35,402,2),
('西西','female',18,'20110312','sale',1000.37,402,2),
('樂樂','female',18,'20160513','sale',3000.29,402,2),
('拉拉','female',28,'20170127','sale',4000.33,402,2),
('僧龍','male',28,'20160311','operation',10000.13,403,3), #以下是運營部門
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬銀','female',18,'20130311','operation',19000,403,3),
('程咬銅','male',18,'20150411','operation',18000,403,3),
('程咬鐵','female',18,'20140512','operation',17000,403,3);
查詢關鍵字之select與from
from控制的是查詢哪張表
select控制的是查詢表里面的哪些字段
select * from emp;
select id,name from emp;
查詢關鍵字之where篩選
where篩選功能
"""
模糊查詢:沒有明確的篩選條件
關鍵字:like
關鍵符號:
%:匹配任意個數任意字符
_:匹配單個個數任意字符
show variables like '%mode%se';
"""
# 1.查詢id大於等於3小於等於6的數據
select id,name from emp where id >= 3 and id <= 6;
select * from emp where id between 3 and 6;
# 2.查詢薪資是20000或者18000或者17000的數據
select * from emp where salary = 20000 or salary = 18000 or salary = 17000;
select * from emp where salary in (20000,18000,17000); # 簡寫
# 3.查詢員工姓名中包含o字母的員工姓名和薪資
# 在你剛開始接觸mysql查詢的時候,建議你按照查詢的優先級順序拼寫出你的sql語句
"""
先是查哪張表 from emp
再是根據什么條件去查 where name like ‘%o%’
再是對查詢出來的數據篩選展示部分 select name,salary
"""
select name,salary from emp where name like '%o%';
# 4.查詢員工姓名是由四個字符組成的員工姓名與其薪資
select name,salary from emp where name like '____';
select name,salary from emp where char_length(name) = 4;
# 5.查詢id小於3或者大於6的數據
select * from emp where id not between 3 and 6;
# 6.查詢薪資不在20000,18000,17000范圍的數據
select * from emp where salary not in (20000,18000,17000);
# 7.查詢崗位描述為空的員工名與崗位名 針對null不能用等號,只能用is
select name,post from emp where post_comment = NULL; # 查詢為空!
select name,post from emp where post_comment is NULL;
select name,post from emp where post_comment is not NULL;
聚合函數
聚合函數主要就是配合分組一起使用
max min sum count avg
查詢關鍵字之group by分組
有些查詢條件,是要對表的某一些字段進行分組查詢的
比如: 查詢每個部門的平均薪資,需要對部門字段進行分組
按照某個指定的條件將單個單個的個體分成一個個整體
eg: 按照男女將人分組
按照膚色分組
按照年齡分組
分組后只能獲取分組的那個字段的數據,其他數據都不能直接獲取
但是在5.6版本中,獲取了也不會報錯,需要手動設置嚴格模式:
set global sql_mode = 'only_full_group_by,STRICT_TRANS_TABLES,PAD_CHAR_TO_FULL_LENGTH';
# 數據分組應用場景:每個部門的平均薪資,男女比例等
# 1.按部門分組
select * from emp group by post; # 分組后取出的是每個組的第一條數據
select id,name,sex from emp group by post; # 驗證
"""
設置sql_mode為only_full_group_by,意味着以后但凡分組,只能取到分組的依據,
不應該在去取組里面的單個元素的值,那樣的話分組就沒有意義了,因為不分組就是對單個元素信息的隨意獲取
"""
set global sql_mode="strict_trans_tables,only_full_group_by";
# 重新鏈接客戶端
select * from emp group by post; # 報錯
select id,name,sex from emp group by post; # 報錯
select post from emp group by post; # 獲取部門信息
# 強調:只要分組了,就不能夠再“直接”查找到單個數據信息了,只能獲取到組名
# 2.獲取每個部門的最高工資
# 以組為單位統計組內數據>>>聚合查詢(聚集到一起合成為一個結果)
# 每個部門的最高工資
select post,max(salary) from emp group by post;
補充:在顯示的時候還可以給字段取別名
select post as '部門',max(salary) as '最高工資' from emp group by post;
as也可以省略 但是不推薦省 因為寓意不明確
# 每個部門的最低工資
select post,min(salary) from emp group by post;
# 每個部門的平均工資
select post,avg(salary) from emp group by post;
# 每個部門的工資總和
select post,sum(salary) from emp group by post;
# 每個部門的人數
select post,count(id) from emp group by post;
統計的時候只要是非空字段 效果都是一致的
這里顯示age,salary,id最后演示特殊情況post_comment
**補充: **
# group_concat 分組之后使用
如果真的需要獲取分組意外的數據字段 可以使用group_concat()
# 每個部門的員工姓名
select post,group_concat(name) from emp group by post;
select post,group_concat(name,'|',sex) from emp group by post;
# concat 不分組使用
select concat(name,sex) from emp;
select concat(name,'|',sex) from emp;
having過濾
"""
where與having都是篩選功能 但是有區別
where在分組之前對數據進行篩選
having在分組之后對數據進行篩選
我們一定要有一個簡單的認識 一條SQL語句的結果也可以看成是一張全新的表
"""
select post,avg(salary) from emp where age>30 group by post having avg(salary)>10000;
關鍵字之distinct去重
# 對有重復的展示數據進行去重操作 一定要是重復的數據
select distinct id,age from emp;
select distinct post from emp;
關鍵字之order by排序
select * from emp order by salary asc; #默認升序排
select * from emp order by salary desc; #降序排
#先按照age降序排,在年輕相同的情況下再按照薪資升序排
select * from emp order by age desc,salary asc;
# 統計各部門年齡在10歲以上的員工平均工資,並且保留平均工資大於1000的部門,然后對平均工資進行排序
select post,avg(salary) from emp where age>10 group by post having avg(salary)>1000 order by avg(salary) desc;
關鍵字之limit分頁
# 限制展示條數
select * from emp limit 3;
# 查詢工資最高的人的詳細信息
select * from emp order by salary desc limit 1;
# 分頁顯示
select * from emp limit 0,5; # 第一個參數表示起始位置,第二個參數表示的是條數,不是索引位置
select * from emp limit 5,5;
關鍵字之regexp正則
select * from emp where name regexp '^j.*(n|y)$';
判斷表關系
# 班級表
cid caption
# 學生表
sid sname gender class_id
# 老師表
tid tname
# 課程表
cid cname teacher_id
# 成績表
sid student_id course_id number
1. 查詢崗位名以及崗位包含的所有員工名字
2. 查詢崗位名以及各崗位內包含的員工個數
3. 查詢公司內男員工和女員工的個數
4. 查詢崗位名以及各崗位的平均薪資
5. 查詢崗位名以及各崗位的最高薪資
6. 查詢崗位名以及各崗位的最低薪資
7. 查詢男員工與男員工的平均薪資,女員工與女員工的平均薪資

- 查詢崗位名以及崗位包含的所有員工名字
select post as '崗位',group_concat(name) as '員工' from emp group by post;
- 查詢崗位名以及各崗位內包含的員工個數
select post as '崗位',count(post) from emp group by post;

- 查詢公司內男員工和女員工的個數
select sex as '性別',count(sex) as '人數' from emp group by sex;

- 查詢崗位名以及各崗位的平均薪資
select post as '崗位',avg(salary) as '平均薪資' from emp group by post;

- 查詢崗位名以及各崗位的最高薪資
select post as '崗位',max(salary) as '最高薪資' from emp group by post;

- 查詢崗位名以及各崗位的最低薪資
select post as '崗位',min(salary) as '最低薪資' from emp group by post;

- 查詢男員工與男員工的平均薪資,女員工與女員工的平均薪資
select sex as '性別',group_concat(name) as '員工',avg(salary) as '平均薪資' from emp group by sex;

