mysql最詳細的查詢知識點總結(二)
四、函式查詢
一、概要
函式是一種有零個或多個引數並且有一個返回值的程式,函式主要分為兩大類單行函式,多行函式(聚合函式)
二、單行函式
1、定義
單行函式: 對每一個函式應用在表的記錄中時,只能輸入一行結果,返回一個結果。
2、分類
- 字元函式
- 數值函式
- 日期函式
- 轉換函式
- 通用函式
2.3、字元函式
1、UPPER
- 說明 將輸入的字串變為大寫返回;
- 作用 在一般的使用之中,使用者輸入資料的時候不關心資料本身存放的是大寫還是小寫
- 語法 upper(列 | 字串)
- 示例程式碼 1、將abcd改變成大寫 SELECT UPPER(‘abcd’) FROM dual 2、查詢姓名為simth的員工資訊 SELECT * FROM emp WHERE ename = UPPER(‘smith’);
2、LOWER
- 說明 將輸入的字串變為小寫返回
- 語法格式 LOWER(字串 | 列)
- 示例程式碼 1、將員工姓名轉化成小寫顯示 SELECT lower(ename) FROM emp
3、REPLACE
- 說明 字串進行替換
- 語法格式 REPLACE(字串 | 列, 被替換的字串, 用來替換的字串)
- 示例程式碼 使用字母’‘替換掉姓名中的所有字母’s’ SELECT REPLACE(ename,‘S’,’’) FROM emp
4、LENGTH
- 說明 求出字串的長度
- 語法格式 LENGTH(字串 | 列)
- 示例程式碼 查詢出每個僱員姓名的長度 SELECT LENGTH(ename) FROM emp;
5、INITCAP
- 說明 首字母大寫
- 語法格式 INITCAP(字串 | 列)
- 示例程式碼 將員工的姓名全部大寫字母開頭 SELECT initcap(ename) FROM emp;
6、SUBSTR(注意:從0和1開始擷取都是從字串的第一位開始)
- 說明 字串擷取,開始點可以是正也可以是負,如果是負表示從後面開始擷取 ,如果長度不寫,預設擷取到末尾
- 語法格式 SUBSTR(字串 | 列,開始點, 長度)
- 示例程式碼 1、從開始點一直擷取到結尾 SELECT SUBSTR(‘abcdefg’,2) from dual; --bcdefg 2、從開始點擷取到結束點,擷取部分內容 SELECT SUBSTR(‘abcdefg’,2,4) from dual;–bcde 3、要求擷取每個僱員姓名的後2個字母 SELECT ename,SUBSTR(ename,LENGTH(ename)-1) FROM emp; 等價於 SELECT ename,SUBSTR(ename,-2) FROM emp;
2.4、數值函式
1、ROUND
- 說明 四捨五入的操作 預設保留0位
- 語法格式 ROUND(數字 | 列 [,保留小數的位數])
- 示例程式碼 SELECT ROUND(100.12), ROUND(100.12 ,1) , ROUND(-100.56), ROUND(-100.56,1), ROUND(-100.567123,3) FROM DUAL; 100 100.1 -101 -100.6 -100.567
2、TRUNC
-
說明 捨棄指定位置的內容
-
語法格式 TRUNC(數字 | 列 [,保留小數的位數])
-
示例程式碼 SELECT TRUNC(903.53567),TRUNC(-903.53567), TRUNC(903.53567,2), TRUNC(-90353567,-1) FROM dual;
903 -903 903.53 -90353560
3、MOD
-
說明 取餘數
-
語法 MOD(數字 1,數字2)
-
示例程式碼 SELECT MOD(10,3) FROM dual
2.5、日期函式
1、NOW:
-
說明 返回伺服器的當前日期和時間(fsp指定小數秒的精度,取值0–6) 格式 ‘YYYY-MM-DD HH:MM:SS’或者‘YYYYMMDDHHMMSS’
-
語法格式 NOW([fsp])
-
示例程式碼 – now()的顯示格式是‘YYYY-MM-DD HH:MM:SS’ select now(); – now()+0的顯示格式是‘YYYYMMDDHHMMSS’ select now()+0; – 指定小數秒的精度 2018-04-19 01:55:46.658198 select now(6);
-
其它相同的還有 CURRENT_TIMESTAMP CURRENT_TIMESTAMP() LOCALTIMESTAMP LOCALTIMESTAMP() LOCALTIME LOCALTIME()
2、CURTIME
-
說明 返回當前時間,只包含時分秒(fsp指定小數秒的精度,取值0–6)
-
語法格式 CURTIME([fsp])
-
示例程式碼 select curtime() # 01:55:47 select curtime()+0 # 163301 select curtime(2) # 01:55:47.90
2、CURDATE
-
說明 返回當前日期,只包含年月日
-
語法格式 CURDATE()
-
示例程式碼 select curdate() select curdate()+0
3、選取日期時間的各個部分
-
說明 日期、時間、年、季度、月、日、小時、分鐘、秒、微秒
-
示例程式碼 SELECT now(),date(now()); – 日期 SELECT now(),time(now()); – 時間 SELECT now(),year(now()); – 年 SELECT now(),quarter(now()); – 季度 SELECT now(),month(now()); – 月 SELECT now(),week(now()); – 周 SELECT now(),day(now()); – 日 SELECT now(),hour(now()); – 小時 SELECT now(),minute(now()); – 分鐘 SELECT now(),second(now()); – 秒 SELECT now(),microsecond(now()); – 微秒
2.6、轉換函式
轉換函式將值從一種資料型別轉換為另外一種資料型別
1、date_format(date, format)
-
說明 把日期和數字轉換為制定格式的字串。format是格式化字串
-
語法格式 date_format(date, format)
-
示例程式碼 對日期的處理 select date_format(now(), ‘%Y-%m-%d’); – 2017-07-24 select date_format(now(), ‘%Y-%m-%d %H:%I:%S’); – 2017-07-24 15:03:44
-
附表 值 含義 秒 %S %s 兩位數字形式的秒( 00,01, …, 59) 分 %i 兩位數字形式的分( 00,01, …, 59) 小時 %H (%h %I) 24小時制, 12小時制 天 %d 兩位數字表示月中天數(01,02, …,31) 月 %m 兩位數字表示月份(01,02, …,12) 年 %Y %y 四位數字表示的年份(2017,2018…) 兩位數字表示的年份(15,16…)
2、str_to_date(str, format)
-
說明 將一個字串變為DATE型資料
-
語法格式 str_to_date(str,[,format]) --注意:格式要和字串日期的格式一致才能解析成功。
-
示例程式碼 將字串日期轉化為年月日 select str_to_date(‘2018-12-25’, ‘%Y-%m-%d’)
將字串日期+時間轉化成年與日時分秒 select str_to_date(‘2018-12-25 13:25:59’, ‘%Y-%m-%d %H:%i:%s’) – 注意年是大寫‘Y’,小時也必須是大寫‘H’ (如果其他為大寫,則得到結果為null)
2.7、通用函式
1、ifnull
主要針對null值的處理,null加任何值等於null
-
說明 如果X為空,返回value,否則返回VALUE
-
語法格式 NVL(col|字串,VALUE) --相當於三則運算
-
示例程式碼 對工資是2000元以下的員工,如果沒發獎金,每人獎金100元 SELECT ename,job,sal,ifnull(comm,100) FROM emp WHERE sal<2000;
三、分組函式
1、什麼叫分組函式
對一組(多行)資料的處理計算並返回一行資料
聚合函式也叫分組函式,有的也叫集合函式,它的資料來源一般來自多組資料,但返回的時候一般是一組資料,聚合函式對一組行中的某個列執行計算並返回單一的值。聚合函式經常與 SELECT 語句的 GROUP BY 子句一同使用,所以有的時候也把其稱之為分組函式
2、分類
函式名稱 返回值(結果)型別 說明 SUM(DISTINCT | ALL 列名) 數值 對所有數值求和 COUNT(DISTINCT | ALL 列名) 或者 COUNT(*) 數值 計數,求資料行數 MAX(DISTINCT | ALL 數值日期列) 數值 求最大值 MIN(DISTINCT | ALL 數值日期列) 數值 求最小值 AVG(DISTINCT | ALL 數值列) 數值 求平均值
3、 SUM(求總和)
1、 說明
- ALL表示對所有值求和
- DISTINCT表示只對不同值求和(相同值只取一次)
2、示例程式碼
- 計算僱員姓名為 'SMITH’和 ‘ALLEN’ 兩個人的基本薪資和 SELECT SUM(sal) FROM emp WHERE ename IN(‘SMITH’,‘ALLEN’);
4、 COUNT(統計行數)
1、 說明
- ALL對所有記錄,陣列做統計 (預設)
- DISTINCT只對不同值統計(相同值只取一次)
- COUNT(DISTINCT | ALL 列名) ---------會忽略null值進行統計 或者 COUNT(*) --------------------------------不需要考慮null值問題(開發使用較多)
2、 示例程式碼
- 顯示emp表中的總條資料 SELECT COUNT(*) FROM emp
- 統計 emp 職位型別的個數。 SELECT COUNT(DISTINCT job) FROM emp;
- 統計 emp 職位為 SALESMAN 的僱員個數 SELECT COUNT(*) FROM emp WHERE job=‘SALESMAN’;
- 統計 emp 中 有佣金的僱員的個數 SELECT COUNT(comm) FROM emp;
5、 MAX(求最大值)
1、 說明
- ALL表示對所有的值求最大值 (預設)
- DISTINCT表示對不同的值求最大值,相同的只取一次
2、 示例程式碼
- 查詢所有僱員中最高的薪資 SELECT MAX(sal) FROM emp;
- 顯示所有工資不同的員工中工資最高的 SELECT MAX(DISTINCT SAL) FROM EMP;
6、 AVG(求平均值)
1、 說明
- ALL表示對所有的值求平均值 ( 預設)
- DISTINCT表示對不同的值求最大值,相同的只取一次
2、 示例程式碼
- 求所有員工工資的平均值 SELECT (sal) FROM emp;
- 求不重複的員工工資的平均值 SELECT AVG(DISTINCT sal) FROM emp;
7、MIN(求最小值)
1、 說明
- ALL表示對所有的值求最小值( 預設)
- DISTINCT表示對不同的值求最小值,相同的只取一次
2、 示例程式碼
- 員工編號最小值 SELECT min(empno) FROM emp
- 查詢工資最低的 SELECT MIN(sal) FROM emp
- 查詢年薪最低的 SELECT * ,MIN((NVL2(comm,comm+sal,comm)*12 ) FROM emp
2.7 、注意事項
- 分組函式只能出現在select 列、having、order by子句中(不能出現在where後面)
- 當使用分組函式時,除了函式count(*)外,其他分組函式都會忽略NULL行。
2.8、單行函式和聚合函式的區別
- 單行函式操作時,根據函式的功能同時處理一行資料,返回每一行的處理結果;
- 聚合函式同時對分組後的一組行進行操作,返回分組後各組的處理結果
四、分組統計查詢
1、概要
Group By語句從英文的字面意義上理解就是“根據(by)一定的規則進行分組(Group)”。它的作用是通過一定的規則將一個數據集劃分成若干個小的區域,然後針對若干個小區域進行資料處理。 如果在查詢的過程中需要按某一列的值進行分組,以統計該組內資料的資訊時,就要使用group by子句。不管select是否使用了where子句都可以使用group by子句group by子句一定要與分組函式結合使用,否則沒有意義。
2、語法格式
----語句------------------------------------------------------------執行順序-----
SELECT [DISTINCT] * | 列名稱 [別名] , 列名稱 [別名] ,... | 統計函式 4、確定查詢列
FROM 資料表 [別名] , 資料表 [別名] ,... 1、資料來源
[WHERE 條件(s)] 2、過濾資料行
[GROUP BY 分組欄位, 分組欄位, ...] 3、執行分組操作
[ORDER BY 欄位 [ASC | DESC] , 欄位 [ASC | DESC] ,...] 5、資料排序
3、示例程式碼
- 查詢每個部門的人數 SELECT deptno ,COUNT(*) FROM emp GROUP BY deptno;
- 顯示每個部門員工的平均工資 SELECT deptno ,AVG(sal) 平均工資 FROM emp GROUP BY deptno;
- 顯示各個部門員工的工資+獎金 SELECT deptno,SUM(sal + IFNULL(comm,0)) FROM emp GROUP BY deptno;
- 按照部門編號分組,求出每個部門的人數,平均工資(要求擷取2位)(配合單行函式使用) SELECT deptno, COUNT(empno), ROUND(AVG(sal),2) FROM emp GROUP BY deptno;
- 按照職位分組,求出每個職位的最高和最低工資(單欄位分組) SELECT job, MAX(sal), MIN(sal) FROM emp GROUP BY job;
- 查詢每個部門的每種崗位的平均工資和最低工資 SELECT AVG(sal), MIN(sal) FROM emp GROUP BY deptno;
- 先統計出各個職位(job)的平均工資(AVG),再統計平均工資最高的工資(分組函式巢狀) SELECT MAX(AVG(sal)) FROM emp GROUP BY job 注意:分組函式允許巢狀,但是巢狀之後的分組函式的查詢之中不能再出現任何的其他欄位
- 查詢每個崗位的總工資但不包括’SALESMAN’崗位(配合Where使用) SELECT FROM emp WHERE name !=‘SALESMAN’
- 按部門、不同的職位,統計員工的工資總額 (多欄位統計) SELECT deptno, job, sum(sal) FROM emp GROUP BY deptno, job;
- 查詢各個部門中相同職位的員工人數並且按部門編號排序(多欄位統計排序) SELECT DEPTNO, JOB,COUNT(*) FROM emp GROUP BY deptno,job ORDER BY deptno;
- 查詢出每個部門的名稱、部門的人數、平均工資(多表單欄位查詢) 1、確定表 dept表 emp表 2、確定關聯欄位 deptno 3. 查詢 SELECT dname,count(e.empno),AVG(sal) FROM emp e,dept d WHERE e.deptno(+) = d.deptno group by dname;
4、注意事項
- GROUP BY後不可以接列的別名(根據執行順序分析就知道了) SELECT deptno dn ,AVG(sal) FROM emp GROUP BY dn; --錯誤
- GROUP BY 後不能接數字 SELECT deptno dn ,AVG(sal) FROM emp GROUP BY 1; --錯誤
- GROUP BY 後不可以接select後沒有的列名 SELECT deptno dn ,AVG(sal) FROM emp GROUP BY job;
- 如果一個SELECT中使用了分組函式,任何不在分組函式中的列(表示式)必須要在GROUP BY中 SELECT job ,deptno dn ,AVG(sal) --deptno列group by 後面沒有,使用會報錯 FROM emp GROUP BY job; 筆記:3和4總結為一句話 1、在select中出現的列名必須在group by 中出現,否則,其他列名只能在分組函式中使用;而在group by 中出現的欄位不一定要在select中出現
- group by之前可以使用where過濾資料,因為where是在分組之前起作用的,(執行順序分析) ----廢話
5、使用HAVING過濾分組
1、說明
- 首先對資料行進行分組。
- 把所得到的分組應用到分組函式中。
- 最後顯示滿足having條件的記錄 作用:在分組之後再過濾掉不符合條件的分組
2、與where的區別
1.只有having裡面可以使用分組函式,where中不允許出現分組函式
2.相同作用——都是根據條件過濾資料;不同的是where是在分組之前過濾資料,having是分組之後過濾分組資料。
3.原則:能在where裡過濾的資料就不要在having裡面去過濾
3、語法格式
----語句-----------------------------------------------------------執行順序---------
SELECT [DISTINCT] * | 列名稱 [別名] , 列名稱 [別名] ,... | 統計函式 5、確定查詢列
FROM 資料表 [別名] , 資料表 [別名] ,... 1、資料來源
[WHERE 條件(s)] 2、過濾資料行
[GROUP BY 分組欄位, 分組欄位, ...] [HIAVING 過濾分組] 3、執行分組操作
[HAVING 條件(s)] 4、過濾分組資料
[ORDER BY 欄位 [ASC | DESC] , 欄位 [ASC | DESC] ,...] 6、資料排序
4、示例程式碼
- 查詢部門的員工人數大於五部門編號 SELECT deptno,COUNT() FROM emp GROUP BY deptno HAVING COUNT()> 5;
- 查詢部門工資總和大於10000的部門編號 SELECT deptno, SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal)>10000;
- 查詢平均工資低於2000的部門號和它的平均工資 SELECT deptno,AVG(sal) a FROM emp GROUP BY deptno HAVING avg(sal)>2000;
- 查詢每個崗位的總工資並且不包括職位是’SALESMAN’崗位而且工資和大於5000 SELECT SUM(sal) FROM emp WHERE job!=‘SALESMAN’ GROUP BY job HAVING SUM(sal)>5000
6、綜合示例
-
查詢非銷售人員工作名稱以及從事同一工作僱員的月工資的總和,並且要滿足從事同一工作的僱員的月工資合計大於$5000,輸出結果按月工資的合計升序排列 1、查詢出所有的非銷售人員的資訊 SELECT * FROM emp WHERE job!=SALESMAN’;
2、按照職位進行分組,並且使用SUM函式統計 SELECT job,SUM(sal) FROM emp WHERE job<>‘SALESMAN’ GROUP BY job;
3、月工資的合計是通過統計函式查詢的,所以現在這個對分組後的過濾要使用HAVING子句完成 SELECT job,SUM(sal) FROM emp WHERE job!=‘SALESMAN’ GROUP BY job HAVING SUM(sal)>5000;
4、按照升序排列 SELECT job,SUM(sal) sum FROM emp WHERE job!=‘SALESMAN’ GROUP BY job HAVING SUM(sal)>5000 ORDER BY sum ASC;
-
顯示部門編號不是30的,的部門詳細資訊(部門編號、部門名稱、部門人數、部門月薪資總和),並要求 部門月工資總和大於8000,輸出結果按部門月薪資的總和降序排列。 SELECT d.deptno,d.dname,COUNT() 人數,NVL(SUM(e.sal),0) 月總收入 FROM dept d,emp e WHERE d.deptno=e.deptno(+) AND d.deptno!=30 GROUP BY d.deptno,d.dname HAVING SUM(e.sal) >8000 ORDER BY SUM(e.sal) DESC; 或 select deptno,d.dname ,count() peonum,sum(e.sal) s from dept d left join emp e using(deptno) --注意:using()中的欄位在使用時不能有字首。 where deptno !=30 group by deptno ,d.dname having sum(e.sal)>8000 order by s desc;
7、效能問題
能在where能過濾資料不要在having裡過濾,A和B都能達到同樣的目的,但是A效能相對好一些,因為A現將deptno=30的資料篩選出來,然後在將篩選的資料放入到臨時表空間內進行分組;而B將全部的資料都讀到臨時表空間內,然後在臨時表空間進行篩選資料,這樣一來B就需要更大的臨時表空間進行分組篩選,索引效能較差。
分頁查詢
1、為什麼需要分頁?
當資料庫的資料過的時候,客服端無法一次性顯示所有資料,例如我們資料庫表裡有十萬條資料,如果一下載入,查詢的速度慢,使用者體驗差,而且使用者也不可能一次性讀完這個十萬條資料
2、分頁技術分類
- 物理分頁(推薦) 在資料庫執行查詢時(實現分頁查詢),查詢需要的資料依賴資料庫SQL語句,屬於後臺分頁
- 邏輯分頁 先查詢所有資料到記憶體,再從記憶體擷取需要資料採用程式內部邏輯,屬於前臺分頁
1、說明
Mysql分頁採用 **LIMIT** 關鍵字
2、語法格式
- 格式 SELECT * FROM table LIMIT [offset,] rows SELECT * FROM table LIMIT rows OFFSET offset
- 說明
- 第一個引數指定第一個返回記錄行的偏移量
- 第二個引數指定返回記錄行的最大數目
- 如果只給定一個引數:它表示返回最大的記錄行數目
- 第二個引數為 -1 表示檢索從某一個偏移量到記錄集的結束所有的記錄行
- 初始記錄行的偏移量是 0(而不是 1)
3、示例程式碼
- 查詢6-10條資料 SELECT * FROM table LIMIT 5,5; – 檢索記錄行 6-10 條資料
- 查詢從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個引數為 -1 SELECT * FROM emp LIMIT 5,-1; – 檢索記錄行 6-最後一條.
- 查詢前 5 條記錄 SELECT * FROM emp LIMIT 5 – LIMIT n 等價於 LIMIT 0,n
- 返回4行,9表示從表的第10行開始 SELECT * FROM emp LIMIT 4 OFFSET 9 – 等價於 select * from Emp limit 9,4
多表查詢
1、定義
針對多張表的查詢,顯示多個表的資料
2、語法格式
SELECT [DISTINCT] * | 列名稱 [別名] , 列名稱 [別名] ,...
FROM 資料表 [別名] , 資料表 [別名] ,...
[WHERE 條件(s)]
[ORDER BY 欄位 [ASC | DESC] , 欄位 [ASC | DESC] ,...]
3、笛卡爾集
1、定義
笛卡爾乘積是指在數學中,兩個集合X和Y的笛卡尓積(Cartesian product),又稱直積
假設集合A={a, b},集合B={0, 1, 2},則兩個集合的笛卡爾積為{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}
2、案例分析
- 同時查詢emp和dept表 SELECT * FROM emp; SELECT * FROM dept; SELECT * FROM emp,dept;
- 分析 發現emp14條,dept表4條。但返回了56條資料56=14*4
3、如何避免笛卡爾積
唯一的方案就是在WHERE字句中加入有效的關聯欄位,
-
示例程式碼 SELECT * FROM emp e,dept d WHERE e.deptno=d.deptno;
-
說明 1、從查詢的結果看,我們顯示的資料正常了,但僅僅是顯示上去除了笛卡爾,而真正笛卡爾積現在依然存在,因為資料庫的操作機制就屬於逐行的進行資料的判斷,那麼如果按照這個思路理解的話,現在假設兩張表的資料量都很大的話,那麼使用這種多表查詢的效能,無法從根本上解決這個問題 2、在進行多表查詢的時候一定會存在有關聯列,在開發中一般都使用表的主鍵作為關聯表的欄位,名字基本也一樣.這樣方便閱讀和理解 3、如果表之中存在有同名的列,那麼一定要使用“表名稱.欄位名”,或者使用“別名.欄位名“(推薦使用別名,開發中常用)
4、示例程式碼
-
查詢每個僱員的編號,姓名,職位,工資,部門名稱,部門位置 分析問題:
- 確定使用到的資料表
- emp表(編號,姓名,職位,工資)
- dept表(部門名稱,部門位置)
- 確定已知的關聯欄位
- emp表與dept表的 deptno。 emp.deptno = dept.deptno; 解決問題:
- 第一步:查詢出每一位僱員的編號,姓名,職位,工資 SELECT e.empno,e.ename,e.job,e.sal FROM emp e;
- 第二步:為查詢中引入部門表,同時需要增加一個消除笛卡爾積的條件 SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc FROM emp e,dept d WHERE e.deptno=d.deptno;
- 確定使用到的資料表
-
查詢每個僱員的編號,姓名,職位,工資,工資等級。 分析問題:
- 確定使用到的資料表
- emp表(編號,姓名,職位,工資)
- salgrade表(工資等級)
- 確定已知的關聯欄位
- emp 表 sal 與salgrade表的 lasal,hisal。 emp.sal BETWEEN salgrade.losal AND salgrade.hisal; 解決問題:
- 第一步:查詢出每一位僱員的編號,姓名,職位,工資 SELECT e.empno,e.ename,e.job,e.sal FROM emp e;
- 第二步:為查詢中引入工資等級表,同時需要增加一個消除笛卡爾積的條件 SELECT e.empno,e.ename,e.job,e.sal,s.grade FROM emp e,salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal;
- 確定使用到的資料表
-
查詢每個僱員的編號,姓名,職位,工資,工資等級,部門名稱。 分析問題:
- 確定使用到的資料表
- emp表(編號,姓名,職位,工資)
- salgrade表(工資等級)
- dept表(部門名稱)
- 確定已知的關聯欄位
- emp表與dept表的 deptno。 emp.deptno = dept.deptno;
- emp 表 sal 與salgrade表的 lasal,hisal。 emp.sal BETWEEN salgrade.losal AND salgrade.hisal; 解決問題:
- 第一步:查詢出每個僱員的編號、姓名、基本工資、職位、工資 SELECT e.empno,e.ename,e.job,e.sal FROM emp e;
- 第二步:引入工資等級表,同時增加一個消除笛卡爾積的條件 SELECT e.empno,e.ename,e.job,e.sal,s.grade FROM emp e,salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal;
- 第三步:引入部門表,繼續增加消除笛卡爾積的條件 SELECT e.empno,e.ename,e.job,e.sal,s.grade,d.dname FROM emp e,salgrade s,dept d WHERE e.deptno=d.deptno AND e.sal BETWEEN s.losal AND s.hisal;
- 確定使用到的資料表
子查詢
1、定義
- 指嵌入在其他sql語句中的select語句
- 通俗的來講指的是在一個查詢之中嵌入若干個小的查詢
- 子查詢可以出現在查詢語句的(9i中除ORDER BY語句)任意位置上,但是實際開發運用中,子查詢出現在WHERE和FROM子句之中較多。
2 、核心作用
子查詢的出現主要是為了解決多表查詢之中的效能問題。
3 、分類
- 巢狀查詢(標準子查詢) 指子查詢可以脫離主查詢獨立執行
- 關聯查詢(相關子查詢) 關聯子查詢就是指子查詢與主查詢之間有條件關聯,關聯子查詢會引用外部查詢中的一列或多列。這種子查詢之所以被稱為關聯子查詢,是因為子查詢的確與外部查詢有關。當問題的答案需要依賴於外部查詢中包含的每一行中的值時,通常就需要使用關聯子查詢。
筆記:關聯子查詢(相關子查詢):子查詢不可以脫離主查詢獨立執行
4 、FROM中使用子查詢
1、說明
如果在 FROM 子句裡面出現的子查詢,其返回的結果一般都是多行多列資料(相當於表)。
2、示例程式碼
- 範例:查詢出每個部門的編號、名稱、位置、部門人數、平均工資
1、方式一
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno,d.dname,d.loc;
2、方式二:通過子查詢完成,所有的統計查詢只能在GROUP BY中出現,所以在子查詢之中負責統計資料,而在外部的查詢之中,負責將統計資料和dept表資料相統一。
SELECT d.deptno,d.dname,d.loc,temp.count,temp.avg
FROM dept d,(SELECT deptno dno,COUNT(empno) count,AVG(sal) avg
FROM emp
GROUP BY deptno) temp
WHERE d.deptno=temp.dno;
3、說明
方式一的資料量,
積的數量:emp 的 14 條 * dept 的 4 條 = 56 條資料;
方式二的資料量
- 子查詢中統計的記錄是14條記錄,最終統計的顯示結果是3條記錄;
- dept表之中一共有4條記錄;
- 如果現在產生笛卡爾積的話只有12條記錄,再加上子查詢中僱員的14條記錄,一共才26條記錄; 通過如上的分析,可以發現,使用子查詢的確要比使用多表查詢更加節省效能,所以在開發之中子查詢出現是最多的,而且在給出一個不成文的規定:大部分情況下,如果最終的查詢結果之中需要出現SELECT子句,但是又不能直接使用統計函式的時候,就在子查詢中統計資訊,即:有複雜統計的地方大部分都需要子查詢。
- 查詢比本部門平均工資高的員工的姓名,部門編號,工資及平均工資 SELECT e.ename, e.sal, e.deptno, temp.salavg FROM emp e, (SELECT department_id, AVG(sal) salavg FROM employees GROUP BY department_id) temp WHERE e.deptno = temp.deptno AND e.sal > temp.salavg
- 查詢出部門名稱,部門的員工數,部門的平均工資,部門的最低收入僱員的姓名 SELECT d.dname,temp.cou,temp.avg,e.ename FROM (SELECT deptno,count(1) cou,round(avg(sal)) avg,min(sal) min FROM emp GROUP BY deptno ) temp, dept d, emp e WHERE d.deptno=temp.deptno AND e.sal=temp.min;