單表多表子查詢


單表多表子查詢

一、單表查詢

增刪改查語句

"""
增:
insert [into] 
	[數據庫名.]表名[(字段1[, ..., 字段n])] 
values 
	(數據1[, ..., 數據n])[, ..., (數據1[, ..., 數據n])];

刪:
delete from [數據庫名.]表名 [條件];

改:
updata [數據庫名.]表名 set 字段1=值1[, ..., 字段n=值n] [條件];

查:
select [distinct] 字段1 [[as] 別名1],...,字段n [[as] 別名n] from [數據庫名.]表名 [條件];
"""

# 條件:from、where、group by、having、distinct、order by、limit => 層層篩選后的結果
# 注:一條查詢語句,可以擁有多種篩選條件,條件的順序必須按照上方順序進行逐步篩選,distinct稍有特殊(書寫位置),條件的種類可以不全
# 可以缺失,但不能亂序
  1. 去重 distinct

    create table t1(
    	id int,
     num int,
     x int
    );
    
    

mysql>: insert into t1 values(1,2,3),(2, 1, 2),(3, 2, 2),(4, 2, 2);

mysql>: select distinct * from t1; # 顯示全部數據
+------+------+------+
| id | num | x |
+------+------+------+
| 1 | 2 | 3 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 2 | 2 |
+------+------+------+

mysql>: select distinct num, x from t1; # 結果
+------+------+
| num | x |
+------+------+
| 2 | 3 |
| 1 | 2 |
| 2 | 2 |
+------+------+
mysql>: select distinct num from t1;
+------+
| num |
+------+
| 2 |
| 1 |
mysql>:
mysql>:


<span style='color: red'>總結distinct:</span>distinct對參與查詢的所有字段,整體去重(所查的數據記錄全部相同,才認為是重復的數據)

2. 數據准備

``` mysql
CREATE TABLE `emp`  ( 
`id` int(0) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL,
`gender` varchar(10),
`age` int(0) NULL DEFAULT 0,
`salary` float NULL DEFAULT 0,
`area` varchar(20) NULL,
`port` varchar(20) ,
`dep` varchar(20),
PRIMARY KEY (`id`)
)charset=utf8;

INSERT INTO `emp` VALUES 
 (1, 'yangsir', '男', 42, 10.5, '上海', '浦東', '教職部'),
 (2, 'engo', '男', 38, 9.4, '山東', '濟南', '教學部'),
 (3, 'jerry', '女', 30, 3.0, '江蘇', '張家港', '教學部'),
 (4, 'tank', '女', 28, 2.4, '廣州', '廣東', '教學部'),
 (5, 'jiboy', '男', 28, 2.4, '江蘇', '蘇州', '教學部'),
 (6, 'zero', '男', 18, 8.8, '中國', '黃浦', '咨詢部'),
 (7, 'owen', '男', 18, 8.8, '安徽', '宣城', '教學部'),
 (8, 'jason', '男', 28, 9.8, '安徽', '巢湖', '教學部'),
 (9, 'ying', '女', 36, 1.2, '安徽', '蕪湖', '咨詢部'),
 (10, 'kevin', '男', 36, 5.8, '山東', '濟南', '教學部'),
 (11, 'monkey', '女', 28, 1.2, '山東', '青島', '教職部'),
 (12, 'san', '男', 30, 9.0, '上海', '浦東', '咨詢部'),
 (13, 'san1', '男', 30, 6.0, '上海', '浦東', '咨詢部'),
 (14, 'san2', '男', 30, 6.0, '上海', '浦西', '教學部'),
 (15, 'ruakei', '女', 67, 2.501, '上海', '陸家嘴', '教學部');
  1. 常用函數
"""
拼接:concat() | concat_ws()
大小寫:upper() | lower()
浮點型操作:ceil() | floor() | round()
整型:可以直接運算
"""
mysql>: select name,area,port from emp;
+---------+------+--------+
| name    | area | port   |
+---------+------+--------+
| yangsir | 上海    | 浦東      |
| engo    | 山東    | 濟南       |
| jerry   | 江蘇     | 張家港     |


# 拼接:concat()
mysql>: select name as 姓名, concat(area, '--', port) as 地址 from emp; 
+---------+--------------+
| 姓名        | 地址            |
+---------+--------------+
| yangsir | 上海--浦東         |
| engo    | 山東--濟南          |
| jerry   | 江蘇--張家港         |


# 拼接:concat_ws()
mysql>: select name as 姓名 , concat_ws('-', area,port,dep) 信息 from emp;
+---------+--------------------+
| 姓名        | 信息                  |
+---------+--------------------+
| yangsir | 上海-浦東-教職部              |
| engo    | 山東-濟南-教學部               |
| jerry   | 江蘇-張家港-教學部              |


# 大小寫:upper() | lower()
mysql>: select upper(name) 姓名大寫, lower(name) 姓名小寫 from emp;
| 姓名大寫        | 姓名小寫       |
+----------+----------+
| YANGSIR  | yangsir  |
| ENGO     | engo     |
| JERRY    | jerry    |

# 浮點型操作:ceil() | floor() | round()
mysql>: select salary, ceil(salary) 上薪資, floor(salary) 下薪資, round(salary) 舍入 from emp;

+--------+--------+--------+------+
| salary | 上薪資      | 下薪資      | 舍入     |
+--------+--------+--------+------+
|   10.5 |     11 |     10 |   10 |
|    9.4 |     10 |      9 |    9 |
|      3 |      3 |      3 |    3 |
|    2.4 |      3 |      2 |    2 |
|    2.4 |      3 |      2 |    2 |
|    8.8 |      9 |      8 |    9 |
|    8.8 |      9 |      8 |    9 |

# 整型:可以直接運算
mysql>: select name 姓名, age 舊年齡, age+2 新年齡 from emp;
+---------+--------+--------+
| 姓名        | 舊年齡       | 新年齡       |
+---------+--------+--------+
| yangsir |     42 |     44 |
| engo    |     38 |     40 |
| jerry   |     30 |     32 |
| tank    |     28 |     30 |

  1. 條件查詢: where
# 多條件協調操作導入:where 奇數 [group by 部門 having 平均薪資] order by [平均]薪資 limit 1
mysql>: select * from emp where id < 15 limit 3 # 正常

mysql>: select * from emp limit 1 where id < 5; # 異常,條件亂序


# 判斷規則
"""
比較符合:>  |  <  |  >=  |  <=  |  =  |  !=
區間符合:between 開始 and 結束 |  in(自定義容器)
邏輯符合:and  |  or  |  not
相似符合:like _|%
正則符合:regexp 正則語法
"""

mysql>: select * from emp where salary>5;
mysql>: select * from emp where id%2=0;

mysql>: select * from emp where salary between 6 and 9;
mysql>: select * from emp where id in(2,3,4,6);

# _o 某o | __o 某某o | _o% 某o* (*是0~n個任意字符) | %o% *o*
mysql>: select * from emp where name like '%o%';
mysql>: select * from emp where name like '_o%';
mysql>: select * from emp where name like '__o%';

# sql只支持部分正則語法
mysql>: select * from emp where name regexp '.*\d';  # 不支持\d代表數字,認為\d就是普通字符串
mysql>: select * from emp where name regexp '.*[0-9]'; # 支持[]語法
+----+------+--------+------+--------+------+------+--------+
| id | name | gender | age  | salary | area | port | dep    |
+----+------+--------+------+--------+------+------+--------+
| 13 | san1 | 男       |   30 |      6 | 上海    | 浦東    | 咨詢部      |
| 14 | san2 | 男       |   30 |      6 | 上海    | 浦西     | 教學部      |
+----+------+--------+------+--------+------+------+--------+
mysql>:

  1. 分組與篩選: group by | having
# 現象:在沒有分組的情況下,where與having結果相同
# 重點:having可以對 聚合結果 進行篩選

mysql>: select * from emp where salary > 5;
mysql>: select * from emp having salary > 5;

mysql>: select * from emp where id in(12,45,3,2);
mysql>: select * from emp having id in(12,45,3,2);
  1. 聚合函數
"""
max(): 最大值
min(): 最小值
avg(): 平均值
sum(): 和
count(): 記數
group_concat(): 組內字段拼接,用來查看組內其他字段
"""
  1. 分組查詢
# 修改my.ini配置重啟mysql服務
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

# 在sql_mode沒有 ONLY_FULL_GROUP_BY 限制下,可以執行,但結果沒有意義
# 有 ONLY_FULL_GROUP_BY 限制,報錯
mysql>: select * from emp group by dep; # 在安全模式下會出錯
+----+---------+--------+------+--------+------+------+--------+
| id | name    | gender | age  | salary | area | port | dep    |
+----+---------+--------+------+--------+------+------+--------+
|  6 | zero    | 男       |   18 |    8.8 | 中國    | 黃浦     | 咨詢部      |
|  2 | engo    | 男       |   38 |    9.4 | 山東    | 濟南     | 教學部      |
|  1 | yangsir | 男       |   42 |   10.5 | 上海    | 浦東    | 教職部      |
+----+---------+--------+------+--------+------+------+--------+

# 分組后,表中數據考慮范圍就不是 單條記錄,因為每個分組都包含了多條記錄,參照分組字段,對每個分組中的 多條記錄 統一處理
# eg: 按部門分組,每個部門都有哪些人、最高的薪資、最低的薪資、平均薪資、組里一共有多少人

# 將多條數據統一處理,這種方式就叫 聚合
# 每個部門都有哪些人、最高的薪資、最低的薪資、平均薪資 都稱之為 聚合結果 - 聚合函數操作的結果
# 注:參與分組的字段,也歸於 聚合結果

mysql>: select dep 部門, group_concat(name) 合並, round(max(salary)) 最高薪資, min(salary) 最低薪資, avg(salary) 平均薪資, sum(salary) 總薪資, count(gender) 人數 from emp group by dep;

mysql>: select dep 部門, group_concat(name) 合並, round(max(salary)) 最高薪資, round(min(salary)) 最低薪資, round(avg(salary)) 平均薪資, round(sum(salary)) 總薪資, count(gender) 人數 from emp group by dep;
+--------+----------------------------------------------------+----------+----------+----------+--------+------+
| 部門       | 合並                                                  | 最高薪資        | 最低薪資        | 平均薪資       | 總薪資      | 人數     |
+--------+----------------------------------------------------+----------+----------+----------+--------+------+
| 咨詢部      | san1,san,zero,ying                                 |        9 |        1 |        6 |     25 |    4 |
| 教學部      | ruakei,san2,kevin,jason,owen,jiboy,tank,jerry,engo |       10 |        2 |        6 |     50 |    9 |
| 教職部      | monkey,yangsir                                     |       10 |        1 |        6 |     12 |    2 |
+--------+----------------------------------------------------+----------+----------+----------+--------+------+
mysql>: select dep 部門, max(salary) 最高薪資 from emp group by dep;
+--------+----------+
| 部門       | 最高薪資        |
+--------+----------+
| 咨詢部      |        9 |
| 教學部      |      9.8 |
| 教職部      |     10.5

總結:分組后,在查詢條件只能為 分組字段 和 聚合函數操作的聚合結果

  1. 分組后having
mysql>: 
select 
dep 部門,
group_concat(name) 成員, 
max(salary) 最高薪資,
min(salary) 最低薪資,
avg(salary) 平均薪資,
sum(salary) 總薪資,
count(gender) 人數
from emp group by dep;

# 最低薪資小於2
mysql>:
select 
	dep 部門,
	group_concat(name) 成員,
	max(salary) 最高薪資,
	min(salary) 最低薪資,
	avg(salary) 平均薪資,
	sum(salary) 總薪資,
	count(gender) 人數
from emp group by dep having avg(salary) > 6;

總結:在分組中,可以使用having 對 聚合結果 再進行篩選,where不可以

  1. 排序
# 排序規則
order by 主排序字段[asc|desc], 次排序字段[asc|desc],.....,次排序字段n[asc|desc]
  • 未分組狀態下排序
mysql>: select * from emp;

# 按年齡升序
mysql>: select * from emp order by age asc;

# 按薪資降序
mysql>: select * from emp order by salary desc;

# 按薪資降序,如果相同按年齡排序
mysql>: select * from emp order by salary desc, age desc;

# 按年齡排序,如果相同再按薪資降序
mysql>: select * from emp order by age desc, salary desc;

分組狀態下排序

mysql>:
select 
	dep 部門,
	group_concat(name) 成員,
	max(salary) 最高薪資,
	min(salary) 最低薪資,
	avg(salary) 平均薪資,
	sum(salary) 總薪資,
	count(gender) 人數
from emp group by dep;

# 最高薪資降序
mysql>:
select 
	dep 部門,
	group_concat(name) 成員,
	max(salary) 最高薪資,
	min(salary) 最低薪資,
	avg(salary) 平均薪資,
	sum(salary) 總薪資,
	count(gender) 人數
from emp group by dep order by 最高薪資 desc;
  1. 限制limit
# 語法:limit 條數 | limit 偏移量, 條數
mysql>: select name, salary from emp where salary < 8 order by salary desc limit 1;

mysql>: select name, salary from emp limit 14, 3;
mysql>: select name, salary from emp limit 4, 5;

二、連表查詢

  1. 連接
# 連接:將有聯系的多張表通過關聯(有聯系就行,不一定是外鍵)字段,進行連接,形參一張大表
# 連表查詢:在大表的基礎上進行查詢,就稱之為連表查詢


# 將表與表建立連接的方式有四種:內連接、左連接、右連接、全連接

創建表

mysql>: create database db3;
mysql>: use db3;

mysql>: 
create table dep(
	id int primary key auto_increment,
	name varchar(16),
	work varchar(16)
);
create table emp(
	id int primary key auto_increment,
	name varchar(16),
	salary float,
	dep_id int
);
insert into dep values(1, '市場部', '銷售'), (2, '教學部', '授課'), (3, '管理部', '開車');
insert into emp(name, salary, dep_id) values('egon', 3.0, 2),('yanghuhu', 2.0, 2),('sanjiang', 10.0, 1),('owen', 88888.0, 2),('liujie', 8.0, 1),('yingjie', 1.2, 0);
  1. 笛卡爾積
# 笛卡爾積: 集合 X{a, b} * Y{o, p, q} => Z{{a, o}, {a, p}, {a, q}, {b, o}, {b, p}, {b, q}}

mysql>: select * from emp, dep;

# 總結:是兩張表 記錄的所有排列組合,數據沒有利用價值
  1. 內連接
# 關鍵字查詢 inner join on
# 語法 from A表 inner join B表 on A表.關聯的字段=B.關聯的字段
mysql>: 
select 
	emp.id, emp.name, salary, emp.dep_id, dep.id, dep.name, dep.work 
from emp inner join dep on emp.dep_id=dep.id;

select 
	emp.id, emp.name, salary, emp.dep_id, dep.id, dep.name, dep.work 
from emp, dep where emp.id=dep.id;
	
+----+----------+--------+--------+----+--------+------+
| id | name     | salary | dep_id | id | name   | work |
+----+----------+--------+--------+----+--------+------+
|  1 | egon     |      3 |      2 |  1 | 市場部      | 銷售     |
|  2 | yanghuhu |      2 |      2 |  2 | 教學部      | 授課    |
|  3 | sanjiang |     10 |      1 |  3 | 管理部      | 開車     |
+----+----------+--------+--------+----+--------+------+
3 rows in set (0.00 sec)
	
# 總結:只保留兩個表有關聯的數據
  1. 左連接
# 關鍵字 left join on
# 語法 from 左表 left join 表名 on 左邊.關聯字段=右表.關聯字段
mysql>:
select 
	emp.id,emp.name,salary,dep.name,work 
from emp left join dep on emp.dep_id=dep.id order by emp.id;
+----+----------+--------+--------+------+
| id | name     | salary | name   | work |
+----+----------+--------+--------+------+
|  1 | egon     |      3 | 教學部      | 授課    |
|  2 | yanghuhu |      2 | 教學部      | 授課    |
|  3 | sanjiang |     10 | 市場部      | 銷售     |
|  4 | owen     |  88888 | 教學部      | 授課    |
|  5 | liujie   |      8 | 市場部      | 銷售     |
|  6 | yingjie  |    1.2 | NULL   | NULL |
+----+----------+--------+--------+------+
6 rows in set (0.00 sec)
# 總結:保留左表的全部數據,右表有對應的數據直接連接表顯示,沒有對應關系用null填充
  1. 右連接
# 關鍵字 right join in
# 語法:from A表 right join B表 on A表.關聯字段=B表.關聯字段
mysql>: 
select 
	emp.id,emp.name,salary,dep.name,work 
from emp right join dep on emp.dep_id=dep.id order by emp.id;
+------+----------+--------+--------+------+
| id   | name     | salary | name   | work |
+------+----------+--------+--------+------+
| NULL | NULL     |   NULL | 管理部      | 開車     |
|    1 | egon     |      3 | 教學部      | 授課    |
|    2 | yanghuhu |      2 | 教學部      | 授課    |
|    3 | sanjiang |     10 | 市場部      | 銷售     |
|    4 | owen     |  88888 | 教學部      | 授課    |
|    5 | liujie   |      8 | 市場部      | 銷售     |
+------+----------+--------+--------+------+
6 rows in set (0.00 sec)

# 總結: 保留右表的全部數據,左表有對應數據直接連表顯示,沒有對應關系用null填空
  1. 左右可以相互轉化
mysql>: 
select 
	emp.id,emp.name,salary,dep.name,work 
from emp right join dep on emp.dep_id=dep.id order by emp.id;
+------+----------+--------+--------+------+
| id   | name     | salary | name   | work |
+------+----------+--------+--------+------+
| NULL | NULL     |   NULL | 管理部      | 開車     |
|    1 | egon     |      3 | 教學部      | 授課    |
|    2 | yanghuhu |      2 | 教學部      | 授課    |
|    3 | sanjiang |     10 | 市場部      | 銷售     |
|    4 | owen     |  88888 | 教學部      | 授課    |
|    5 | liujie   |      8 | 市場部      | 銷售     |
+------+----------+--------+--------+------+
6 rows in set (0.00 sec)

select 
	emp.id,emp.name,salary,dep.name,work 
from emp left join dep on emp.dep_id=dep.id order by emp.id;
+----+----------+--------+--------+------+
| id | name     | salary | name   | work |
+----+----------+--------+--------+------+
|  1 | egon     |      3 | 教學部      | 授課    |
|  2 | yanghuhu |      2 | 教學部      | 授課    |
|  3 | sanjiang |     10 | 市場部      | 銷售     |
|  4 | owen     |  88888 | 教學部      | 授課    |
|  5 | liujie   |      8 | 市場部      | 銷售     |
|  6 | yingjie  |    1.2 | NULL   | NULL |
+----+----------+--------+--------+------+
6 rows in set (0.00 sec)
  1. 全連接(一對多)
select emp.id, emp.name, salary, dep.name, work 
from emp left join dep on emp.dep_id=dep.id
union
select emp.id, emp.name, salary, dep.name, work
from emp right join dep on emp.dep_id=dep.id order by id;

# 總結:左表右表數據都被保留,彼此有對應關系正常顯示,彼此沒有對應關系均用空null填充對方

  1. 一對一與一對多情況一致
# 創建一對一 作者與作者詳情 表
create table author(
	id int,
    name varchar(64),
    detail_id int
);
create table author_detail(
	id int,
    phone varchar(11)
);
# 填充數據
insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0);
insert into author_detail values(1, '13344556677'), (2, '14466779988'), (3, '12344332255');

# 內聯
select author.id, author.name, author_detail.phone from author inner join author_detail on author.detail_id=author_detail.id;

+------+------+-------------+
| id   | name | phone       |
+------+------+-------------+
|    1 | Bob  | 13344556677 |
|    2 | Tom  | 14466779988 |
+------+------+-------------+
2 rows in set (0.00 sec)

# 全連
select author.id, author.name, author_detail.phone from author left join author_detail on author.detail_id=author_detail.id
union
select author.id, author.name, author_detail.phone from author right join 
author_detail on author.detail_id=author_detail.id;

+------+--------+-------------+
| id   | name   | phone       |
+------+--------+-------------+
|    1 | Bob    | 13344556677 |
|    2 | Tom    | 14466779988 |
|    3 | ruakei | NULL        |
| NULL | NULL   | 12344332255 |
+------+--------+-------------+
4 rows in set (0.00 sec)

  1. 多對多:
# 在一對一基礎上,建立 作者與書 的多對多關系關系

# 利用之前的作者表
create table author(
	id int,
    name varchar(64),
    detail_id int
);
insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0);

# 創建新的書表
create table book(
	id int,
    name varchar(64),
    price decimal(5,2)
);
insert into book values(1, 'python', 3.66), (2, 'Linux', 2.66), (3, 'Go', 4.66);

# 創建 作者與書 的關系表
create table author_book(
	id int,
    author_id int,
    book_id int
);
# 數據:author-book:1-1,2  2-2,3  3-1,3
insert into author_book values(1,1,1),(2,1,2),(3,2,2),(4,2,3),(5,3,1),(6,3,3);

select author.id, author.name, book.name, book.price from author join 
author_book on author.id = author_book.author_id  # 這是一張表與另一張表拼接
join book on book.id=author_book.id;



------+------+--------+-------+
| id   | name | name   | price |
+------+------+--------+-------+
|    1 | Bob  | python |  3.66 |
|    1 | Bob  | Linux  |  2.66 |
|    2 | Tom  | Go     |  4.66 |
+------+------+--------+-------+
3 rows in set (0.00 sec)



免責聲明!

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



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