四、函式查詢

一、概要

函式是一種有零個或多個引數並且有一個返回值的程式,函式主要分為兩大類單行函式,多行函式(聚合函式)

二、單行函式

1、定義

單行函式: 對每一個函式應用在表的記錄中時,只能輸入一行結果,返回一個結果。

2、分類

  1. 字元函式
  2. 數值函式
  3. 日期函式
  4. 轉換函式
  5. 通用函式

2.3、字元函式

1、UPPER

  1. 說明 將輸入的字串變為大寫返回;
  2. 作用 在一般的使用之中,使用者輸入資料的時候不關心資料本身存放的是大寫還是小寫
  3. 語法 upper(列 | 字串)
  4. 示例程式碼 1、將abcd改變成大寫 SELECT UPPER(‘abcd’) FROM dual 2、查詢姓名為simth的員工資訊 SELECT * FROM emp WHERE ename = UPPER(‘smith’);

2、LOWER

  1. 說明 將輸入的字串變為小寫返回
  2. 語法格式 LOWER(字串 | 列)
  3. 示例程式碼 1、將員工姓名轉化成小寫顯示 SELECT lower(ename) FROM emp

3、REPLACE

  1. 說明 字串進行替換
  2. 語法格式 REPLACE(字串 | 列, 被替換的字串, 用來替換的字串)
  3. 示例程式碼 使用字母’‘替換掉姓名中的所有字母’s’ SELECT REPLACE(ename,‘S’,’’) FROM emp

4、LENGTH

  1. 說明 求出字串的長度
  2. 語法格式 LENGTH(字串 | 列)
  3. 示例程式碼 查詢出每個僱員姓名的長度 SELECT LENGTH(ename) FROM emp;

5、INITCAP

  1. 說明 首字母大寫
  2. 語法格式 INITCAP(字串 | 列)
  3. 示例程式碼 將員工的姓名全部大寫字母開頭 SELECT initcap(ename) FROM emp;

6、SUBSTR(注意:從0和1開始擷取都是從字串的第一位開始)

  1. 說明 字串擷取,開始點可以是正也可以是負,如果是負表示從後面開始擷取 ,如果長度不寫,預設擷取到末尾
  2. 語法格式 SUBSTR(字串 | 列,開始點, 長度)
  3. 示例程式碼 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

  1. 說明 四捨五入的操作 預設保留0位
  2. 語法格式 ROUND(數字 | 列 [,保留小數的位數])
  3. 示例程式碼 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

  1. 說明 捨棄指定位置的內容

  2. 語法格式 TRUNC(數字 | 列 [,保留小數的位數])

  3. 示例程式碼 SELECT TRUNC(903.53567),TRUNC(-903.53567), TRUNC(903.53567,2), TRUNC(-90353567,-1) FROM dual;

    903              -903             903.53           -90353560
    

3、MOD

  1. 說明 取餘數

  2. 語法 MOD(數字 1,數字2)

  3. 示例程式碼 SELECT MOD(10,3) FROM dual

2.5、日期函式

1、NOW:

  1. 說明 返回伺服器的當前日期和時間(fsp指定小數秒的精度,取值0–6) 格式 ‘YYYY-MM-DD HH:MM:SS’或者‘YYYYMMDDHHMMSS’

  2. 語法格式 NOW([fsp])

  3. 示例程式碼 – 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);

  4. 其它相同的還有 CURRENT_TIMESTAMP CURRENT_TIMESTAMP() LOCALTIMESTAMP LOCALTIMESTAMP() LOCALTIME LOCALTIME()

2、CURTIME

  1. 說明 返回當前時間,只包含時分秒(fsp指定小數秒的精度,取值0–6)

  2. 語法格式 CURTIME([fsp])

  3. 示例程式碼 select curtime() # 01:55:47 select curtime()+0 # 163301 select curtime(2)   # 01:55:47.90

2、CURDATE

  1. 說明 返回當前日期,只包含年月日

  2. 語法格式 CURDATE()

  3. 示例程式碼 select curdate() select curdate()+0

3、選取日期時間的各個部分

  1. 說明 日期、時間、年、季度、月、日、小時、分鐘、秒、微秒

  2. 示例程式碼 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)

  1. 說明 把日期和數字轉換為制定格式的字串。format是格式化字串

  2. 語法格式 date_format(date, format)

  3. 示例程式碼 對日期的處理 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

  4. 附表 值 含義 秒 %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)

  1. 說明 將一個字串變為DATE型資料

  2. 語法格式 str_to_date(str,[,format]) --注意:格式要和字串日期的格式一致才能解析成功。

  3. 示例程式碼 將字串日期轉化為年月日 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

  1. 說明 如果X為空,返回value,否則返回VALUE

  2. 語法格式 NVL(col|字串,VALUE) --相當於三則運算

  3. 示例程式碼 對工資是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、 說明

  1. ALL表示對所有值求和
  2. DISTINCT表示只對不同值求和(相同值只取一次)

2、示例程式碼

  1. 計算僱員姓名為 'SMITH’和 ‘ALLEN’ 兩個人的基本薪資和 SELECT SUM(sal) FROM emp WHERE ename IN(‘SMITH’,‘ALLEN’);

4、 COUNT(統計行數)

1、 說明

  1. ALL對所有記錄,陣列做統計 (預設)
  2. DISTINCT只對不同值統計(相同值只取一次)
  3. COUNT(DISTINCT | ALL 列名) ---------會忽略null值進行統計 或者 COUNT(*) --------------------------------不需要考慮null值問題(開發使用較多)

2、 示例程式碼

  1. 顯示emp表中的總條資料 SELECT COUNT(*) FROM emp
  2. 統計 emp 職位型別的個數。 SELECT COUNT(DISTINCT job) FROM emp;
  3. 統計 emp 職位為 SALESMAN 的僱員個數 SELECT COUNT(*) FROM emp WHERE job=‘SALESMAN’;
  4. 統計 emp 中 有佣金的僱員的個數 SELECT COUNT(comm) FROM emp;

5、 MAX(求最大值)

1、 說明

  1. ALL表示對所有的值求最大值 (預設)
  2. DISTINCT表示對不同的值求最大值,相同的只取一次

2、 示例程式碼

  1. 查詢所有僱員中最高的薪資 SELECT MAX(sal) FROM emp;
  2. 顯示所有工資不同的員工中工資最高的 SELECT MAX(DISTINCT SAL) FROM EMP;

6、 AVG(求平均值)

1、 說明

  1. ALL表示對所有的值求平均值 ( 預設)
  2. DISTINCT表示對不同的值求最大值,相同的只取一次

2、 示例程式碼

  1. 求所有員工工資的平均值 SELECT (sal) FROM emp;
  2. 求不重複的員工工資的平均值 SELECT AVG(DISTINCT sal) FROM emp;

7、MIN(求最小值)

1、 說明

  1. ALL表示對所有的值求最小值( 預設)
  2. DISTINCT表示對不同的值求最小值,相同的只取一次

2、 示例程式碼

  1. 員工編號最小值 SELECT min(empno) FROM emp
  2. 查詢工資最低的 SELECT MIN(sal) FROM emp
  3. 查詢年薪最低的 SELECT * ,MIN((NVL2(comm,comm+sal,comm)*12 ) FROM emp

2.7 、注意事項

  1. 分組函式只能出現在select 列、having、order by子句中(不能出現在where後面)
  2. 當使用分組函式時,除了函式count(*)外,其他分組函式都會忽略NULL行。

2.8、單行函式和聚合函式的區別

  1. 單行函式操作時,根據函式的功能同時處理一行資料,返回每一行的處理結果;
  2. 聚合函式同時對分組後的一組行進行操作,返回分組後各組的處理結果

四、分組統計查詢

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、示例程式碼

  1. 查詢每個部門的人數 SELECT deptno ,COUNT(*) FROM emp GROUP BY deptno;
  2. 顯示每個部門員工的平均工資 SELECT deptno ,AVG(sal) 平均工資 FROM emp GROUP BY deptno;
  3. 顯示各個部門員工的工資+獎金 SELECT deptno,SUM(sal + IFNULL(comm,0)) FROM emp GROUP BY deptno;
  4. 按照部門編號分組,求出每個部門的人數,平均工資(要求擷取2位)(配合單行函式使用) SELECT deptno, COUNT(empno), ROUND(AVG(sal),2) FROM emp GROUP BY deptno;
  5. 按照職位分組,求出每個職位的最高和最低工資(單欄位分組) SELECT job, MAX(sal), MIN(sal) FROM emp GROUP BY job;
  6. 查詢每個部門的每種崗位的平均工資和最低工資 SELECT AVG(sal), MIN(sal) FROM emp GROUP BY deptno;
  7. 先統計出各個職位(job)的平均工資(AVG),再統計平均工資最高的工資(分組函式巢狀) SELECT MAX(AVG(sal)) FROM emp GROUP BY job 注意:分組函式允許巢狀,但是巢狀之後的分組函式的查詢之中不能再出現任何的其他欄位
  8. 查詢每個崗位的總工資但不包括’SALESMAN’崗位(配合Where使用) SELECT FROM emp WHERE name !=‘SALESMAN’
  9. 按部門、不同的職位,統計員工的工資總額 (多欄位統計) SELECT deptno, job, sum(sal) FROM emp GROUP BY deptno, job;
  10. 查詢各個部門中相同職位的員工人數並且按部門編號排序(多欄位統計排序) SELECT DEPTNO, JOB,COUNT(*) FROM emp GROUP BY deptno,job ORDER BY deptno;
  11. 查詢出每個部門的名稱、部門的人數、平均工資(多表單欄位查詢) 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、注意事項

  1. GROUP BY後不可以接列的別名(根據執行順序分析就知道了) SELECT deptno dn ,AVG(sal) FROM emp GROUP BY dn; --錯誤
  2. GROUP BY 後不能接數字 SELECT deptno dn ,AVG(sal) FROM emp GROUP BY 1; --錯誤
  3. GROUP BY 後不可以接select後沒有的列名 SELECT deptno dn ,AVG(sal) FROM emp GROUP BY job;
  4. 如果一個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中出現
  5. group by之前可以使用where過濾資料,因為where是在分組之前起作用的,(執行順序分析) ----廢話

5、使用HAVING過濾分組

1、說明

  1. 首先對資料行進行分組。
  2. 把所得到的分組應用到分組函式中。
  3. 最後顯示滿足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、示例程式碼

  1. 查詢部門的員工人數大於五部門編號 SELECT deptno,COUNT() FROM emp GROUP BY deptno HAVING COUNT()> 5;
  2. 查詢部門工資總和大於10000的部門編號 SELECT deptno, SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal)>10000;
  3. 查詢平均工資低於2000的部門號和它的平均工資 SELECT deptno,AVG(sal) a FROM emp GROUP BY deptno HAVING avg(sal)>2000;
  4. 查詢每個崗位的總工資並且不包括職位是’SALESMAN’崗位而且工資和大於5000 SELECT SUM(sal) FROM emp WHERE job!=‘SALESMAN’ GROUP BY job HAVING SUM(sal)>5000

6、綜合示例

  1. 查詢非銷售人員工作名稱以及從事同一工作僱員的月工資的總和,並且要滿足從事同一工作的僱員的月工資合計大於$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;

  2. 顯示部門編號不是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、分頁技術分類

  1. 物理分頁(推薦) 在資料庫執行查詢時(實現分頁查詢),查詢需要的資料依賴資料庫SQL語句,屬於後臺分頁
  2. 邏輯分頁 先查詢所有資料到記憶體,再從記憶體擷取需要資料採用程式內部邏輯,屬於前臺分頁

1、說明

Mysql分頁採用 **LIMIT** 關鍵字

2、語法格式

  1. 格式 SELECT * FROM table LIMIT [offset,] rows SELECT * FROM table LIMIT rows OFFSET offset
  2. 說明
    • 第一個引數指定第一個返回記錄行的偏移量
    • 第二個引數指定返回記錄行的最大數目
    • 如果只給定一個引數:它表示返回最大的記錄行數目
    • 第二個引數為 -1 表示檢索從某一個偏移量到記錄集的結束所有的記錄行
    • 初始記錄行的偏移量是 0(而不是 1)

3、示例程式碼

  1. 查詢6-10條資料 SELECT * FROM table LIMIT 5,5; – 檢索記錄行 6-10 條資料
  2. 查詢從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個引數為 -1 SELECT * FROM emp LIMIT 5,-1; – 檢索記錄行 6-最後一條.
  3. 查詢前 5 條記錄 SELECT * FROM emp LIMIT 5 – LIMIT n 等價於 LIMIT 0,n
  4. 返回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、案例分析

  1. 同時查詢emp和dept表 SELECT * FROM emp; SELECT * FROM dept; SELECT * FROM emp,dept;
  2. 分析 發現emp14條,dept表4條。但返回了56條資料56=14*4

3、如何避免笛卡爾積

唯一的方案就是在WHERE字句中加入有效的關聯欄位,
  1. 示例程式碼 SELECT * FROM emp e,dept d WHERE e.deptno=d.deptno;

  2. 說明 1、從查詢的結果看,我們顯示的資料正常了,但僅僅是顯示上去除了笛卡爾,而真正笛卡爾積現在依然存在,因為資料庫的操作機制就屬於逐行的進行資料的判斷,那麼如果按照這個思路理解的話,現在假設兩張表的資料量都很大的話,那麼使用這種多表查詢的效能,無法從根本上解決這個問題 2、在進行多表查詢的時候一定會存在有關聯列,在開發中一般都使用表的主鍵作為關聯表的欄位,名字基本也一樣.這樣方便閱讀和理解 3、如果表之中存在有同名的列,那麼一定要使用“表名稱.欄位名”,或者使用“別名.欄位名“(推薦使用別名,開發中常用)

4、示例程式碼

  1. 查詢每個僱員的編號,姓名,職位,工資,部門名稱,部門位置 分析問題:

    • 確定使用到的資料表
      • emp表(編號,姓名,職位,工資)
      • dept表(部門名稱,部門位置)
    • 確定已知的關聯欄位
      • emp表與dept表的 deptno。 emp.deptno = dept.deptno; 解決問題:
    1. 第一步:查詢出每一位僱員的編號,姓名,職位,工資 SELECT e.empno,e.ename,e.job,e.sal FROM emp e;
    2. 第二步:為查詢中引入部門表,同時需要增加一個消除笛卡爾積的條件 SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc FROM emp e,dept d WHERE e.deptno=d.deptno;
  2. 查詢每個僱員的編號,姓名,職位,工資,工資等級。 分析問題:

    • 確定使用到的資料表
      • emp表(編號,姓名,職位,工資)
      • salgrade表(工資等級)
    • 確定已知的關聯欄位
      • emp 表 sal 與salgrade表的 lasal,hisal。 emp.sal BETWEEN salgrade.losal AND salgrade.hisal; 解決問題:
    1. 第一步:查詢出每一位僱員的編號,姓名,職位,工資 SELECT e.empno,e.ename,e.job,e.sal FROM emp e;
    2. 第二步:為查詢中引入工資等級表,同時需要增加一個消除笛卡爾積的條件 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;
  3. 查詢每個僱員的編號,姓名,職位,工資,工資等級,部門名稱。 分析問題:

    • 確定使用到的資料表
      • emp表(編號,姓名,職位,工資)
      • salgrade表(工資等級)
      • dept表(部門名稱)
    • 確定已知的關聯欄位
      • emp表與dept表的 deptno。 emp.deptno = dept.deptno;
      • emp 表 sal 與salgrade表的 lasal,hisal。 emp.sal BETWEEN salgrade.losal AND salgrade.hisal; 解決問題:
    1. 第一步:查詢出每個僱員的編號、姓名、基本工資、職位、工資 SELECT e.empno,e.ename,e.job,e.sal FROM emp e;
    2. 第二步:引入工資等級表,同時增加一個消除笛卡爾積的條件 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;
    3. 第三步:引入部門表,繼續增加消除笛卡爾積的條件 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、定義

  1. 指嵌入在其他sql語句中的select語句
  2. 通俗的來講指的是在一個查詢之中嵌入若干個小的查詢
  3. 子查詢可以出現在查詢語句的(9i中除ORDER BY語句)任意位置上,但是實際開發運用中,子查詢出現在WHERE和FROM子句之中較多。

2 、核心作用

子查詢的出現主要是為了解決多表查詢之中的效能問題。

3 、分類

  1. 巢狀查詢(標準子查詢) 指子查詢可以脫離主查詢獨立執行
  2. 關聯查詢(相關子查詢) 關聯子查詢就是指子查詢與主查詢之間有條件關聯,關聯子查詢會引用外部查詢中的一列或多列。這種子查詢之所以被稱為關聯子查詢,是因為子查詢的確與外部查詢有關。當問題的答案需要依賴於外部查詢中包含的每一行中的值時,通常就需要使用關聯子查詢。

筆記:關聯子查詢(相關子查詢):子查詢不可以脫離主查詢獨立執行

4 、FROM中使用子查詢

1、說明

如果在 FROM 子句裡面出現的子查詢,其返回的結果一般都是多行多列資料(相當於表)。

2、示例程式碼

  1. 範例:查詢出每個部門的編號、名稱、位置、部門人數、平均工資 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子句,但是又不能直接使用統計函式的時候,就在子查詢中統計資訊,即:有複雜統計的地方大部分都需要子查詢。
  2. 查詢比本部門平均工資高的員工的姓名,部門編號,工資及平均工資 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
  3. 查詢出部門名稱,部門的員工數,部門的平均工資,部門的最低收入僱員的姓名 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;