多表查詢 前面講過的基本查詢都是對一張表進行查詢,但在實際的開發中遠遠不夠。 下麵使用表emp,dept,salgrade進行多表查詢 emp: dept: salgrade: 1.前置-mysql表查詢-加強 1.1查詢增強 使用where子句 如何查找1992.1.1後入職的員工 在mysql中 ...
多表查詢
前面講過的基本查詢都是對一張表進行查詢,但在實際的開發中遠遠不夠。
下麵使用表emp,dept,salgrade進行多表查詢
emp:
dept:
salgrade:
1.前置-mysql表查詢-加強
1.1查詢增強
-
使用where子句
如何查找1992.1.1後入職的員工
在mysql中,日期類型可以直接比較,需要註意格式
-
如何使用like操作符
%表示0到多個任意字元 _表示單個任意字元
如何顯示首字元為S的員工姓名和工資
如何顯示第三個字元為大寫O的所有員工的姓名和工資
-
如何顯示沒有上級的雇員的情況
-
查詢表結構
-
使用order by子句
如何按照工資的從低到高的順序,顯示雇員的信息
按照部門號升序而雇員的工資降序排列,顯示雇員的信息
練習
SELECT * FROM emp;
SELECT * FROM dept;
SELECT * FROM salgrade;
-- - 使用where子句
-- 在mysql中,日期類型可以直接比較
-- 如何查找1992.1.1後入職的員工
SELECT * FROM emp
WHERE hiredate > '1992-01-01';
-- - 如何使用like操作符
-- %表示0到多個字元 _表示單個字元
-- 如何顯示首字元為S的員工姓名和工資
SELECT ename,sal FROM emp
WHERE ename LIKE 'S%';
-- 如何顯示第三個字元為大寫O的所有員工的姓名和工資
SELECT ename,sal FROM emp
WHERE ename LIKE '__O%';
-- - 如何顯示沒有上級的雇員的情況
SELECT * FROM emp
WHERE mgr IS NULL;
-- - 查詢表結構
DESC emp;
-- 使用order by子句
-- 如何按照工資的從低到高的順序,顯示雇員的信息
SELECT * FROM emp
ORDER BY sal ASC;
-- 按照部門號升序而雇員的工資降序排列,顯示雇員的信息
SELECT * FROM emp
ORDER BY deptno ASC,sal DESC;
1.2分頁查詢
-
按照雇員的id號升序取出,每頁顯示3條記錄,請分別顯示第一頁,第二頁,第三頁
-
基本語法
select ... limit start,rows
表示從start+1行開始取,取出rows行,start從0開始計算
練習
-- 按照雇員的id號升序取出,每頁顯示3條記錄,請分別顯示第一頁,第二頁,第三頁
SELECT * FROM emp
ORDER BY empno
LIMIT 0,3
SELECT * FROM emp
ORDER BY empno
LIMIT 3,3
SELECT * FROM emp
ORDER BY empno
LIMIT 6,3
公式:
SELECT * FROM emp
ORDER BY empno
LIMIT 每頁顯示記錄數*(第幾頁-1),每頁顯示記錄數
1.3分組函數和分組子句加強
- 使用分組函數和分組子句group by
- 顯示每種崗位的雇員總數,平均工資
- 顯示雇員總數以及獲得補助的雇員數
- 顯示管理者的總人數
- 顯示雇員工資的最大差額
# 使用分組函數和分組子句groupby
-- 1. 顯示每種崗位的雇員總數,平均工資
SELECT COUNT(*),AVG(sal),job FROM emp
GROUP BY job;
-- 2. 顯示雇員總數以及獲得補助的雇員數
-- 思路:COUNT(列) 如果該列的值為空,是不會統計進去的
SELECT COUNT(*),COUNT(comm)
FROM emp
-- 擴展:統計沒有獲得補助的雇員數
SELECT COUNT(*),COUNT(IF(comm IS NULL,1,NULL))
FROM emp
-- 或者
SELECT COUNT(*),COUNT(*)-COUNT(comm)
FROM emp
-- 3. 顯示管理者的總人數
SELECT COUNT(DISTINCT mgr)
FROM emp;
-- 4. 顯示雇員工資的最大差額
SELECT MAX(sal)-MIN(sal)
FROM emp;
- 數據分組的總結
如果select語句同時包含有group by,having,limit,order by子句,
那麼他們的順序應該為 group by,having,order by,limit
應用案例
請統計每個部門的平均工資,並且是大於1000的,並且按照平均工資從高到低排序,取出前兩行記錄
-- 請統計每個部門group by 的平均avg工資,
-- 並且是大於1000的,having
-- 並且按照平均工資從高到低排序,order by
-- 取出前兩行記錄 limit
SELECT deptno,AVG(sal) AS avg_sal
FROM emp
GROUP BY deptno
HAVING avg_sal > 1000
ORDER BY avg_sal DESC
LIMIT 0,2
2.多表查詢
2.1笛卡爾積
- 說明
多表查詢是指基於兩個或兩個以上的表查詢,在實際的應用中,查詢單個表可能不能滿足需求,這時候就要用到多表查詢
例子-笛卡爾集(積)
SELECT * FROM emp,dept;
顯示的結果如下:共有52行記錄
emp表:共有13行記錄
dept表:共有4行記錄
分析如下:
當兩張表查詢時,規則為
- 從第一張表中,取出一行 和第二張表的每一行進行組合,返回結果[含有兩張表的所有列]
- 一共返回的記錄數=第一張表的行數*第二張表的行數
- 這樣多表查詢預設處理返回的結果,稱為笛卡爾集(積)
- 解決這個多表的關鍵就是要寫出正確的過濾條件 where
- 多表查詢的條件不能少於 表的個數 -1 ,否則會出現笛卡爾積
練習
-
顯示雇員名,雇員工資以及所在部門的名字
-
如何顯示部門號為10的部門名,員工名和工資
-
顯示各個員工的姓名,工資及其工資的級別
-- 1. 顯示雇員名,雇員工資以及所在部門的名字
SELECT ename,sal,dname,emp.deptno
FROM emp,dept
WHERE emp.deptno = dept.deptno;
-- 2. 如何顯示部門號為10的部門名,員工名和工資
SELECT ename,sal,dname,emp.deptno
FROM emp,dept
WHERE emp.deptno = dept.deptno AND emp.deptno =10;
-- 3. 顯示各個員工的姓名,工資及其工資的級別
SELECT ename,sal,grade
FROM emp,salgrade
WHERE sal BETWEEN losal AND hisal;
-- 4.顯示雇員名,雇員工資以及所在部門的名字,並按照部門名排序
SELECT ename,sal,dname
FROM emp,dept
WHERE emp.deptno = dept.deptno
ORDER BY dept.dname DESC;
2.2自連接
- 自連接
自連接是指在同一張表的連接查詢
- 自連接的特點
- 將同一張表看做兩張表使用
- 需要給表取別名 ,格式為 表名 表別名
思考:顯示公司員工和他上級的名字
分析:可以發現員工的名字和上級的名字都是在emp表中
員工和上級是通過emp表的mgr列關聯的
-- 顯示公司員工和他上級的名字
SELECT worker.ename AS '職員名', boss.ename AS '上級名'-- 列的別名
FROM emp worker,emp boss -- 為表起別名
WHERE worker.mgr = boss.empno; -- 過濾條件
3.子查詢
- 什麼是子查詢
子查詢是指嵌入在其他SQL語句的select語句,也叫嵌套查詢
- 單行子查詢
單行子查詢是指只返回一行數據的子查詢語句
請思考:如何顯示與Smith同一部門的所有員工?
- 多行子查詢
多行子查詢指返回多行數據的子查詢 使用關鍵字 in
3.1多行子查詢
練習1
-- 請思考:如何顯示與Smith同一部門的所有員工?
/*
1.先查詢到Smith的部門編號
2.把上面的select語句當做是一個子查詢來使用
*/
SELECT deptno
FROM emp
WHERE ename = 'SMITH';-- 先查詢到Smith的部門編號
-- 單行子查詢
SELECT *
FROM emp
WHERE deptno = (SELECT deptno
FROM emp
WHERE ename = 'SMITH'
);
-- 多行子查詢
-- 如何查詢和部門10的工作相同 的雇員的名字、崗位、工資、部門號,但是不含10號部門自己的雇員
/*
1.查詢到10號部門有哪些工作崗位
2.把上面的查詢結果當做是一個子查詢來使用
*/
SELECT DISTINCT job
FROM emp
WHERE deptno=10;
SELECT ename,job,sal,deptno
FROM emp
WHERE job IN( -- 返回了一個集合,用in
SELECT DISTINCT job
FROM emp
WHERE deptno=10)
AND deptno !=10; -- 不含10號部門自己的雇員
3.2all操作符
- 在多行子查詢中使用all操作符
請思考:顯示工資比部門30所有員工工資高的員工的姓名、工資和部門號
-- 顯示工資比部門30所有員工工資高的 員工的姓名、工資和部門號
SELECT ename,sal,deptno
FROM emp
WHERE sal>ALL(
SELECT sal
FROM emp
WHERE deptno = 30
)
-- 或者
SELECT ename,sal,deptno
FROM emp
WHERE sal>(
SELECT MAX(sal)
FROM emp
WHERE deptno = 30
)
3.3any操作符
- 在多行子查詢中使用any操作符
請思考:如何顯示工資比部門30其中一個員工工資高的 員工的姓名、工資和部門號
-- 請思考:如何顯示工資比部門30其中一個員工工資高的 員工的姓名、工資和部門號
SELECT ename,sal,deptno
FROM emp
WHERE sal>ANY(
SELECT sal
FROM emp
WHERE deptno = 30
)
-- 或者
SELECT ename,sal,deptno
FROM emp
WHERE sal>(
SELECT MIN(sal)
FROM emp
WHERE deptno = 30
)
3.4子查詢臨時表
- 子查詢當做一張表來使用
例子
ecshop表:
要求:查詢ecshop中各個類別中價格最高的商品
- 先得到各個類別中,價格最高的商品 --當做一個臨時表
-
選擇臨時表和原本的表格,過濾條件為
臨時表的cat_id = 原商品表的cat_id
&& 臨時表的max_price=原商品表的price
3.5多列子查詢
多列子查詢是指查詢返回多個列數據的子查詢語句
語法:
(欄位1,欄位2...) = (select 欄位1 ,欄位2 from ...)
例子
請思考如何查詢與ALLEN的部門和崗位完全相同的所有雇員(並且不包含ALLEN本人)
-- 請思考如何查詢與allen的部門和崗位完全相同的所有雇員(並且不包含Smith本人)
-- 1.得到ALLEN的部門和崗位
SELECT deptno , job
FROM emp
WHERE ename = 'ALLEN';
-- 2.把上面的查詢當做子查詢來使用,並且使用多列子查詢的語法進行匹配
SELECT * FROM emp
WHERE (deptno,job)=(
SELECT deptno , job
FROM emp
WHERE ename = 'ALLEN')
AND ename != 'ALLEN';
練習
-- 請得到和宋江數學、英語、語文成績完全相同的學生
SELECT * FROM student
WHERE (math,english,chinese)=(
SELECT math,english,chinese
FROM student
WHERE `name`= '宋江'
);
3.6子查詢練習
- 在from子句中使用子查詢
請思考:查找每個部門工資高於本部門平均工資的人的資料
-- 查找每個部門工資高於本部門平均工資的人的資料
-- 1.先得到對應的部門號和部門對應的平均工資
SELECT deptno,AVG(sal) FROM emp
GROUP BY deptno;
-- 2.把上面的結果當做子查詢,和emp進行多表查詢
SELECT ename,sal,temp.avg_sal,emp.deptno FROM emp,
(SELECT deptno,
AVG(sal) AS avg_sal FROM emp
GROUP BY deptno) temp
WHERE emp.deptno=temp.deptno AND emp.sal > avg_sal
-
查找每個部門工資最高的人的詳細信息
-- 查找每個部門工資最高的人的詳細信息 -- 1. 先得到每個部門的最高工資 SELECT MAX(sal) FROM emp GROUP BY deptno; -- 2.將上面的結果作為子查詢,和emp表進行多表查詢 SELECT ename,sal,temp.max_sal,emp.deptno FROM emp,( SELECT MAX(sal) AS max_sal FROM emp GROUP BY deptno ) temp WHERE emp.sal = temp.max_sal
-
查詢每個部門的信息(包括部門名、編號、地址)和人員數量
-- 查詢每個部門的信息
-- 1.部門名、編號、地址來自dept表
-- 2.各個部門的人員數量 ---》構建一個臨時表
SELECT COUNT(*),deptno
FROM emp
GROUP BY deptno
SELECT dname,dept.deptno,loc,person_num
FROM dept,(
SELECT COUNT(*) AS person_num,deptno
FROM emp
GROUP BY deptno
) temp
WHERE dept.deptno = temp.deptno
-- 還有一種寫法 表.* 表示將該表所有列都顯示出來,可以簡化SQL語句
-- 在多表查詢中,當多個表的列不重覆時,才可以直接寫列名
SELECT dname,loc,temp.*
FROM dept,(
SELECT COUNT(*) AS person_num,deptno
FROM emp
GROUP BY deptno
) temp
WHERE dept.deptno = temp.deptno