1. 程式人生 > 其它 >2022.5.5 約束條件之外來鍵及查詢關鍵字

2022.5.5 約束條件之外來鍵及查詢關鍵字

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;