2022.5.5 約束條件之外來鍵及查詢關鍵字
阿新 • • 發佈:2022-05-06
2022.5.5 約束條件之外來鍵及查詢關鍵字
- 約束條件之外來鍵
- 查詢關鍵字
一、約束條件之外來鍵
1、引入
# 建立一張員工表 id name age dep_name dep_desc 缺陷>>>: 1.表重點不清晰,可以說是員工表也可以是部門表 2.表中某些欄位對應資料重複,浪費儲存空間 3.表的擴充套件性差,牽一髮動全身,耦合度太高不利維護 解決>>>: 將這張表分成兩張表: 員工表>>>: id name age 部門表>>>: id dep_name dep_desc 解決後缺陷>>>: 致命缺陷:員工與部門沒有繫結關係 再次優化>>>: 在員工表中新增一個‘部門編號’欄位dep_id,與部門表的主鍵欄位對應 # 引入知識 新增的部門編號欄位其實就是外來鍵欄位>>>: 記錄表與表之間關係的資料
2、外來鍵關係(4種)
- 一對多
- 多對多
- 一對一
- 無關係
判斷表關係四字口訣>>>: 換位思考
(1)一對多
# 換位思考 以員工表與部門表為例 1.先站在員工表的角度 問:一個員工能否對應多個部門 答:不可以 2.再站在部門表的角度 問:一個部門能否對應多個員工 答:可以 結論:換位思考之後得出的答案是一個可以一個不可以 (1)所以關係是"一對多",部門是'一'員工是'多' (2)關係表達只能用一對多,不能用多對一 (3)一對多關係,外來鍵欄位建在"多"的一方(員工表) # 外來鍵sql語句 foreign key(dep_id) references dep(id) (1)建立表的時候,應該先建立被關聯表(沒有外來鍵欄位的表) (2)插入資料的時候,應該先插入被關聯表(沒有外來鍵欄位的表);因為外來鍵欄位填入的值只能是被關聯表中已經存在的主鍵值 問題:修改、刪除被關聯表資料都會出現障礙,且報錯 解決辦法>>>: 級聯更新、級聯刪除 # 級聯更新、級聯刪除 on update cascade # 級聯更新,外來鍵關聯的表主鍵更新,另一個表對應資料也更新 on delete cascade # 級聯刪除,外來鍵關聯的表主鍵刪除,另一個表對應資料刪除 # 新增外來鍵sql語句總結: create table 員工表( id int; name vrchar(32); ... foreign key(部門表_id) references 部門表(id) on update cascade on delete cascade # 外來鍵+級聯更新、刪除 ) """ 在實際工作中外來鍵也可能不會使用 因為外來鍵會消耗額外的資源 並且會增加表的複雜度 表很多的情況下 我們也可以通過SQL語句的形式建立邏輯意義上的表關係 """
一對一關係表>>>外來鍵sql語句程式碼操作:
# 在建立表字段的時候也可以給每個欄位新增中文註釋>>> comment '註釋內容' 員工表>>>: create table emp( id int primary key auto_increment comment '編號', name varchar(32) comment '姓名', age int comment '年齡', dep_id int comment '部門編號', foreign key(dep_id) references dep(id) on update cascade on delete cascade # 新增外來鍵及級聯更新、級聯刪除 ); 部門表>>>: create table dep( id int primary key auto_increment comment '編號', dep_name varchar(32) comment '部門名稱', dep_desc varchar(32) comment '部門描述' );
這樣,只要部門表主鍵修改或者刪除某行資料,員工表對應資料也會隨之修改和刪除;
關係如下圖:
(2)多對多關係
以圖書表和作者表為例
# 換位思考
1.先站在圖書表的角度
問:一本書籍能否對應多名作者
答:可以
2.再站在作者表的角度
問:一名作者能否對應多本書籍
答:可以
結論:換位思考之後兩邊都可以 那麼就是"多對多"關係
那麼思考以下,針對多對多關係的表,是否可以將兩者的外來鍵都設定成對方的主鍵呢,這樣不就可以關聯了?
但是這樣有個致命的問題,修改或者刪除其中一個表的主鍵、資料,另一個表的資料也會隨之修改、刪除,那麼就沒辦法實現多對多的效果了,那麼應該怎麼辦呢?
# 針對多對多關係,需要單獨開設第三張表專門儲存兩張表的關係,這兩張表叫“基表”
圖書表>>>:
create table book(
id int primary key auto_increment,
title varchar(32),
price float(10,2)
);
作者表>>>:
create table author(
id int primary key auto_increment,
name varchar(32),
gender enum('male','female','others')
);
第三張表>>>:
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)一對一關係
# 資料分析
1.以QQ使用者表為例,分析裡面的資料分為兩類>>>:
熱資料:經常使用的資料 >>> qq號碼、座右銘、個人簡介、愛好等
冷資料:不經常使用的資料 >>> 郵箱、電話、學校等
2.為節省資源並降低資料庫壓力,將表一分為二>>>:
使用者表:存放使用頻率較高的資料欄位
使用者詳情表:存放使用頻率較低的資料欄位
# 換位思考
先站在使用者表的角度
問:一個使用者資料能否對應多個使用者詳情資料
答:不可以
再站在使用者詳情表的角度
問:一個使用者詳情資料能否對應多個使用者資料
答:不可以
結論:換位思考之後兩邊都不可以,那麼關係可能有兩種
(1)'沒有關係'
(2)'一對一關係'
針對'一對一關係'外來鍵欄位建在任意一方都可以,但是推薦建在查詢頻率較高的一方
# sql語句程式碼
使用者表>>>:
create table user(
id int primary key auto_increment,
name varchar(32),
gender enum('male','female','others'),
user_detail_id int unique, # 加unique是因為資料是一對一的,要保證不能重複
foreign key(user_detail_id) reference userdetail(id) on update cascade on delete cascade
)
使用者詳情表>>>:
create table userdetail(
id int primary key auto_increment,
phone bigint,
age int
);
關係如下圖:
這樣,針對使用者基本資料及使用者的詳細資訊的資料就分好了;
二、表查詢關鍵字
先建立一個表格便於操作關鍵字:
# 資料準備
建立員工表>>>:
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, # 年齡 非空 預設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);
1、查詢關鍵字之select與from
select # 用於指定查詢的欄位
from # 用於指定查詢的表
select id,name from mysql.user; # 查詢user中的id和name欄位
'''查詢關鍵字其實有先後執行順序 但是無需過多在意!!!'''
2、查詢關鍵字之where篩選
# 1.查詢id大於等於3且小於等於6的資料
select * 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.查詢id小於3和大於6的資料
select * from emp where id not between 3 and 6; # 資料取反
# 4.查詢薪資不在20000,18000,17000的資料
select * from emp where salary not in (20000,18000,17000);
# 5.查詢崗位描述為空的資料
select * from emp where post_comment=null # 報錯!針對null只能用is不能用等號
select * from emp where post_comment is null; # 不報錯
# 6.查詢員工姓名中包含字母o的員工姓名和薪資
查詢條件如果不是很明確的情況下 我們統一稱之為'模糊查詢'
關鍵字
like : 開啟模糊查詢的關鍵字
關鍵符號
% : 匹配任意個數的任意字元
_ : 匹配單個個數的任意字元
select name,salary from emp where name like '%o%'; # 前後加%表示匹配任意字元
# 7.查詢員工姓名是由四個字元組成的資料
select * from emp where name like '____'; # 用四個下劃線可以指代四個字元
select * from emp where char_length(name)=4; # char_length獲取字元長度也可以
3、查詢關鍵字之group by分組
(1)什麼是分組?
按照指定的條件將單個單個的個體組織成一個個整體
eg:按照性別分組 按照部門分組 按照年齡分組 按照國家分組...
(2)為什麼需要分組?
分組的好處在於可以快速統計出某些資料
eg:最大薪資、平均年齡、最小年齡、總人數等
(3)如何分組?
按照部分分組
# 按照崗位分組並查詢所有資料
select * from emp group by post;
如果是MySQL5.6及以下版本>>>:
有幾個組就顯示幾行資料,且會顯示其他欄位的資訊,但是隻顯示一條,每條資料預設顯示該組的第一條資料
mysql5.7及以上版本>>>:
預設自帶sql_mode=only_full_group_by
輸入上面程式碼就會報錯!
因為該模式要求分組之後預設只可以直接獲取分組的依據,不能直接獲取其他欄位;
原因是分組的目的就是按照分組的條件來管理諸多資料 最小單位應該是分組的依據而不是單個單個的資料;
select post from emp group by post; # 這樣才不會報錯,且展示的資料僅限分組後的post的資料(單個不重複)
# 結論:如果是MySQL5.6及以下版本,需要自己手動新增>>>: sql_mode=only_full_group_by
(4)聚合函式
專門用於分組之後的資料統計
# 聚合函式分類
max 統計最大值
min 統計最小值
sum 統計求和
count 統計計數
avg 統計平均值
函式括號裡是欄位型別,用以篩選分組後或者未分組的資料;
ps:是否需要分組,我們可以在題目或者需求中發現;
# 1.統計每個部門的最高薪資
像這種需要統計某個欄位的某個資料,就需要使用分組和聚合函數了;
select post,max(salary) from emp group by post; # 先按照部門分組,然後展示組別和每個組的最大薪資,逗號隔開;
# 2.統計每個部門的平均薪資
select post,avg(salary) from emp group by post;
# 3.統計每個部門的員工人數
select post,count(id) from emp group by post;
# 4.統計每個部門的月工資開銷
select post,sum(salary) from emp group by post;
# 5.統計每個部門最小的年齡數
select post,min(age) from emp group by post;
"""間接獲取分組以外其他欄位的資料"""
group_concat(欄位型別),
(1)可以展示分組後的其他某欄位的所有資料集中展示;
(2)括號裡可以對欄位展示的格式進行拼接字串格式化輸出
# 1.統計每個部門下所有員工的姓名
select post,group_concat(name) from emp group by post;
# 2.統計每個部門下所有員工的姓名和年齡
select post,group_concat(name,age) from emp group by post; # 獲取按照post分組後的所有name和age
select post,group_concat(name,'|',age) from emp group by post; # 拼接字串後展示
(5)欄位起別名
select post,group_concat(name) as '姓名' from emp group by post; # as加別名
select id as '序號',name as '姓名' from emp;
# as關鍵字也可以不寫 但是語義不明確 建議加上
select id '序號',name '姓名' from emp;