MySQL 數據庫 之 外鍵 & SQL查詢語句詳解


內容概要

  • 外鍵
  • 表與表之間關系
    • 一對多
    • 多對多
    • 一對一
    • 沒有關系
  • 操作表的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]image

上面這張表有以下缺陷:

  • 1、表的重點不突出,到底是員工表還是部門表
  • 2、表中部門和部門信息兩個字段的數據很多在重復
  • 3、表的拓展性極差,只要教學部改一個名字,整張表都要跟着改掉,牽一發而動全身

如何建立外鍵?

解決以上表的缺陷:

將上述一張表拆分成兩張表,然后通過給一個表添加一個外鍵字段,將兩張表聯系起來

image

外鍵字段>>>:部門編號

其實就是用來標識表與表之間的數據關系

簡單的理解為該字段可以讓你去到其他表中查找數據

表與表之間關系

表關系總共就四種:

一對多、多對多、一對一、沒有關系

判斷表關系的方式:換位思考

補充:級聯更新,級聯刪除,也就是兩表之間的數據改動可以進行同步

    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. 查詢男員工與男員工的平均薪資,女員工與女員工的平均薪資

image

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

image

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

image

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

image

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

image

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

image

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

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM