學習中的思考 在 mysql 學習和使用中,我遇到了不少的難題,我覺得我應該形成一套邏輯思考體系,可以讓我在初識 mysql 的過程中加入理性思考,從一開始就探求原理,瞭解所學內容的核心和關鍵點,做到一葉知秋而不是只見樹木不見森林。 mysql 幾種數據類型的底層是如何存儲的,不同的 sql 語句對 ...
學習中的思考
在 mysql 學習和使用中,我遇到了不少的難題,我覺得我應該形成一套邏輯思考體系,可以讓我在初識 mysql 的過程中加入理性思考,從一開始就探求原理,瞭解所學內容的核心和關鍵點,做到一葉知秋而不是只見樹木不見森林。
- mysql 幾種數據類型的底層是如何存儲的,不同的 sql 語句對其有何限制?
- 學習 sql 語句時,需要思考:這個 sql 語句的底層是如何實現的,對哪些數據類型起作用,有什麼限制,如果這個 sql 語句對單欄位可以使用,可否在多欄位中使用,在多欄位使用的過程中,可否做到只對一個欄位起作用或者對多個欄位同時起作用?
- 隔離級別是如何實現的?
MySQL
基礎
一、為什麼要學習資料庫
二、資料庫的相關概念:
- DB:資料庫(database),存儲數據的“倉庫”,它保存了一系列有組織的數據。
- DBMS:資料庫管理系統(Database Management System),資料庫是通過 DBMS 創建和操作的容器。
SQL
:結構化查詢語言(Structure Query Language),專門用來與資料庫通信的語言。
SQL
的優點:
- 不是某個特定資料庫供應商專有的語言,幾乎所有DBMS都支持 SQL 。
- 簡單易學。
- 強有力,靈活使用。
三、資料庫存儲結構的特點:
- 將數據放到表中,表再放到庫中。
- 一個資料庫可以有多個表,每個表都有一個名字,用來表示自己。表名具有唯一性。
- 表具有一些特定,這些特定定義了數據在表中如何存儲,類似 java 中“類”的設計。
- 表由列組成,我們也稱為欄位。所有表都是由一個或多個列組成的,每一列類似 java 中的“屬性”。
- 表中的數據都是按行存儲的,每一行類似與 java 中的“對象”。
四、初識MySQL
MySQL
產品的介紹
DBMS分為兩類:
- 基於共用文件系統的DBMS(Access)
- 基於客戶機-伺服器的DBMS(
MySQL
、Oracle、SqlServer
)
MySQL
產品的安裝
MySQL
安裝
MySQL
卸載
-
控制面板卸載
-
安裝路徑刪除
mysql
文件夾 + 刪除 C 盤根目錄下ProgramData
下mysql
文件夾; -
清理註冊表:
A. HKEY_LOCAL_MAACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL 目錄
B. HKEY_LOCAL_MAACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application\MySQL 目錄
C. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL 目錄
D. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControl001\Services\MYSQL 目錄
E. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControl002\Services\MYSQL 目錄
F. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControlSet\Services\MYSQL 目錄
- 刪除
C:\Document and Settings\All Users\Application Data\MySQL
目錄(隱藏的目錄)
MySQL
服務的啟動和停止
-
方式一:電腦 -> 管理 -> 服務
-
方式二:命令行(管理員)
net start 服務名(啟動服務)
net stop 服務名(停止服務)
MySQL
服務端的登錄和退出
-
方式一:通過
mysql
自帶的客戶端;只限於 root 用戶 -
方式二:通過 windows 自帶的客戶端
登錄:
mysql [-h 主機名 -P 埠號] -u 用戶名 -p密碼
退出:
exit 或者 ctrl + c
MySQL
常見的命令
-
查看當前所有資料庫
show databases;
-
打開指定的庫
use 庫名;
-
查看當前庫的所有表
show tables;
-
查看其它庫的所有表
show tables from 庫名;
-
查看目前位於哪個庫
select database();
-
創建表
create table 表名(
列名 列類型,
列名 列類型,
......
);
-
查看表結構
desc 表名
; -
查看伺服器的版本
- 方式一:登錄到
mysql
伺服器select version()
; - 方式二:沒有登錄到
mysql
伺服器mysql --version
MySQL
語法規範
-
不區分大小寫,但建議關鍵字大寫,表名、列名小寫。
-
每條命名最好用分號或 \G、\g 結尾(會格式化輸出數據)
-
每條命令根據需要,可以進行縮進或換行。
-
註釋
- 單行註釋:# 註釋文字
- 單行註釋:-- 註釋文字
- 多行註釋:/* 註釋文字 */
- 試說出查詢語句中涉及到的所有關鍵字,以及執行先後順序
SELECT 查詢列表 7
FROM 表1 別名 第1步
連接類型 join 表2 2
ON 連接條件 3
WHERE 篩選條件 4
GROUP BY 分組列表 5
HAVING 分組後的篩選 6
ORDER BY 排序列表 8
LIMIT 偏移,條目數; 9
五、DQL
(Data Query Language)語言的學習
基礎查詢
語法:
SELECT 查詢列表 FROM 表名;
特點:
1.查詢列表可以是:表中的欄位、常量值、表達式、函數;
2.查詢的結果是一個虛擬的表格;查詢表中的某個欄位
- 查詢表中的所有欄位
> 方式一:
SELECT `employee_id`,
`first_name`,
FROM
employees;
> 方式二:
SELECT * FROM employees;
- 查詢常量值
SELECT 100;
SELECT 'john'; //字元和日期型的常量值必須用單引號,數值型不需要;
- 查詢表達式
SELECT 100*99;
- 查詢函數
SELECT VERSION();
SELECT 函數名(實參列表);
- 起別名
- 便於理解;
- 如果要查詢的欄位有重名的情況,使用別名可以區分開來;
- 如果別名中含有關鍵詞,用 單引號 或者 雙引號 將別名括起來;
方式一:使用 AS
SELECT 100%98 AS 結果;
SELECT last_name AS 姓, first_name AS 名 FROM employees;
方式二:使用空格
SELECT last_name 姓,first_name 名 FROM employees;
-
去重
distinct
-
DISTINCT 需要放到所有列名的前面。
-
DISTINCT 其實對後面所有列名的 組合 進行去重。
SELECT DISTINCT 欄位名 FROM 表名;
案例:查詢員工表中涉及到的所有部門編號
SELECT DISTINCT department_id FROM employees;
concat
函數:和null
拼接結果為null
案例:查詢員工名和姓連接成一個欄位,並顯示為 姓名
SELECT
CONCAT(last_name,first_name) AS 姓名
FROM
employees;
案例:顯示出表employee的全部列,各個列之間用逗號連接,列頭顯示成OUT_PUT
SELECT
CONCAT(`first_name`,',',`last_name`,',',`job_id`,',',IFNULL(commission_pct,0)) AS out_put
FROM
employees;
ifnull
函數
功能:判斷某欄位或表達式是否為null,如果為null,返回指定值,否則返回原本的值
SELECT ifnull(commissiop_pct,0) from employees;
空值參與運算
-
所有運算符或列值遇到 null 值,運算的結果都為 null。
-
在 MySQL 裡面, 空值不等於空字元串。一個空字元串的長度是 0,而一個空值的長度是空。而且,在 MySQL 裡面,空值是占用空間的。
運算符
算數運算符
- 加法與減法運算符
mysql
中的加號,只有一個功能:運算符,做加法運算。
SELECT 100+90; 兩個操作數都為數值型,則做加法運算
SELECT '123'+90;只要其中一方為字元型,試圖將字元型數值轉成數值型,
如果轉換成功,則繼續做加法運算。
如果轉換失敗,則將字元型數值轉換成0
SELECT null+10; 只要其中一方為null,則結果肯定為null
- 乘法與除法運算符
-
一個數乘以整數1和除以整數1後仍得原數;
-
個數乘以浮點數1 和除以浮點數1後變成浮點數,數值與原數相等;
-
一個數除以整數後,不管是否能除盡,結果都為一個 浮點數;
-
一個數除以另一個數,除不盡時,結果為一個浮點數,並保留到小數點後4位;
-
乘法和除法的優先順序相同,進行先乘後除操作與先除後乘操作,得出的結果相同。
-
在數學運算中,0不能用作除數,在MySQL中,一個數除以0為NULL。
- 求模(求餘)運算符
結果的符號與被模數的符號一致。
比較運算符
比較運算符用來對錶達式左邊的操作數和右邊的操作數進行比較,比較的結果為真則返回1,比較的結果為假則返回0,其他情況則返回 NULL。
- 等號運算符
-
如果等號兩邊的值一個是整數,另一個是字元串,則MySQL會將字元串轉化為數字進行比較。
-
如果等號兩邊的值、字元串或表達式中有一個為NULL,則比較結果為NULL。
-
使用安全等於運算符時,兩邊的操作數的值都為NULL時,返回的結果為1而不是NULL,其他返回結果與等於運算符相同。
- 不等於運算符
-
LEAST(值1,值2,...,值n):在有兩個或多個參數的情況下,返回最小值。當比較值列表中有NULL時,不能判斷大小,返回值為NULL。
-
GREASTEST:最大值運算符。
邏輯運算符
-
邏輯非運算符 邏輯非(NOT或!)運算符表示當給定的值為0時返回1;當給定的值為非0值時返回0;當給定的值為NULL時,返回NULL。
-
邏輯與運算符 邏輯與(AND或&&)運算符是當給定的所有值均為非0值,並且都不為NULL時,返回1;當給定的一個值或者多個值為0時則返回0;否則返回NULL。
-
邏輯或運算符 邏輯或(OR或||)運算符是當給定的值都不為NULL,並且有任何一個值為非0值時,則返回1,否則返回0;當一個值為NULL,並且另一個值為非0值時,返回1,否則返回NULL;當兩個值都為NULL時,返回NULL。
-
邏輯異或運算符 邏輯異或(XOR)運算符是當給定的值中任意一個值為NULL時,則返回NULL;如果兩個非NULL的值都是0或者都不等於0時,則返回0;如果一個值為0,另一個值不為0時,則返回1。
-
AND 的優先順序高於OR。
位運算符
條件查詢
-
語法:
SELECT 查詢列表 FROM 表名 WHERE 篩選條件;
-
分類:
-
按條件表達式篩選
條件運算符: > < = != <> >= <= <=>
-
按邏輯表達式篩選
邏輯運算符:
&&
||
!
and
or
not
&& 和 and:兩個條件都為 true,結果為 true,反之為 false;
|| 和 or:只要有一個條件為 true,結果為 true;
-
模糊查詢
like
between and
in
is null / is not null
-
- 按條件表達式篩選
#案例1:查詢工資>12000的員工信息
SELECT
*
FROM
employees
WHERE
salary>120000;
#案例2:查詢部分編號不等於90的員工名和部門編號
SELECT
last_name,
department_id
FROM
employees;
WHERE
department_id<>90;
- 按邏輯表達式篩選
#案例一:查詢工資在10000到20000之間的員工名、工資以及獎金
SELECT
last_name,
salary,
commission_pct
FROM
employees
WHERE
salary >= 10000
AND
salary <= 20000
- 模糊查詢
-
like
一般和通配符搭配使用,可以判斷 字元型 或 數值型;
通配符:
%s
任意多個字元,_
任意單個字元#案例1:查詢員工名中包含符a的員工信息 SELECT * FROM employees WHERE last_name LIKE '%a%'; #案例2:查詢員工名中第三個字元為e,第五個字元為a的員工名和工資 SELECT last_name, salary, FROM employees WHERE last_name LIKE '__e_a%'; #案例3:查詢員工名中第二個字元為_的員工名 SELECT last_name FROM employees WHERE last_name LIKE '_\_%'; 或者 last_name LIKE '_$_%' ESCAPE '$';
-
between and
- 使用 between and 可以提高語句的簡介度;
- 包含 臨界值;
- 兩個臨街值 不要 調換順序;
案例1:查詢員工編號在100到120之間的員工信息 SELECT * FROM employees WHERE employee_id BETWEEN 100 AND 120;
-
in
含義:判斷某欄位的值是否屬於 in 列表中的某一項;
- 使用 in 提高語句簡介度;
- in 列表的值類型必須一致或相容;
- 不支持通配符;
案例:查詢員工的工種編號是 IT_PROG、AD_VP、AD_PRES中的一個員工名和工種編號。 SELECT last_name, job_id FROM employees WHERE job_id IN ('IT_PROT','AD_VP','AD_PRES');
-
is null
判斷某欄位或表達式是否為 null,如果是,則返回1,否則返回0。
- = 或 <> 不能用於判斷 null 值;
- is null 或 is not null 可以判斷null值;
案例1:查詢沒有獎金的員工名和獎金率 SELECT last_name, commission_pct FROM employees WHERE commission_pct IS NULL; IS NOT NULL
-
安全等於
<=>
案例1:查詢沒有獎金的員工名和獎金率 SELECT last_name, commision_pct FROM employees WHERE commission_pct <=> NULL; 案例2:查詢工資為12000的員工名和獎金率 SELECT last_name, commision_pct FROM employees WHERE salary <=> 12000;
-
is null
pk<=>
- IS NULL:僅僅可以判斷NULL值,可讀性較高,建議使用;
- <=>:既可以判斷 NULL 值,又可以判斷普通的數值,可讀性較低。
-
經典面試題:
試問,select * from employees;和select * from employees where commission_pct like '%%' and last_name like '%%';結果是否一樣?並說明原因。
答:不一樣。如果判斷的欄位有null值。
排序查詢
語法:
SELECT 查詢列表
FROM 表
[WHERE 篩選條件]
order by 排序列表 [asc/desc]
特點:
-
asc 代表的是升序,desc 代表的是降序;如果不寫,預設是升序。
-
order by 子句中可以支持單個欄位、多個欄位、表達式、函數、別名。
-
order by 後面的列必須是在 select 後面存在的。
-
order by 子句一般是放在查詢語句的最後面,limit 子句除外。
-
可以使用列的別名進行排序,但別名只能在 order by 中使用,不能在 WHERE 中使用。
#案例1:查詢愚弄信息,要求工資從高到低排序
SELECT * FROM employees
ORDER BY salary DESC;
#案例2:查詢部門編號>=90的員工信息,按入職時間的先後順序進行排序
SELECT *
FROM employees
WHERE department_id>=90
ORDER BY hiredate ASC;
#案例3:按年薪的高低顯示員工的信息和年薪[按表達式排序]
SELECT *,salary*12*(1+IFNULL(commission_prt,0)) 年薪
FROM employees
ORDER BY salary*12*(1+IFNULL(commission_prt,0)) DESC; 或 ORDER BY 年薪 DESC;
#案例5:按姓名的長度顯示員工的姓名和工資[按函數排序]
SELECT LENGTH(last_name) 位元組長度,last_name,salary
FROM employees
ORDER BY LENGTH(last_name) DESC;
#案例6:查詢員工信息,要求先按工資升序,再按員工編號降序[按多個欄位排序]
SELECT *
FROM employees
ORDER BY salary ASC,employee_id DESC;
常見函數
select 函數名(實參列表) [from 表]
(1) 單行函數
concat、length、ifnull等
(2) 分組函數
做統計使用,又稱為統計函數、聚合函數、組函數
單行函數
-
操作數據對象
-
接受參數返回一個結果
-
只對一行進行變換
-
每行返回一個結果
-
可以嵌套
-
參數可以是一列或一個值
字元函數
註意:MySQL中,字元串的位置是從1開始的。
函數 | 作用 |
---|---|
ASCII(S) | 返回字元串 S 中的第一個字元的 ASCII 碼值 |
CHAR_LENGTH(s) | 返回字元串s的字元數。作用與CHARACTER_LENGTH(s)相同 |
LENGTH(s) | 返回字元串s的個數,和字元集有關 |
CONCAT(s1,s2,...,sn) | 連接s1,s2,......sn 為一個字元串 |
CONACT_WS(x,s1,s2,......,sn) | 同CONCAT(s1,s2,...)函數,但是每個字元串之間要加上x |
INSERT(str,idx,len,replacestr) | 將字元串str從第idx位置開始,len個字元長的子串替換為字元串replacestr |
REPLACE(str,a,b) | 用字元串b替換字元串str中所有出現的字元串a |
UPPER(s) 或 UCASE(s) | 將字元串s的所有字母都轉換成大寫字母 |
LOWER(s) 或 LCASE(s) | 將字元串s的所有字母都轉成小寫字母 |
LEFT(str,n) | 返回字元串str最左邊的n個字元 |
RIGHT(str,n) | 返回字元串str最右邊的n個字元 |
LPAD(str,len,pad) | 用字元串pad對str最左邊進行填充,直到str的長度為len個字元 |
RPAD(str,len,pad) | 用字元串pad對str最右邊進行填充,直到str的長度為len個字元 |
LTRIM(s) | 去掉字元串s左側的空格 |
RTRIM(s) | 去掉字元串s右側的空格 |
TRIM(s) | 去掉字元串s開始與結尾的空格 |
TRIM(s1 FROM s) | 去掉字元串s開始與結尾的s1 |
TRIM(LEADING s1 FROM s) | 去掉字元串s開始處的s1 |
TRIM(TRAILING s1 FROM s) | 去掉字元串s結尾處的s1 |
REPEAT(str,n) | 返回str重覆n次的結果 |
SPACE(n) | 返回n個空格 |
STRCMP(s1,s2) | 比較字元串s1,s2的ASCII碼值的大小 |
SUBSTR(s,index,len) | 返回從字元串s的index位置其len個字元,作用與SUBSTING(s,n,len)相同 |
LOCATE(substr,str) | 返回字元串 substr 在字元串 str 中首次出現的位置,作用與 POSITION(substr IN str)、INSTR(str,substr) 相同。未找到,返回0 |
ELT(m,s1,s2,......,sn) | 返回指定位置的字元串,如果m=1,則返回s1,如果m=2,則返回s2,如果m=n,則返回sn |
FIELD(s,s1,s2,...,sn) | 返回字元串s在字元串列表中第一次出現的位置 |
FIND_IN_SET(s1,s2) | 返回字元串s1在字元串s2中出現的位置。其中,字元串s2是一個以逗號分隔的字元串 |
REVERSE(s) | 返回s反轉後的字元串 |
NULLIF(value1,value2) | 比較兩個字元串,如果value1與value2相等,則返回NULL,否則返回value |
-
length()
:獲取參數值的位元組個數SELECT LENGTH('張三豐hahaha'); SHOW VARIVALE LIKE '%char%'; 查看字元集
-
concat()
:拼接字元串SELECTV CONCAT(last_name,'_',first_name) 姓名 FROM employees;
-
upper()
、lower()
-
substr()
、substring()
:註意:索引從1開始
# 截取從指定索引處後面所有字元 SELECT SUBSTR('李莫愁愛上了路站元',7) out_put; # 截取從指定所引處指定字元長度的字元 SELECT SUBSTR('李莫愁愛上了路站元',1,3) out_put; #案例:姓名中首字元大寫,其他字元小寫,然後用 _ 拼接,顯示出來 SELECT CONTACT(UPPER(SUBSTR(last_name,1,1)),LOWER(SUBSTR(last_name),2)) out_put;
-
instr()
:返回字串第一次出現的索引,如果找不到返回0 -
trim()
:SELECT TRIM('a' FROM 'aaaaa張aa翠山aaaaaa') AS out_put;
-
lpad()
:用指定的字元實現左填充指定長度SELECT LPAD('殷素素',10,'*') AS out_put; //10為總字元數 SELECT LPAD('殷素素',2,'*') AS out_put; //殷素
-
rpad()
:用指定的字元實現右填充指定長度SELECT RPAD('殷素素',12,'ab') AS out_put;
-
replace()
:替換
數學函數
-
round()
:四捨五入SELECT ROUND(1.65); SELECT ROUND(1.567,2); // 1.57
-
ceil()
:向上取整,返回 >= 該參數的最小整數 -
floor()
:向下取整,返回 <= 該參數的最大整數 -
truncate()
:截斷SELECT TRUNCATE(1.6999,1); //1.6
-
mod()
:取餘mod(a,b) = a-a/b*b
-
rand()
:獲取隨機數,返回 0-1 之間的小數
日期函數
-
now()
:返回當前系統日期+時間SELECT NOW();
-
curdate()
:返回當前系統日期,不包含時間curtime()
:返回當前時間,不包含日期 -
可以獲取指定的部分,年、月、日、小時、分鐘、秒
SELECT YEAR(now()); SELECT YEAR('1998-1-1') 年;
-
str_to_date
:將日期格式的字元轉換成指定格式的日期STR_TO_DATE('9-13-1999','%m-%d-%Y') 1999-09-13
-
date_format
:將日期格式轉換成字元DATE_FORMAT('2018/6/6','%Y年%m月%d日') 2018年06月06日
-
year()、month()、day()、hour()、minute()、second()
-
datediff()
:返回兩個日期相差的天數 -
monthname()
:以英文形式返回月
其他函數
SELECT VERSION();
SELECT DATABASE();
SELECT USER();
SELECT password('字元'):返回該字元的密碼形式 自動加密
MD5('字元'):返回該字元的md5加密形式
流程式控制制函數
-
if 函數:if else 的效果
if(條件表達式,表達式1,表達式2):如果條件表達式成立,返回表達式1;否則返回表達式2
SELECT last_name,commission_pct,IF(commission_pct IS NULL,'沒獎金,呵呵','有獎金,嘻嘻') 備註 FROM employees;
-
case函數的使用一:switch case 的效果
case 要判斷的欄位或表達式 when 常量1 then 要顯示的值1或語句1; when 常量2 then 要顯示的值2或語句2; ... else 要顯示的值n或語句n; end
#案例:要查詢員工的工資,要求 部門號=30,顯示的工資為1.3倍 部門號=40,顯示的工資為1.4倍 部門號=50,顯示的工資為1.5 倍 其他部門,顯示的工資為原工資 SELECT salary 原始工資,department_id, CASE department_id WHEN 30 THEN salary*1.3 WHEN 40 THEN salary*1.4 WHEN 50 THEN salary*1.5 ELSE salary END AS 新工資 FROM employees;
-
case 函數的使用二:類似於 多重if
case when 條件1 then 要顯示的值1或語句1 when 條件2 then 要顯示的值2或語句2 ... else 要顯示的值n或語句n end
#案例:查詢員工的工資的情況 如果工資 > 20000,顯示A級別 如果工資 > 15000,顯示B級別 如果工資 > 10000,顯示C級別 否則,顯示D級別 SELECT salary, CASE WHEN salary>20000 THEN 'A' WHEN salary>15000 THEN 'B' WHEN salary>10000 THEN 'C' ELSE 'D' END AS 工資級別 FROM employees;
加密與解密函數
函數 | 用法 |
---|---|
PASSWORD(str) | 返回字元串str的加密版本,41位長的字元串。加密結果不可逆,常用語用戶的密碼加密。在mysql8.0中被棄用。 |
MD5(str) | 返回字元串str的md5加密後的值,也是一種加密方式。若參數為NULL,則會返回NULL。不可逆。 |
SHA(str) | 從原明文密碼str計算並返回加密後的密碼字元串,當參數為 NULL 時,返回 NULL。不可逆。 |
ENCODE(value,password_seed) | 返回使用 password_seed 作為加密密碼加密value。mysql8.0後被棄用。 |
DECODE(value,password_seed) | 返回使用password_seed作為加密密碼解密value |
mysql 信息函數
函數 | 用法 |
---|---|
VERSION() | 返回當前MySQL的版本號 |
CONNECTION_ID() | 返回當前MySQL伺服器的連接id |
DATABASE(),SCHEMA() | 返回MySQL命令行當前所在的資料庫 |
USER(),CURRENT_USER()、SYSTEM_USER(), SESSION_USER() | 返回當前連接MySQL的用戶名,返回結果格式為 “主機名@用戶名” |
CHARSET(value) | 返回字元串value自變數的字元集 |
COLLATION(value) | 返回字元串value的比較規則 |
其他函數
函數 | 用法 |
---|---|
FORMAT(value,n) | 返回對數字value進行格式化後的結果數據。n表示 四捨五入 後保留到小數點後n位 |
CONV(value,from,to) | 將value的值進行不同進位之間的轉換 |
INET_ATON(ipvalue) | 將以點分隔的IP地址轉化為一個數字 |
INET_NTOA(value) | 將數字形式的IP地址轉化為以點分隔的IP地址 |
BENCHMARK(n,expr) | 將表達式expr重覆執行n次。用於測試MySQL處理expr表達式所耗費的時間 |
CONVERT(value USING char_code) | 將value所使用的字元編碼修改為char_code |
分組函數
-
功能:用作統計使用,又稱為聚合函數或統計函數或組函數。輸入的是一組數據的集合,輸出的是單個值。
-
分類:sum 求和、 avg 平均值、 max 最大值、 min 最小值、 count 計算個數;
-
特點:
-
sum、avg一般用於處理數值型;max、min、count 可以處理任何類型;
-
以上分組函數都忽略 null 值;
-
可以和 distinct 搭配實現去重的運算;
```sql
SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;
```
- count函數的詳細介紹,一般使用 COUNT(*) 統計行數;
```sql
SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees; //只要某一行有一個不為null,就相當於+1(不包含NULL值)
SELECT COUNT(1) FROM employees; //統計1的個數,相當於計算行數
效率:
如果使用的是 MyISAM 存儲引擎,則三者效率相同,都是O(1)
如果使用的是 InnoDB 存儲引擎,則三者效率:COUNT(*) = COUNT(1) > COUNT(欄位)
```
- 和分組函數一同查詢的欄位要求是 group by 後面的欄位;
```
SELECT AVG(salary),employee_id FROM employees; 有問題,AVG(salary)只有一行,employee_id有很多行
```
分組查詢
- 語法
#執行順序
SELECT column,group_function(column) 5
FROM table 1
[WHERE condition] 2
GROUP BY group_by_expression 3
[HAVING 分組後的篩選] 4
[ORDER BY column]; 6
-
明確:WHERE 一定放在 FROM 後面;
-
註意:查詢列表必須特殊,要求是分組函數和 group by 後出現的欄位;
-
當使用 ROLLUP 時,不能同時使用 ORDER BY 子句進行結果排序,即 ROLLUP 和 ORDER BY 是互相排斥的。
為了更好的理解 grouy by 多個列和聚合函數的應用,我們可以假設在group by執行之後,生成了一個虛擬的中間表。相同的group by欄位合併成一行,其餘的欄位分別寫到一個單元格裡。
對於id和number裡面的單元格有多個數據的情況,使用聚合函數。聚合函數就是用來輸入多個數據,輸出一個數據的。
#對name欄位進行分組
id name number
1 aa 2
2 3
3 4
4 bb 5
8 6
-
特點:
-
分組查詢中的篩選條件分為兩類:
```
數據源 位置 關鍵字
分組前篩選 原始表 group by子句的前面 where
分組後篩選 分組後的結果集 group by子句的後面 having
```
-
group by 子句支持單個欄位分組,多個欄位分組(多個欄位之間用逗號隔開,沒有順序要求),表達式或函數(用的較少);
-
也可以添加排序(排序放在整個分組查詢的最後);
-
從 mysql8.0 開始,group by不再支持隱式排序。
-
當 group by 這列有 null 值時,group 會把他們當成是同一個直接聚合。
-
如果過濾條件中使用了聚合函數,則必須使用 HAVING 來替換 WHERE。否則,報錯。
-
案例:
#案例1:查詢每個工種的最高工資
SELECT MAX(salary),job_id
FROM employees
GROUP BY job_id;
#案例2:查詢每個位置上的部門個數
SELECT COUNT(*),location_id
FROM employees
GROUP BY location_id;
#案例3:查詢郵箱中包含a字元的,每個部門的平均工資
SELECT AVG(salary),department_id
FROM employees
WHERE email LIKE '%a%'
GROUP BY department_id;
#案例4:查詢有獎金的每個領導手下員工的最高工資
SELECT MAX(salary),manager_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY manager_id;
#案例5:查詢哪個部門的員工個數>2
(1) 查詢每個部門員工個數
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id;
(2) 根據(1)的結果進行篩選,查詢哪個部門的員工個數>2
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>2;
#案例:查詢每個工種有獎金的員工的最高工資>12000的工種編號和最高工資
(1)查詢每個工種有獎金的員工的最高工資
SELECT MAX(salary),job_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id;
(2)根據(1)結果繼續篩選,最高工資>12000
SELECT MAX(salary),job_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING MAX(salary)>12000;
#案例:查詢領導編號>102的每個領導手下的最低工資>5000的領導編號是哪個,以及其最低工資;
(1)查詢每個領導手下的員工最低工資
SELECT MIN(salary),manager_id
FROM employees
GROUP BY manager_id;
(2)添加篩選條件:編號>102
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id > 102
GROUP BY manager_id;
(3)添加篩選條件:最低工資>5000
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id > 102
GROUP BY manager_id
HAVING MIN(salary)>5000;
> 按表達式或函數分組
> 案例:按員工姓名的長度分組,查詢每一組的員工個數,篩選員工個數>5的的有哪些
(1)查詢每個長度的員工個數
SELECT COUNT(*),LENGTH(last_name)
FROM employees
GROUP BY LENGTH(last_name);
(2)添加篩選條件
SELECT COUNT(*),LENGTH(last_name)
FROM employees
GROUP BY LENGTH(last_name)
HAVING COUNT(*)>5;
> 按多個欄位分組
#案例:查詢每個部門每個工種的員工的平均工資
SELECT AVG(salary),department_id,job_id
FROM employees
GROUP BY job_id,department_id;
#添加排序
#案例:查詢每個部門每個工種的員工的平均工資,並且按平均工資的高低顯示
SELECT AVG(salary),department_id,job_id
FROM employees
WHERE department_id IS NOT NULL
GROUP BY job_id,department_id
ORDER BY AVG(salary) DESC;
連接查詢
-
含義:又稱多表查詢,當查詢的欄位來自多個表時;
-
笛卡爾乘積現象:表1有 m 行,表2有 n 行,結果 m*n 行
發生原因:沒有有效的連接條件;
如何避免:添加有效的連接條件;
分類:
- 按年代分類:
sql92標準:僅僅支持內連接
等值
非等值
自連接
也支持一部分外連接(用於 oracle、sqlserver,mysql 不支持)
sql99標準(推薦):支持內連接+外連接(左外和右外)+交叉連接
- 按功能分類:
-
內連接
等值連接
非等值連接
自連接 -
外連接
左外連接
右外連接
全外連接(mysql不支持) -
交叉連接
sql92 標準
等值連接
- 多表等值連接的結果為多表的交集部分;
- n表的連接,至少需要n-1個連接條件;
- 多表的順序沒有要求;
- 一般需要為表起別名;
- 可以搭配前面介紹的所有子句使用,比如排序、篩選、分組;
語法:
SELECT 查詢列表
FROM 表1 別名, 表2 別名
WHERE 表1.key = 表2.key
[AND 篩選條件]
[GROUP BY 分組欄位]
[HAVING 分組後的篩選]
[ORDER BY 排序欄位]
案例:
#案列1:查詢女生名和對應的男生名
SELECT NAME,boyName
FROM boys,beauty
WHERE beauty.boyfriend_id = boys.id;
#案例2:查詢員工名和對應的部門名
SELECT last_name,department_name
FROM employees,departments
WHERE employees.`department_id` = departments.`department_id`;
-
為表起別名
-
提高語句的簡潔度;
-
區分多個重名的欄位;
-
註意:如果為表起了別名,則查詢的欄位就不能使用原來的表名去限定;
#案例:查詢員工名、工種號、工種名
SELECT e.last_name,e.job_id,j.job_title #employees.last_name錯誤
FROM employees AS e,jobs j
WHERE e.`job_id` = j.`job_id`;
-
兩個表的順序可以調換
-
加篩選
#案例:查詢有獎金的員工名、部門名
SELECT last_name,department_name
FROM employees e,departements d
WHERE e.`department_id` = d.`department_id`
AND e.`commission_pct` IS NOT NULL;
#案例2:查詢城市名中第二個字元為o的部門名和城市名
SELECT dapartment_name,city
FROM departments d,location l
WHERE d.`location_id` = l.`location_id`
AND city LIKE `_o%`;
- 加分組
#案例1:查詢每個城市的部門個數
SELECT COUNT(*) 個數,city
FROM departments d,locations l
WHERE d.`location_id` = l.`location_id`
GROUP BY city;
#案例2:查詢有獎金的部門的部門名和部門的領導編號和該部門的最低工資
SELECT department_name,d.`manager_id`,MIN(salary)
FROM dapartment d,employees e
WHERE d.`department_id` = e.`department_id`
AND commission_pct IS NOT NULL
GROUP BY department_name,d.mamager_id;
- 加排序
#案例:查詢每個工種的工種名和員工的個數,並且按員工的個數降序
SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id` = j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;
- 三表連接
#案列:查詢員工名、部門名和所在的城市
SELECT last_name,department_name,city
FROM employees e,department d,location l
WHERE e.`department_id` = d.`department_id`
AND d.`location_id` = l.`location_id`
AND city LIKE 's%'
ORDER BY department_name DESC;
非等值連接
SELECT 查詢列表
FROM 表1 別名, 表2 別名
WHERE 非等值的連接條件
[AND 篩選條件]
[GROUP BY 分組欄位]
[HAVING 分組後的篩選]
[ORDER BY 排序欄位]
#案例1:查詢員工的工資和工資級別
SELECT salary,grade_level
FROM employess e,job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`hightest_sal`
//AND g.`grade_level` = 'A';
自連接
#案例:查詢員工名和上級的名稱
SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.manager_id = m.employee_id;
sql99 語法
SELECT 查詢列表
FROM 表1 別名 [連接類型]
JOIN 表2 別名
ON 連接條件
[WHERE 篩選條件]
[GROUP BY 分組]
[HAVING 篩選條件]
[ORDER BY 排序列表]
內連接:inner
SELECT 查詢列表
FROM 表1 別名
INNER JOIN 表2 別名
ON 連接條件;
分類:等值、非等值、自連接
-
等值連接
特點:
- 添加排序、分組、篩選;
- inner 可以省略;
- 篩選條件放在 where 後面,連接條件放在 on 後面,提高分離性,便於閱讀;
- inner join 連接和 sql92 語法中的等值連接效果是一樣的,都是查詢多表;
#案例1:查詢員工名、部門名 SELECT last_name,department_name FROM employees e INNER JOIN departments d ON e.`department_id` = d.`department_id`; #案例2:查詢員工名字中包含e的員工名和工種名(添加篩選) SELECT last_name,job_title FROM employees e INNER JOIN jobs j ON e.`job_id` = j.`job_id` WHERE e.`last_name` LIKE '%e%'; #案例3:查詢部門個數>3的城市名稱和部門個數(添加分組+篩選) #(1)查詢每個城市部門的個數 #(2)在(1)結果上篩選滿足條件的 SELECT city,COUNT(*) 部門個數 FROM departments d INNER JOIN locations l ON d.`location_id` = l.`location_id` GROUP BY city HAING COUNT(*)>3; #案例4:查詢哪個部門的員工個數>3的部門名和員工個數,並按個數降序(添加排序) #(1)查詢每個部門的員工個數 SELECT COUNT(*),department_name FROM employees e INNER JOIN departments d ON e.`department_id` = d.`department_id` GROUP BY department_name; #(2)在(1)結果上篩選員工個數>3的記錄,併排序 SELECT COUNT(*),department_name FROM employees e INNER JOIN departments d ON e.`department_id` = d.`department_id` GROUP BY department_name HAVING COUNT(*)>3 ORDER BY COUNT(*) DESC; #案例5:查詢員工名、部門名、工種名,並按部門名排序 SELECT last_name,department_name,job_title FROM employees e INNER JOIN departments d ON e.`department_id` = d.`department_id` INNER JOIN jobs j ON e.`job_id`=j.`job_id` ODER BY department_name DESC;
-
非等值連接
#案例1:查詢員工的工資級別 SELECT salary,grade_level FROM employees e JOIN job_grade e ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`; #案例2:查詢工資級別的個數>20的個數,並且按工資級別降序 SELECT COUNT(*),grade_level FROM employees e JOIN job_grade e ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal` GROUP BY grade_level HAVING COUNT(*)>20 ORDER BY grade_level DESC;
-
自連接
#案例:查詢姓名中包含字元k的員工的名字、上級的名字 SELECT e.last_name,m.last_name FROM employees e JOIN employees m ON e.`manager_id` = m.`manager_id` WHERE e.`last_name` LIKE '%k%';
外連接
- 左外: left [outer]
- 右外: right [outer]
- 全外: full [outer]
應用場景:用於查詢一個表中有,另一個表中沒有的記錄;
特點:
- 外連接的查詢結果為主表中的所有記錄;
如果從表中有和它匹配的,則顯示匹配的值;
如果從表中沒有和它匹配的,則顯示 null;
外連接查詢結果=內連接結果 + 主表中有而從表中沒有的記錄;
- 左外連接,left join 左邊的是主表;
右外連接,right join 右邊的是主表;
全外連接,兩邊都是主表。
-
左外和右外交換兩個表的順序,可以實現同樣的效果;
-
全外連接=內連接的結果+表1中有但表2沒有的+表2中有的但表1沒有的;
#案例:查詢男朋友 不在男明星表的女明星名
SELECT b.name,bo.*
FROM beauty b
LEFT OUTERF JOIN boys bo
ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id` IS NULL; //問題:為什麼用boys.id為NULL就可以了呢,實際上的boys表裡的id是主鍵,根本不可能為NULL啊?
#案例1:查詢哪個部門沒有員工
#左外
SELECT d.*,e.employee_id
FROM departments d
LEFT OUTER JOIN employees e
ON d.`department_id`=e.`department_id`
WHERE e.`employee_id` IS NULL;
#案例2:查詢哪個城市沒有部門
SELECT city
FROM department d
RIGHT OUTER JOIN locations l
ON d.location_id = l.location_id
WHERE d.department_id IS NULL;
#案例3:查詢部門為SAL或IT的員工信息
SELECT e.*,d.department_name
FROM departments d
LEFT OUTER JOIN employees e
ON d.department_id = e.department_id
WHERE d.department_name IN ('SAL','IT');
交叉連接:cross
SELECT 查詢列表
FROM 表1 別名
CROSS JOIN 表2 別名;
#特點:類似於笛卡爾乘積
sql99 語法新特性
自然連接
NATURAL JOIN 用來表示自然連接。我們可以把自然連接理解為 SQL92 中的等值連接。它會幫你自動查詢兩張連接表中所有相同的欄位 ,然後進行等值連接 。
#sql92中:
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
AND e.`manager_id` = d.`manager_id`;
#在sql99中可寫成:
SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;
USING 連接
當我們進行連接的時候,SQL99還支持使用 USING 指定數據表裡的 同名欄位 進行等值連接。但是只能配合JOIN一起使用。比如:
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
USING (department_id);
子查詢
含義:出現在其他語句中的 select 語句,稱為子查詢或內查詢;
外部的查詢語句,稱為主查詢或外查詢。
外面的語句可以是 insert、update、delete、select 等,一般 select 作為外面語句較多。
分類:
- 按子查詢出現的位置:
- select 後面:
- 僅僅支持標量子查詢
- from 後面:
- 支持表子查詢
- where 或 having 後面
- 標量子查詢(單行)
- 列子查詢 (多行)
- 行子查詢
- exists 後面(相關子查詢)(返回的結果1或0,類似布爾操作)
- 表子查詢
- 按結果集的行列數不同:
- 標量子查詢(單行子查詢)(結果集是一個數據:一行一列)
- 列子查詢(多行子查詢)(結果集是一列:一列多行):一般搭配著多行操作符使用 in、any/some、 all
- 行子查詢(結果集是一行:一行多列)
- 表子查詢(結果集一般為多行多列)
where 或 haing 後面
- 標量子查詢
- 列子查詢
- 行子查詢
特點:
- 子查詢放在小括弧內
- 子查詢一般放在條件的右側
- 標量子查詢,一般搭配著單行操作符使用 > < >= <= = <>
- 子查詢的執行順序優於主查詢執行,主查詢的條件用到了子查詢的結果
標量子查詢
#案例1:誰的工資比Abel高?
#(1)查詢Abel的工資
SELECT salary
FROM employees
WHERE last_name = 'Abel'
#(2)查詢員工信息,滿足 salary>(1)結果
SELECT *
FROM employees
WHERE salary>(
SELECT salary
FROM employees
WHERE last_name = 'Abel'
);
#案例2:返回job_id與141號員工相同,salary比143號員工多的員工姓名,job_id和工資
#(1)查詢141號員工的job_id
SELECT job_id
FROM employees
WHERE employee_id = 141
#(2)查詢143號員工的salary
SELECT salary
FROM employees
WHERE employee_id = 143
#(3)查詢員工的姓名、job_id和工資,要求job_id=(1)並且salary>(2)
SELECT last_name,job_id,salary
FROM employees
WHERE job_id = (
SELECT job_id
FROM employees
WHERE employee_id = 141
) AND salary > (
SELECT salary
FROM employees
WHERE employee_id = 143
);
#案例3:返回公司工資最少的員工的last_name,job_id和salary
#(1)查詢公司的最低工資
SELECT MIN(salary)
FROM employees;
#(2)查詢last_name,job_id和salary,要求salary=(1)
SELECT last_name,job_id,salary
FROM employees
WHERE salary = (
SELECT MIN(salary)
FROM employees;
);
#案例4:查詢最低工資大於50號部門最低工資的部門id和其最低工資
#(1)查詢50號部門的最低工資
SELECT MIN(salary)
FROM employees
WHERE department_id =50
#(2)查詢每個部門的最低工資
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
#(3)在(2)的基礎上,滿足min(salary)>(1)
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id =50
);
非法使用標量子查詢:
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT salary
FROM employees
WHERE department_id =50
);
列子查詢(多行子查詢)
- 返回多行
- 使用多行比較操作符
操作符 | 含義 |
---|---|
IN / NOT IN | 等於列表中的任意一個 |
ANY | SOME | 和子查詢返回的某一個值比較 |
ALL | 和子查詢返回的所有值比較 |
#案例1:返回 location_id 是 1400 或 1700 的部門中所有員工姓名
#(1)查詢location_id是1400或1700的部門編號
SELECT DISTINCT department_id
FROM departments
where location_id IN(1400,1700)
#(2)查詢員工姓名,要求部門號是(1)列表中的某一個
SELECT last_name
FROM employees
WHERE deapartment_id IN(
SELECT DISTINCT department_id
FROM departments
where location_id IN(1400,1700)
);
#案例2:查詢其它工種中比job_id為`IT_PROG`工種任一工資低的員工的員工號、姓名、job_id 和 salary
#(1)查詢job_id為`IT_PROG`部門任一工資
SELECT DISTINCT salary
FROM employees
WHERE job_id='IT_PROG'
#(2)查詢員工號、姓名、job_id以及salary,salary<(1)的任意一個
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary < ANY(
SELECT DISTINCT salary
FROM employees
WHERE job_id='IT_PROG'
)AND job_id<>'IT_PROG';
或
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary < (
SELECT MAX(salary)
FROM employees
WHERE job_id='IT_PROG'
)AND job_id<>'IT_PROG';
行子查詢(結果集一行多列或多行多列)
#案例:查詢員工編號最小且工資最高的員工信息
#(1)查詢最小的員工編號
SELECT MIN(employee_id)
FROM employees
#(2)查詢最高工資
SELECT MAX(salary)
FROM employees
#(3)查詢員工信息
SELECT *
FROM employees
WHERE employee_id=(
SELECT MIN(employee_id)
FROM employees
)AND salary=(
SELECT MAX(salary)
FROM employees
);
SELECT *
FROM employees
WHERE (employee_id,salary)=(
SELECT MIN(employee_id),MAX(salary)
FROM employees
);
select後面:僅僅支持標量子查詢
#案例1:查詢每個部門的員工個數
SELECT d.*,(
SELECT COUNT(*)
FROM employees
WHERE e.department_id = d.`department_id`
) 個數
FROM departments d;
#案例2:查詢員工號=102的部門名
SELECT (
SELECT department_name
FROM departments d
INNER JOIN employees e
ON d.department_id = e.department_id
WHERE e.employee_id = 102
) 部門名;
from 後面
將子查詢結果充當一張表,要求必須起別名;
#案例1:查詢每個部門的平均工資的工資等級
#(1)查詢每個部門的平均工資
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#(2)連接(1)的結果集和job_grade表,篩選條件平均工資between lowest_sal and highest_sal
SELECT ag_dep.*,g.`grade_level`
FROM(
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
INNER JOIN job_grade g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
#案例2:查詢各部門中工資比本部門平均工資高的員工的員工號,姓名和工資
#(1)查詢各部門的平均工資
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id;
#(2)連接(1)結果集和 employees 表,進行篩選
SELECT employee_id,last_name,salary,e.department_id
FROM employees e
INNER JOIN (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id;
)ag_dep
ON e.department_id = ag_dep.department_id
WHERE salary > ag_dep.ag;
exists後面(相關子查詢)
語法:
exists(完整的查詢語句) 問題:exists(NULL)?
結果:
1或0
#案例1:查詢有員工的部門名
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE e.`department_id`= d.`department_id`
);
#in
SELECT department_name
FROM departments d
WHERE d.`deparment_id` IN (
SELECT department_id
FROM employees
);
#案例2:查詢沒有女朋友的男生信息
#in
SELECT bo.*
FROM boys bo
WHERE bo.id NOT IN(
SELECT boyfriend_id
FROM beauty
);
#exists
SELECT bo.*
FROM boys bo
WHERE NOT EXISTS(
SELECT boyfriend_id
FROM beauty b
WHERE bo.id = b.boyfriend_id
);
子查詢經典案例
# 1.查詢工資最低的員工信息:last_name,salary
#(1)查詢最低的工資
SELECT MIN(salary)
FROM employees
#(2)查詢last_name,salary,要求salary=(1)
SELECT last_name,salary
FROM employees
WHERE salary = (
SELECT MIN(salary)
FROM employees
)
# 2.查詢平均工資最低的部門信息
#方法一:
#(1)各部門的平均工資
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#(2)查詢(1)結果上的最低平均工資
SELECT MIN(ag)
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
#(3)查詢哪個部門的平均工資=(2)
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(ag)
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
)
#(4)查詢部門信息
SELECT d.*
FROM departments d
WHERE d,department = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(ag)
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
)
)
#方法二:
#(1)各部門的平均工資
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#(2)求出最低平均工資的部門編號
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary)
LIMIT 1;
# 3.查詢平均工資最低的部門信息和該部門的平均工資
#(1)各部門的平均工資
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#(2)求出最低平均工資的部門編號和平均工資
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id
ORDER BY AVG(salary)
LIMIT 1;
#(3)查詢部門信息(內連接)
SELECT d.*,
FROM departments d
INNER JOIN (
SELECT department_id,AVG(salary) ag
FROM employees
GROUP BY department_id
ORDER BY AVG(salary)
LIMIT 1;
)ag_dep
ON d.department_id = ag_dep.department_id;
# 4.查詢平均工資最高的 job 信息
#(1)查詢每個job的平均工資
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id
#(2)在(1)的結果上獲取平均工資最高的job
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id
ORDER BY AVG(salary) DESC
LIMIT 1
#(3)查詢job信息
SELECT *
FROM jobs
WHERE job_id = (
SELECT job_id
FROM employees
GROUP BY job_id
ORDER BY AVG(salary) DESC #order by後面存在的非聚合列必須在select後面出現
LIMIT 1
)
# 5.查詢平均工資高於公司平均工資的部門有哪些
#(1)查詢公司的平均工資
SELECT AVG(salary)
FROM employees
#(2)查詢每個部門的平均工資
SELECT AVG(salary)
FROM employees
GROUP BY department_id
#(3)篩選(2)結果集,滿足平均工資>(1)
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) > (
SELECT AVG(salary)
FROM employees
)
# 6.查詢出公司中所有 manager 的詳細信息
#(1)查詢所有manager的員工編號
SELECT DISTINCT manager_id
FROM employees
#(2)查詢詳細信息,滿足employee_id=(1)
SELECT *
FROM employees
WHERE employee_id = ANY(
SELECT DISTINCT manager_id
FROM employees
)
# 7.各個部門中,最高工資中最低的那個部門的最低工資是多少
#(1)查詢各部門的最高工資中最低的
SELECT MAX(salary),department_id
FROM employees
GROUP BY department_id
ORDER BY MAX(salary) ASC
LIMIT 1
#(2)查詢(1)結果的那個部門的最低工資
SELECT MIN(salary),department_id
FROM employees
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY MAX(salary) ASC
LIMIT 1
)
# 8.查詢平均工資最高的部門的 manager 的詳細信息:last_name,department_id,email,salary
#(1)查詢平均工資最高的部門編號
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary) DESC
LIMIT 1
#(2)將employees和departments表連接查詢,篩選條件是(1)
SELECT last_name,d.department_id,email,salary
FROM employeese e
INNER JOIN departments d
ON d.department_id = e.department_id
WHERE d.department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary) DESC
LIMIT 1
)
分頁查詢
應用查詢:當要顯示的數據,一頁顯示不全,需要分頁提交 sql 請求。
語法:
SELECT 查詢列表 7
FROM 表 1
[JOIN type join 表2 2
ON 連接條件 3
WHERE 篩選條件 4
GROUP BY 分組欄位 5
HAVING 分組後的篩選 6
ORDER BY 排序的欄位] 8
LIMIT offset,size; 9
# offset 要顯示條目的起始索引(起始索引從0開始)
# size 要顯示的條目個數
根據執行順訊,可以得出:
1. order by 後面的列必須是在 select 後面存在的;
2. select、having 或 order by 後面存在的非聚合列必須全部在 group by 中存在。
特點:
-
limit 語句放在查詢語句的最後
-
公式
#要顯示的頁數page 每頁的條目數size
SELECT 查詢列表
FROM 表
LIMIET (page-1)*size,size;
#案例1:查詢前五條員工信息
SELECT * FROM employees LIMIT 0,5;
或
SELECT * FROM employees LIMIT 5;
#案例2:查詢