目錄
一、基礎查詢介紹
1、起別名
優點:
①便於理解
②如果要查詢的字段有重名的情況,使用別名可以區分開來
#方式一
‘As‘形式
SELECT first_name As "名字", salary As "薪水" FROM `employees`;
#方式二
’空格’形式
SELECT first_name "名字", salary "薪水" FROM employees; #MySQL建議別名加雙引號
2、去重
#案例:查詢員工表中涉及到的所有的部門編號
SELECT department_id FROM `employees`
加入DISTINCT關鍵字
SELECT DISTINCT department_id FROM `employees`
3、+號的作用
Java中的+號
①運算符,兩個操作數都爲數值型,則做加法運算
②連接符,只要有一個操作數爲字符串
MySQL中的+號
僅有一個功能:運算符
~兩個操作數爲數值型,則做加法運算
select 100+20
~其中一方爲字符型,試圖將字符型數值轉成數值型
如果轉換成功,則繼續做加法運算,如果轉換失敗,則將字符型數值轉成0
SELECT '100'+20
SELECT 'jiusen'+20
~只要一方爲null,則結果肯定爲null
SELECT NULL + 20
4、使用concat實現連接
SELECT CONCAT('a', 'b', 'c')
#案例:查詢員工名和姓連接成一個字段,並顯示爲姓名
SELECT
CONCAT(last_name, first_name) AS 姓名
FROM
employees
5、IFNULL
SELECT
IFNULL(`commission_pct`, 0) AS 獎金率,
commission_pct
FROM
employees
二、條件查詢
語法:
SELECT
查詢列表
FROM
表名
WHERE 篩選條件
分類:
一、按條件表達式篩選
簡單條件運算符: > < = != <> >= <=
二、按邏輯表達式篩選
&& || ! and or not
三、模糊查詢
like
between and
in
is null
一、按條件表達式篩選
#案例1 : 查詢工資 > 12000的員工信息
SELECT
*
FROM
employees
WHERE salary > 12000
#案例2: 查詢部門編號不等於30號的員工名和部門編號
select
`employee_id`,
`department_id`
from
`employees`
where `department_id` <> 30
二、按邏輯表達式篩選
#案例1:查詢工資在10000到20000之間的員工名、工資以及獎金
SELECT
`last_name`,
`salary`,
`commission_pct`
FROM
`employees`
WHERE salary >= 10000
AND salary <= 20000
#案例2:查詢部門編號不是在90到110之間,或者工資高於15000的員工信息
SELECT
*
FROM
`employees`
WHERE AND(
`department_id` >= 90
AND `department_id` <= 110
)
OR `salary` > 15000
三、模糊查詢
1、like
特點①一般和通配符搭配使用
通配符: %任意多個字符,包含0個字符
_任意單個字符
#案例1::查詢員工名中包含字符a的員工信息
SELECT
*
FROM
`employees`
WHERE `last_name` LIKE '%a%'
#案例2:查詢員工名中第三個字符爲n,第五個字符爲a的員工名
SELECT
`last_name`,
`salary`
FROM
`employees`
WHERE `last_name` LIKE '__n_r%'
#案例3:查詢員工名中第三個字符爲_的員工名
-- 使用 '\'轉義字符進行轉義
SELECT
`last_name`
FROM
`employees`
WHERE `last_name` LIKE '_\_%';
-- 使用ESCAPE關鍵字
SELECT
`last_name`
FROM
`employees`
WHERE `last_name` LIKE '_$_%' ESCAPE '$';
2、between and
①使用between and 可以提高語句的簡介度
②包含臨界值
③兩個臨界值不能更換位置
#案例1:查詢員工編號在100到120之間的員工信息
select
*
from
`employees`
where `employee_id` between 100 and 120
3、in關鍵字
#案例:查詢員工的工種編號是IT_PROG 、AD_VP、 AD_PRES中的一個員工名和工種編號
SELECT
`last_name`,
`job_id`
FROM
`employees`
WHERE `job_id` IN ('IT_PROG', 'AD_PRES', 'AD_VP') ;
4、 is null
=或者<>不能用於判斷null值
is null 或者 is not null可以判斷 null 值
#案例:查詢沒有獎金的員工名和獎金率
SELECT
`last_name`,
`commission_pct`
FROM
`employees`
WHERE `commission_pct` IS NULL ;
5、安全等於 <=>
IS NULL : 僅僅可以判斷NULL值,可讀性較高
<=> : 既可以判斷NULL值,又可以判斷普通的數值,可讀性較低
#案例1:查詢沒有獎金的員工名和獎金率
select
`last_name`,
`commission_pct`
from
`employees`
where `commission_pct` <=> null ;
#案例2:查詢薪資爲12000的員工名和薪資
SELECT
`last_name`,
`salary`
FROM
`employees`
WHERE salary <=> 12000
#案例:查詢員工號爲176的員工號、姓名、月薪、獎金率、年薪
SELECT
`last_name`,
`department_id`,
`salary`,
`commission_pct`,
salary * 12 *(1+ IFNULL(commission_pct, 0)) AS 年薪
FROM
employees
WHERE `employee_id` = 176;
測試題:
#測試1: 查詢沒有獎金,且工資小於18000的salary, last_name
SELECT
`salary`,
`last_name`
FROM
`employees`
WHERE `commission_pct` IS NULL
AND `salary` < 18000 ;
#測試2:查詢employees表中,job_id不爲'IT'或者工資爲12000的員工信息
SELECT
*
FROM
`employees`
WHERE `job_id` <> 'IT'
OR `salary` = 12000 ;
#測試3:查看部門departments表的結構
DESC `employees`;
#測試4:查詢部門departments表中涉及到了哪些位置編號
SELECT DISTINCT
`location_id`
FROM
`departments`
## 經典面試題:
試問 SELECT * FROM `employees` ; 和 SELECT * FROM `employees` WHERE `commission_pct` LIKE '%%' AND `last_name` LIKE '%%'; 結果是否一樣?並說明原因
SELECT * FROM `employees`;
SELECT * FROM `employees` WHERE `commission_pct` LIKE '%%' AND `last_name` LIKE '%%';
第二種不能夠查詢到null的情況
三、排序查詢
語法:
select 查詢列表 from 表 【where 篩選條件】 order by 排序列表 asc | desc
特點:
1、asc代表的是升序,desc代表的是降序
如果不寫,默認是升序
2、order by子句中可以支持單個字段、多個字段、表達式、函數、別名
3、order by子句一般是放在查詢語句的最後面,limit子句除外
# 案例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_pct, 0)) as '年薪'
from
`employees`
order by 年薪;
#案例5:按姓名的長度顯示員工的姓名和工資【按函數進行排序】
SELECT
LENGTH(last_name) 字節長度,
`last_name`,
`salary`
FROM
`employees`
ORDER BY LENGTH(last_name) ;
# 案例6:查詢員工信息,要求先按工資升序,再按員工編號降序【按多個字段排序】
SELECT
*
FROM
`employees`
ORDER BY salary ASC,
`employee_id` DESC ;
## 排序案例
#1、查詢員工的姓名和部門號和年薪,按年薪降序 按姓名升序
SELECT
`last_name`,
`department_id`,
`salary` * 12 * (1+ IFNULL(`commission_pct`, 0)) AS 年薪
FROM
`employees`
ORDER BY 年薪 DESC,
`last_name` ASC ;
#2、選擇工資不在8000到17000的員工的姓名和工資,按工資降序
SELECT
`last_name`,
`salary`
FROM
`employees`
WHERE salary NOT BETWEEN 8000
AND 17000
ORDER BY salary DESC ;
#3、查詢郵箱中包含e的員工信息,並先按郵箱的字節數降序,再按部門號升序
SELECT
*
FROM
`employees`
WHERE `email` LIKE '%e%'
ORDER BY LENGTH(email) DESC,
`department_id` ASC ;
四、常見函數
概念:類似於Java的方法,將一組邏輯語句封裝在方法中,對外暴露方法名
好處:1、隱藏了實現細節, 2、提高了代碼的重用性
調用:select 函數名(實參列表) 【from表】;
特點:①叫什麼(函數名) ②幹什麼(函數功能)
分類:
1、單行函數 如 concat 、length 、ifnull等
2、分組函數 功能:做統計使用,又稱爲統計函數 、 聚合函數、組函數
一、字符函數
#1、length 獲取參數值的字節個數
SELECT LENGTH('john');
SELECT LENGTH('森哥哥521');
#2、concat拼接字符串
SELECT CONCAT('郭', 'love', '張');
#3、upper、lower
SELECT UPPER('love'), LOWER('AK'); -- 字符串記得加上''或者""
#4、substr、substring
MySQL中索引從1開始
#截取從指定索引後面的所有字符
select substr('郭久森愛上了張瑩瑩', 7) output;
#截取從指定索引處指定字符長度的字符
select substr('郭久森愛上了張瑩瑩',1,3) output;
## 案例:姓名中首字符大寫,其他字符小寫然後用_拼接,顯示出來
SELECT
CONCAT(
UPPER(SUBSTR(`last_name`, 1, 1)),
'-',
LOWER(SUBSTR(`last_name`, 2))
) 姓名
FROM
`employees`
#5、instr
返回指定字符串第一次出現的索引,如果找不到就返回0
SELECT
INSTR(
'郭久森愛上了張瑩瑩',
'張瑩瑩'
) AS out_put ;
#6、trim
去除字符串中的空格
select
trim('aa' from 'aaaaaaaa森') as out_put ;
#7、lpad用指定的字符實現左填充指定長度
SELECT LPAD('森啊啊啊', 5, '*') output
#8、右填充與左填充類似
#9、replace替換指定字符串
SELECT
REPLACE(
'郭久森愛上了計算機',
'計算機',
'張瑩瑩'
) AS output ;
二、數學函數
#round 四捨五入
SELECT ROUND(-1.56)
SELECT
ROUND(- 1.567, 2) 四捨五入 ;
#ceil 向上取整,返回>=該參數的最小整數
SELECT
CEIL(- 1.567) 向上取整 ;
#floor向下取整,返回<=該參數的最大整數
SELECT
FLOOR(- 1.567) 向下取整 ;
#截斷 truncate
SELECT
TRUNCATE(1.6654, 2)
#mod取餘 : a*a/b*b
SELECT
MOD(10, 3)
三、日期函數
#now返回當前的系統日期 + 時間
#curdate返回當前系統日期,不包含時間
#curtime返回當前時間,不包含日期
#年、月、日
SELECT
YEAR(NOW()); -- 年
SELECT
MONTH(NOW()); -- 月
SELECT
DAY(NOW()); -- 日
#str_to_date 將字符通過指定的格式轉換成日期
SELECT
STR_TO_DATE('4-3 1992', '%m-%d %Y')
##案例:查詢入職日期爲1992-4-3的員工信息
SELECT
*
FROM
`employees`
WHERE `hiredate` = STR_TO_DATE('4-3 1992', '%m-%d %Y') ;
#date_format 將日期轉換成字符
SELECT
DATE_FORMAT(NOW(), '%Y年%m月%d日')
#案例:查詢有獎金的員工名和入職日期(xx月/xx日 xx年)
SELECT
`last_name`,
DATE_FORMAT(`hiredate`, '%m月/%d日 %Y年') 入職日期
FROM
`employees`
WHERE `commission_pct` IS NOT NULL ;
四、流程控制函數
#1、if函數: if else的效果
SELECT IF(10>5,'大','小');
#查詢有獎金的員工:
SELECT
`last_name`,
`commission_pct`,
IF(
`commission_pct` IS NULL,
'沒獎金,呵呵',
'有獎金,嘻嘻'
) AS 備註
FROM
`employees` ;
五、case結構
MySQL中
1、類似於switch ... case... default.....
case 要判斷的字段或者表達式
when 常量1 then要顯示的值1或語句1
when 常量2 then要顯示的值1或語句2
when 常量3 then要顯示的值1或語句3
......
else 要顯示的值n或語句n
end
## 案例:查詢員工的工資,要求:
部門號=30,顯示的工資爲1.1倍
部門號=40,顯示的工資爲1.2倍
部門號=50,顯示的工資爲1.3倍
其他部門,顯示的工資爲原工資
SELECT
`salary` 薪資,
`department_id`,
CASE
`department_id`
WHEN 30
THEN 1.1 * `salary`
WHEN 40
THEN 1.2 * `salary`
WHEN 50
THEN 1.3 * `salary`
ELSE `salary`
END AS 新工資
FROM
`employees` ;
2、
case
when 條件1 then 要顯示的值1或語句1
when 條件2 then 要顯示的值2或語句2
......
else 要顯示的值n或語句n
end
區別:
1比較適合於處理等值判斷。2、比較適合區間的判斷
## 查詢員工的工資的情況
如果工資>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` ;
案例練習
#1、顯示系統時間(注:日期+時間)
SELECT
NOW() AS 系統時間 ;
#2、查詢員工號、姓名、工資、以及工資提高百分之20後的結果(new salary)
SELECT
`employee_id`,
`last_name`,
`salary`,
`salary` * (1+0.02) AS 'new salary'
FROM
`employees` ;
#3、將員工的姓名按首字母排序,並寫出姓名的長度(LENGTH)
SELECT
`last_name`,
SUBSTR(`last_name`, 1, 1) AS 首字母,
LENGTH(`last_name`)
FROM
`employees`
ORDER BY `last_name`
#4、做一個查詢,產生下面的結果
SELECT
CONCAT(
`last_name`,
' earns ',
salary,
' monthly but wants ',
salary * 3
) AS 'Dream Salary'
FROM
`employees`
WHERE salary = 24000
#5、使用case-when,按照下面的條件:
job_id | Grade |
AD_PRES | A |
ST_MAN | B |
IT_PROG | C |
SA_REP | D |
ST_CLERK | E |
產生下面結果:
SELECT
`job_id` AS job,
CASE
`job_id`
WHEN 'AD_PRES'
THEN 'A'
WHEN 'ST_MAN'
THEN 'B'
WHEN 'IT_PROG'
THEN 'C'
WHEN 'SA_REP'
THEN 'D'
WHEN 'ST_CLERK'
THEN 'E'
END AS 等級
FROM
`employees`
WHERE job_id = 'AD_PRES'
六、分組函數
功能:用作統計使用,又稱爲聚合函數或統計函數或組函數
分類:
sum 求和、 avg 平均值、 max 最大值、 min 最小值、 count 計算個數
1、 簡單的使用:
1、sum求和:
SELECT
SUM(`salary`) 總薪資
FROM
`employees`
2、avg 平均值
SELECT
AVG(`salary`) 平均薪資
FROM
`employees`
3、max最大值
select
max(`salary`) 最高薪資
from
`employees`
4、min最小值
SELECT
MIN(`salary`) 最低薪資
FROM
`employees`
5、count計算個數
SELECT
COUNT(`last_name`) 總人數
FROM
`employees`
** 另外也可以這些分組函數一起使用
SELECT
COUNT(`last_name`) 總人數,
SUM(`salary`) 總薪資,
AVG(`salary`) 平均薪資,
MAX(`salary`) 最高薪資,
MIN(`salary`) 最低薪資
FROM
`employees`
2、分組函數的特點
1、sum、avg一般用於處理數值型
max、min、count可以處理任何類型
2、是否忽略null值
sum、avg、max、min、count忽略了null值
3、和distinct搭配
例:
select
sum(distinct `salary`) 去重求和,
sum(`salary`) 求和
from
`employees`
4、count函數的詳細介紹
SELECT
COUNT(`commission_pct`) 非空的總行數
FROM
`employees`
SELECT
COUNT(*) 表的總行數
FROM
`employees`
SELECT
COUNT(1) 總行數 -- 常量代表將表的列置爲一個常量,然後統計一列中該常量的個數
FROM
`employees`
效率:
NYISAM存儲引擎下,COUNT(*)的效率最高
INNODB存儲引擎下,COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)要高一些 ,字段的話要進行一下判斷是否爲null
一般使用count(*)用作統計行數
5、分組函數的其他注意事項
和分組函數一同查詢的字段要求是group by後的字段(group by知識點後面總結)
案例複習
#1、查詢員工表中的最大入職時間和最小入職時間的相差天數(DIFFRENCE)
SELECT
DATEDIFF(MAX(`hiredate`), MIN(`hiredate`)) DIFFERENT
FROM
`employees`
#2、查詢部門編號爲90的員工個數
SELECT
COUNT(*) 員工號爲90的個數
FROM
`employees`
WHERE `department_id` = 90
五、分組查詢的介紹
語法:
select 分組函數,列(要求出現在group by的後面)
from 表
【where 篩選條件】
group by 子組的列表
【order by 子句】
注意:查詢列表必須特殊,要求是分組函數和group by後出現的字段
分組查詢的簡單使用
# 案例:查詢每個部門的平均薪資
select
avg(`salary`) 平均薪資,
`department_id` 部門
from
`employees`
group by `department_id`
# 案例:查詢每個工種的最高工資
SELECT
MAX(`salary`) 最高工資,
`job_id` 工種
FROM
`employees`
GROUP BY `job_id`
# 案例:查詢每個位置上的部門個數
SELECT
COUNT(*) 部門個數,
`location_id` 部門
FROM
`departments`
GROUP BY `location_id`
添加篩選條件
分組前篩選
案例1:查詢郵箱中包含a字符的,每個部門的平均工資
SELECT
AVG(`salary`) 平均薪資,
`department_id` 部門,
`email` 郵箱
FROM
`employees`
WHERE `email` LIKE '%a%'
GROUP BY `department_id`
案例2:查詢有獎金的每個領導手下員工的最高工資
SELECT
MAX(`salary`) 最高工資,
`manager_id` 部門
FROM
`employees`
WHERE `commission_pct` IS NOT NULL
GROUP BY `manager_id`
分組後篩選
#案例1:查詢哪個部門的員工個數>2
SELECT
COUNT(*) 員工個數,
`department_id` 部門
FROM
`employees`
GROUP BY `department_id`
HAVING COUNT(*) > 2
#案例2、查詢每個工種有獎金的員工的最高工資>12000的工種編號和最高工資
對於稍微複雜的查詢,可以分部來解決
①查詢每個工種有獎金的員工的最高工資
SELECT
MAX(salary) 最高工資,
`job_id` 工種
FROM
`employees`
WHERE `commission_pct` IS NOT NULL
GROUP BY job_id
②根據①結果繼續篩選,最高工資>12000
select
max(salary) 最高工資,
`job_id` 工種
from
`employees`
where `commission_pct` is not null
group by job_id
having max(salary) > 12000
#案例3:查詢領導編號>102的每個領導手下的最低工資>5000的領導編號,以及其最低工資
思路:先分組,再加篩選條件
SELECT
MIN(salary) 最低工資,
manager_id 領導編號
FROM
employees
WHERE manager_id > 102
GROUP BY manager_id
HAVING MIN(salary) > 5000
按表達式或函數分組
#案例:按員工姓名的長度分組,查詢每一組的員工個數,篩選員工個數>5的有哪些
分步解決:
①查詢每個長度的員工個數
SELECT
COUNT(*),
LENGTH(last_name)
FROM
employees
GROUP BY LENGTH(last_name)
②添加篩選條件
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`
GROUP BY `job_id`,
`department_id`
ORDER BY AVG(salary)DESC;
小結
1、分組查詢中的篩選條件分爲兩類:
類型 | 數據源 | 位置 | 關鍵字 |
分組前篩選 | 原始表 | group by子句的前面 | where |
分組後篩選 | 分組後的結果集 | group by子句的後面 | having |
①分組函數做條件肯定是放在having字句中
②能用分組前篩選的,就優先考慮使用分組前篩選
2、group by子句支持單個字段分組,多個字段分組(多個字段之間用逗號隔開沒有順序要求),表達式或函數(用的較少)
3、也可以添加排序(排序放在整個分組查詢的最後)
案例練習
#1、查詢各job_id的員工工資的最大值,最小值,平均值,總和,並按job_id升序
SELECT
MAX(salary) 最大值,
MIN(salary) 最小值,
AVG(salary) 平均值,
SUM(salary) 總和
FROM
`employees`
GROUP BY job_id
ORDER BY job_id
#2、查詢員工最高工資和最低工資之間的差距 DIFFERENT
SELECT
MAX(salary) - MIN(salary) DIFFERENT
FROM
`employees`
#3、查詢各個管理者手下員工的最低工資,其中最低工資不能低於6000,沒有管理者的員工不計算在內
SELECT
MIN(salary), `manager_id`
FROM
employees
WHERE `manager_id` IS NOT NULL
GROUP BY `manager_id`
HAVING MIN(salary) >= 6000
#4、查詢所有部門的編號,員工數量和工資平均值,並按平均工資降序
SELECT
COUNT(*) 員工數量,
AVG(salary) 平均薪資,
`department_id` 部門編號
FROM
`employees`
GROUP BY `department_id`
5、選擇具有各個job_id的員工數量
SELECT
COUNT(*)員工數量,
job_id
FROM
`employees`
GROUP BY `job_id`
六、連接查詢
含義:又稱爲多表查詢,當查詢的字段來自於多個表時,就會用到連接查詢
笛卡爾乘積
假設表1有m行數據,表2有n行數據,則下方SQL處理後,則產生m*n條數據
SELECT
`name`,
`boyName`
FROM
`beauty`,
`boys`
連接查詢的分類
按照年代分類:
sql92標準:僅僅支持內連接
sql99標準【推薦】:支持內連接、外連接(左外、右外)、交叉連接
按功能分類:
內連接: 等值連接、非等值連接、自連接
外連接:左外連接、右外連接、全外連接
交叉連接
等值連接
#案例:查詢女神名和對應的男神名
先查詢出所有的,然後再加上條件
select
`name`,
`boyName`
from
`beauty`,
`boys`
where beauty.id = boys.id
#2、查詢員工名和對應的部門名
SELECT
`last_name`,
`department_name`
FROM
`employees`,
`departments`
WHERE departments.department_id = employees.department_id
##3、查詢員工號、工種號、工種名
SELECT
`last_name`,
a.`job_id`,
`job_title`
FROM
`employees` AS a, -- 由於表名字段太長,這裏起別名
`jobs` AS b
WHERE a.`job_id` = b.`job_id`
爲表起別名
①、提高語句的簡介度
②、區分多個重名的子段
注:如果爲表起了別名,則查詢的字段就不能使用原來的表明去限定
等值連接的示例
#案例1、表名是否可以交換:
可以
#案例2、查詢有獎金的員工名、部門名
SELECT
`last_name`,
`department_name` ,
`commission_pct`
FROM
`departments` d,
`employees` e
WHERE d.`department_id` = e.`department_id`
AND e.`commission_pct` IS NOT NULL
#案例3:查詢城市名中第二個字符爲o的部門名和城市名(加篩選條件)
SELECT
`department_name`,
`city`
FROM
`departments` d,
`locations` l
WHERE d.`location_id` = l.`location_id` -- 兩個篩選條件之間用 and進行連接
AND l.`city` LIKE '_o%'
#案例4:查詢每個城市的部門個數
SELECT
COUNT(*) 部門個數,
city 城市
FROM
`locations` l,
`departments` d
WHERE l.`location_id`=d.`location_id`
GROUP BY l.`city`
#案例5:查詢有獎金的每個部門的部門名和部門的領導編號和該部門的最低工資
SELECT
d.`department_name`,
d.`manager_id`,
MIN(salary) 最低工資
FROM
departments d,
employees e
WHERE d.`department_id` = e.`department_id`
AND e.`commission_pct` IS NOT NULL
GROUP BY d.`department_name`
#案例6:查詢每個工種的工種號和員工的個數,並且按員工個數降序(排序)
SELECT
j.`job_title` 工種名,
COUNT(*) 員工個數
FROM
`employees` e,
`jobs` j
WHERE e.`job_id` = j.`job_id`
GROUP BY j.`job_title`
ORDER BY 員工個數 DESC
#案例7:查詢員工名、部門名和所在的城市(多表連接查詢)
SELECT
`last_name`,
`department_name`,
`city`
FROM
`departments` d,
`employees` e,
`locations` l
WHERE d.`department_id` = e.`department_id`
AND d.`location_id` = l.`location_id`
小結
①多表等值連接的結果爲多表的交集部分
②n表連接,至少需要n-1個連接條件
③多表的順序沒有要求
④一般需要爲表起別名
⑤可以搭配前面介紹的所有子句使用,比如排序、分組、篩選
非等值連接
#案例:查詢員工的工資和工資級別並按薪資升序
SELECT
`salary`,
`grade_level`
FROM
`employees` e,
`job_grades` j
WHERE e.`salary` BETWEEN j.`lowest_sal`
AND j.`highest_sal`
ORDER BY e.`salary`
自連接
意思也就是表自己連接自己
比如下表
#案例:查詢員工名和上級的名稱
思路:把這一個表看做一個員工表、一個領導表進行連接
select
e1.`last_name` 員工名,
e2.`last_name` 領導名
from
`employees` e1,
`employees` e2
where e1.`manager_id` = e2.`employee_id`
測試題
一、顯示員工表的最大工資,平均工資
SELECT
MAX(salary) 最大工資,
AVG(salary) 平均工資
FROM
`employees`
二、查詢員工表的employee_id,job_id,last_name,按department_id降序、salary升序
SELECT
`employee_id`,
`job_id`,
`last_name`
FROM
`employees`
ORDER BY `department_id` DESC,
`salary` ASC
三、查詢員工表的job_id中包含'a和‘e’的,並且 a 在 e 的前面
SELECT
DISTINCT `job_id`
FROM
`employees`
WHERE `job_id` LIKE '%a%e%'
四、
已知表student,裏面有id(學號),name, gradeId(年級編號)
已知表grade,裏面有id(年級編號),name(年級號)
已知表result,裏面有id,score,studentNo(學號)
要求查詢姓名、年級名、成績
SELECT
s.`name`,
g.`name`,
r.`score`
FROM
student s,
grade g,
result r
WHERE s.gradeId = g.id
AND s.id = r.studentId
五、顯示當前日期、以及去前後空格、截取子字符串的函數
SELECT NOW();
SELECT TRIM(' ' FROM 'asfass ');
SELECT SUBSTR(str,startIndex);
SELECT SUBSTR(str, startIndex, slength)
SQL練習
1、顯示所有的員工的姓名,部門號和部門名稱
SELECT
e.`last_name`,
e.`department_id`,
d.`department_name`
FROM
`employees` e,
`departments` d
WHERE e.`department_id` = d.`department_id`
2、查詢90號部門員工的job_id和90號部門的location_id
SELECT
d.`department_id`,
e.`job_id`,
d.`location_id`
FROM
`employees` e,
`departments` d
WHERE e.`department_id` = d.`department_id`
AND e.`department_id` = 90
3、選擇所有有獎金的員工的last_name,department_name,location_id,city
SELECT
e.`last_name`,
d.`department_name`,
l.`location_id`,
e.`commission_pct`,
l.`city`
FROM
`locations` l,
`employees` e,
`departments` d
WHERE l.`location_id` = d.`location_id`
AND e.`department_id` = d.`department_id`
AND e.`commission_pct` IS NOT NULL
4、選擇city在Toronto工作的員工的last_name,job_id, department_id, department_name,city
select
e.`last_name`,
e.`job_id`,
d.`department_id`,
d.`department_name`,
l.`city`
from
`employees` e,
`departments` d,
`locations` l
where e.`department_id` = d.`department_id`
and d.`location_id` = l.`location_id`
and l.`city` = 'Toronto'
5、查詢每個工種、每個部門的部門名、工種名和最低工資
select
e.`job_id`,
d.`department_name`,
j.`job_title`,
min(salary) 最低工資
from
`employees` e,
`departments` d,
`jobs` j
where e.`department_id` = d.`department_id`
and e.`job_id` = j.`job_id`
group by e.`job_id`
6、查詢每個國家下的部門個數大於2的國家的編號、部門號以及部門個數
SELECT
`country_id`,
`department_id`,
COUNT(*) 部門個數
FROM
`locations` l,
`departments` d
WHERE l.`location_id` = d.`location_id`
GROUP BY l.`country_id`
HAVING 部門個數 > 5
7、選擇指定員工的姓名、員工號,以及他的管理者的姓名和員工號,結果類似於下面的格式
employees Emp# manager Mgr#
kochhar 101 king 100
SELECT
e1.`last_name` employees,
e1.`employee_id` "emp#",
e2.`last_name` manager,
e2.`employee_id` "Mgr#"
FROM
`employees` e1,
`employees` e2
WHERE e1.`manager_id` = e2.`employee_id`
sql99語法介紹
語法:
select 查詢列表
from 表1 別名 【連接類型】
join 表2 別名
on 連接條件
【where 篩選條件】
【group by 分組】
【having 篩選條件】
【order by 排序條件】
內連接(*):inner
外連接 :
左外(*):left 【outer】
右外(*):right 【outer】
全外:full【outer】
交叉連接 :cross
內連接
語法:
select 查詢列表
from 表1 別名
inner join 表2 別名
on 連接條件
分類: 等值、非等值、自連接
等值連接
#案例一:查詢員工名、部門名(調換表位置也可以)
SELECT
`last_name`,
`department_name`
FROM
`employees` e
INNER JOIN `departments` d
ON e.`department_id` = d.`department_id`
案例二、查詢名字中包含a的員工名和工種名(篩選)
SELECT
`last_name`,
`job_title`
FROM
`employees` e
INNER JOIN `jobs` j
ON e.`job_id` = j.`job_id`
WHERE e.`last_name` LIKE '%a%'
案例三、查詢部門個數>3的城市名和部門個數(添加分組+篩選)
思路:1、查詢每個城市的部門個數,2、在1結果上篩選滿足條件的
SELECT
`city`,
COUNT(*)
FROM
`locations` l
INNER JOIN `departments` d
ON l.`location_id` = d.`location_id`
GROUP BY city
HAVING COUNT(*) > 3
案例四、查詢哪個部門的部門員工個數>3的部門名和員工個數,並按個數降序
SELECT
d.`department_name`,
COUNT(*)
FROM
`employees` e
INNER JOIN `departments` d
ON e.`department_id` = d.`department_id`
GROUP BY e.`department_id`
HAVING COUNT(*) > 3
ORDER BY COUNT(*) DESC
案例五、查詢員工名、部門號、工種名,並按部門號降序(多變內聯)
SELECT
`last_name`,
d.`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`
ORDER BY e.`department_id` DESC
非等值連接
案例: 查詢員工的工資級別
SELECT
`salary`,
`grade_level`
FROM
`employees` e
INNER JOIN `job_grades` j
ON salary BETWEEN `lowest_sal`
AND `highest_sal`
案例2:查詢每個工資級別大於20的個數,並且按工資級別降序
SELECT
`grade_level`,
COUNT(*) 級別個數
FROM
`employees` e
INNER JOIN `job_grades` j
ON salary BETWEEN `lowest_sal`
AND `highest_sal`
GROUP BY grade_level
HAVING 級別個數 > 20
ORDER BY COUNT(*) DESC
自連接
案例:查詢員工的姓名、上級的名字
SELECT
e1.`last_name`員工,
e2.`last_name` 上級
FROM
`employees` e1
INNER JOIN `employees` e2
ON e1.`manager_id` = e2.`employee_id`
案例2:查詢姓名中包含字符k的員工的姓名、上級的名字
SELECT
e1.`last_name` 員工,
e2.`last_name` 上級
FROM
`employees` e1
INNER JOIN `employees` e2
ON e1.`manager_id` = e2.`employee_id`
WHERE e1.`last_name` LIKE '%k%'
左右連接
應用場景:用於查詢一個表中有,另外一個表中沒有的記錄
特點:
1、
外連接的查詢結果爲主表中的所有記錄
如果從表中有和他匹配的,則顯示匹配的值,
如果從表中沒有和他匹配的,則顯示null
外連接查詢結果=內連接結果+主表中有而從表中沒有的記錄
2、左外連接:left join左邊的是主表 右外連接:right join右邊的是主表
3、左外和右外交換兩個表的順序,可以實現同樣的效果
4、全連接=內連接的結果+表1中有但表2沒有的+表2有但是表1沒有的
SELECT
bo.*,
b.*
FROM
`boys` bo
LEFT OUTER JOIN `beauty` b
ON bo.`id`=b.`boyfriend_id`
引入:查詢男朋友不在男神表的女神名
SELECT
b.`name`
FROM
`beauty` b
LEFT OUTER JOIN `boys` bo
ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id` IS NULL
案例:查詢哪個部門沒有員工
左連接之後,查詢員工id爲null的,另外
SELECT
d.*
FROM
`departments` d
LEFT OUTER JOIN `employees` e
ON d.`department_id` = e.`department_id`
WHERE e.`email` IS NULL
全外連接
MySQL不支持全外連接
交叉連接
也就是表之間的笛卡爾積
SELECT
b.*,
bo.*
FROM
`boys` b
CROSS JOIN `beauty` bo
查詢總結
案例講解
一、查詢編號>3的女神編號、名字以及男朋友的信息,如果有則列出詳細信息,如果沒有,用null填充
SELECT
b.`id`,
b.`name`,
bo.*
FROM
`beauty` b
LEFT OUTER JOIN `boys` bo
ON b.`boyfriend_id` = bo.`id`
WHERE b.`id`>3
二、查詢哪個城市沒有部門
SELECT
l.*,d.*
FROM
`locations` l
LEFT OUTER JOIN `departments` d
ON l.`location_id` = d.`location_id`
WHERE d.`department_id` IS NULL
三、查詢部門名爲SAL或IT的員工信息
SELECT
e.*, d.`department_name`, d.`department_id`
FROM
`employees` e
RIGHT OUTER JOIN `departments` d
ON e.`department_id` = d.`department_id`
WHERE d.`department_name` IN('SAL', 'IT')
注:有重名部門的情況,內連接的話,少兩條null的信息,就是這個部門沒有員工
子查詢
含義:出現在其他語句中的select語句,稱之爲子查詢或內查詢
外部的查詢語句,稱之爲主查詢或外查詢
where和having後面的子查詢
特點:
①子查詢放在小括號內
②子查詢一般放在條件的右側
③標量子查詢,一般搭配着單行操作符使用 > < >= <= = <>
列子查詢,一般搭配着多行操作符使用 in 、any/some、 all
④子查詢的執行優先於主查詢執行,主查詢的條件用到了子查詢的結果
標量子查詢
案例1:誰的工資比Abel高?
①查詢Abel的工資
②查詢員工薪資>①的
select
`employee_id`,
`last_name`,
salary 薪資
from
`employees`
where salary >
(select
salary
from
`employees`
where `last_name` = 'Abel')
案例2:返回job_id與141號員工相同,salary比143號員工多的員工 姓名,job_id 和 工資
思路:先子查詢的單行單列值,然後再進行
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
select
`last_name`,
`job_id`,
`salary`
from
`employees`
where salary =
(select
min(salary)
from
`employees`)
案例4:查詢最低工資大於50號部門最低工資的部門id和其最低工資
思路:
①查詢50號部門最低工資
②查詢各個部門的最低工資
③查詢各個部門的最低工資 > ①的的部門id和其最低工資
SELECT
MIN(salary) 最低工資,
department_id
FROM
`employees`
GROUP BY `department_id`
HAVING 最低工資 >
(SELECT
MIN(salary)
FROM
`employees`
WHERE `department_id` = 50)
列子查詢(多行子查詢)
案例一、返回location_id是1400或1700的部門中的所有員工姓名
SELECT
`last_name`
FROM
`employees`
WHERE `department_id` IN
(SELECT
`department_id`
FROM
`departments`
WHERE `location_id` IN (1700, 1400))
此題也可以使用內連接:
SELECT
`last_name`
FROM
`employees` e
INNER JOIN `departments` d
WHERE e.`department_id` = d.`department_id`
AND d.`location_id` IN (1700, 1400)
案例2:返回其他部門中比job_id爲‘IT_PROG’部門任一工資低的員工號、姓名、job_id以及salary
注:比X部門任一工資低:小於X部們的任何一個就OK,所以用any關鍵字就OK
SELECT
`employee_id` 員工號,
`last_name` 姓名,
`job_id`,
`salary`
FROM
`employees`
WHERE salary < ANY
(SELECT DISTINCT
salary
FROM
`employees`
WHERE job_id = 'IT_PROG')
AND job_id <> 'IT_PROG'
案例3:返回其他部門中比job_id爲‘IT_PROG’部門所有工資都低的員工的 員工號、姓名、job_id 以及salary
注:任一,所以使用ALL關鍵字
SELECT
`employee_id` 員工號,
`last_name` 姓名,
`job_id`,
`salary`
FROM
`employees`
WHERE salary < ALL
(SELECT DISTINCT
salary
FROM
`employees`
WHERE job_id = 'IT_PROG')
AND job_id <> 'IT_PROG'
-- 或者 --
SELECT
`employee_id` 員工號,
`last_name` 姓名,
`job_id`,
`salary`
FROM
`employees`
WHERE salary <
(SELECT DISTINCT
MIN(salary)
FROM
`employees`
WHERE job_id = 'IT_PROG')
AND job_id <> 'IT_PROG'
行子查詢
...
exits後面的子查詢(相關子查詢)
語法:
exists(完整的查詢語句)
結果:
1或0
案例1:查詢員工名和部門名
select
`department_name`
from
`departments` d
where exists ( -- 存在,
select*
from
`employees` e
where d.`department_id` =e.`department_id` -- 部門編號在員工表中有對應的存在
)
用 in的話
SELECT
`department_name`
FROM
`departments` d
WHERE d.`department_id` IN
(SELECT DISTINCT
`department_id`
FROM
`employees`)
#案例:查詢沒有女朋友的男神信息
使用exists
SELECT
bo.*
FROM
`boys` bo
WHERE NOT EXISTS
(SELECT
*
FROM
`beauty` b
WHERE b.`boyfriend_id` = bo.`id`)
使用 in
SELECT
bo.*
FROM
`boys` bo
WHERE bo.`id` NOT IN
(SELECT DISTINCT
boyfriend_id
FROM
`beauty`)
案例
#1、查詢和zlotkey相同部門的員工姓名和工資
SELECT
`last_name`,
`salary`
FROM
`employees`
WHERE `department_id` =
(SELECT
`department_id`
FROM
`employees`
WHERE `last_name` = 'zlotkey')
#2、查詢工資比公司平均工資高的員工的員工號、姓名和工資
SELECT
`employee_id`,
`last_name`,
`salary`
FROM
`employees`
WHERE salary >
(SELECT
AVG(salary)
FROM
`employees`)
#3、查詢各部門中工資比本部門平均工資高的員工的員工號、姓名和工資
-- 方法一:
SELECT
`employee_id`,
`last_name`,
`salary`
FROM
`employees` e1
WHERE salary >
(SELECT
AVG(salary) AVG,
department_id
FROM
`employees` e2
WHERE e2.`department_id` = e1.`department_id`)
-- 方法二:
SELECT
`employee_id`,
`last_name`,
`salary`
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 e.`salary` > ag_dep.ag
#4、查詢和姓名中包含字母u的員工在相同部門的員工的員工號和姓名
SELECT
`employee_id`,
`last_name`
FROM
`employees`
WHERE `department_id` IN
(SELECT DISTINCT
`department_id`
FROM
`employees`
WHERE `last_name` LIKE '%u%')
#5、查詢在部門的location_id爲1700的部門工作的員工的員工號
SELECT
`employee_id`
FROM
`employees`
WHERE `department_id` = ANY -- 或者 in
(SELECT
`department_id`
FROM
`departments`
WHERE `location_id` = 1700)
#6、查詢管理者是K_ing的員工姓名和工資
SELECT
`last_name`,
`salary`
FROM
`employees`
WHERE `manager_id` IN
(SELECT
`employee_id`
FROM
`employees`
WHERE `last_name` LIKE 'k_ing')
#7、查詢工資最高的員工的姓名,要求first_name和last_name顯示爲一列,列名爲姓.名
SELECT
CONCAT(`first_name`, '.', `last_name`) '姓.名'
FROM
`employees`
WHERE salary =
(SELECT
MAX(salary)
FROM
`employees`)
總結:對於子查詢來說,,SQL書寫步驟可以爲:先寫子SQL語句,再寫主查詢
分頁查詢
應用場景:當要顯示的數據,一頁顯示不全,需要分頁提交SQL請求
語法:
select 查詢列表
from 表
【join type join 表2
on 連接條件
where 篩選條件
group by 分組字段
having 分組後的篩選
order by 排序的字段】
limit offset, size
offset要顯示條目的起始索引(起始索引從0開始)
案例一:查詢前5條員工信息
SELECT
*
FROM
`employees`
LIMIT 0, 5
案例二:查詢第11條到第25條
SELECT
*
FROM
`employees`
LIMIT 10, 15
案例三:有獎金的員工的信息,並且工資較高的前10名顯示出來
SELECT
*
FROM
`employees`
WHERE `commission_pct` IS NOT NULL
ORDER BY salary DESC
LIMIT 0, 10
特點
①limit語句放在查詢語句的最後
②公式
要顯示的頁數page,每頁的條目數size
select * from 表 limit (page-1)*size, size
測試題
一、查詢所有學員的郵箱的用戶名(注:郵箱中@前面的字符)
select
substr(email, 1, instr(email, '@') - 1) 用戶名 -- instr,獲取字符的索引,substr,從指定索引開始截取指定長度的字符串
from
stuinfo
二、查詢男生和女生的個數
SELECT
COUNT(*) 個數, sex
FROM
stuinfo
GROUP BY sex
三、查詢年齡>18歲的所有學生的姓名和年級名稱
SELECT
`name`,
gradeName
FROM
stuinfo s
INNER JOIN grade g
ON s.gradeId = g.id
WHERE s.age > 18
四、查詢哪個年級的學生的最小年齡>20歲
SELECT
MIN(age),
gradeId
FROM
stuinfo
GROUP BY gradeId
HAVING MIN(age) > 20
五、試說出查詢語句中涉及到的所有的關鍵字,以及執行先後順序
select 查詢列表 ⑦
from 表 ①
連接類型 join 表2 ②
on 連接條件 ③
where 篩選條件 ④
group by 分組列表 ⑤
having 分組後的篩選 ⑥
order by 排序列表 ⑧
limit 起始索引, 條目數 ⑨
子查詢經典案例
#1、查詢工資最低的員工信息:last_name, salary
select
`last_name`,
`salary`
from
`employees`
where salary =
(SELECT
MIN(salary)
FROM
`employees`)
#2、查詢平均工資最低的部門信息(@@)
SELECT
*
FROM
`departments`
WHERE `department_id` =
(SELECT
department_id
FROM
`employees`
GROUP BY `department_id`
ORDER BY AVG(salary)
LIMIT 1)
#3、查詢平均工資最低的部門信息和該部門的平均工資
SELECT
d.*, af.ag 平均薪資
FROM
`departments` d
INNER JOIN
(SELECT
AVG(salary) ag,
`department_id`
FROM
`employees`
GROUP BY `department_id`
ORDER BY ag
LIMIT 1) AS af
ON d.`department_id` = af.department_id
#4、查詢平均工資最高的job信息
SELECT
j.*
FROM
`jobs` j
WHERE `job_id` =
(SELECT -- 等於最高平均工資的job_id
`job_id`
FROM
`employees`
GROUP BY `job_id`
HAVING AVG(salary) =
(SELECT
AVG(salary) ag
FROM
`employees`
GROUP BY `job_id`
ORDER BY ag DESC
LIMIT 1)) -- 最高平均工資
#5、查詢平均工資高於公司平均工資的部門有哪些
SELECT
AVG(salary) 平均薪資,
`department_id` 部門號
FROM
`employees`
GROUP BY `department_id`
HAVING AVG(salary) >
(SELECT
AVG(salary)
FROM
`employees`) -- 公司的平均工資
#6、查詢出公司中所有manager的詳細信息
SELECT
e1.*
FROM
`employees` e1
WHERE e1.`department_id` IN
(SELECT DISTINCT
`manager_id`
FROM
`employees` e2)
#7、各個部門中最高工資中最低的那個部門的最低工資是多少
SELECT
*
FROM
`employees`
WHERE `employee_id` IN
(SELECT DISTINCT
`manager_id`
FROM
`employees`)
#8、查詢平均工資最高的部門的manager的詳細信息:last_name,department_id,email,salary
select
`last_name`,
`department_id`,
`email`,
`salary`
from
`employees`
where `employee_id` =
(SELECT
`manager_id`
FROM
`departments`
WHERE `department_id` =
(SELECT
department_id
FROM
`employees`
GROUP BY `department_id`
ORDER BY AVG(salary) DESC
LIMIT 1)) -- 各部門平均薪資最高的部門id))
七、聯合查詢
union 聯合 合併:將多條查詢語句的結果合併成一個結果,支持多個union
引入的案例:查詢部門編號>90或郵箱包含a的員工信息
select * from `employees` where email like '%a%'
union
SELECT * FROM `employees` WHERE `department_id`>90
應用場景:要查詢的結果來自多個表,且多個表沒有直接的聯繫關係
特點:
①要求多條查詢語句的查詢列數是一致的
②要求多條查詢語句的查詢的每一列的類型和順序最好一致
③union關鍵字默認去重,可以使用union all不去重
查詢的爲兩個表的並集,重複項會被去重,如果不想去重,可以使用 union all關鍵字