第一部分:Mysql數據庫基礎知識(一)之 基礎查詢----分組查詢
7、連接查詢
說明:又稱多表查詢,當查詢語句涉及到的字段來自於多個表時,就會用到連接查詢
分類:
按年代分類:
1、sql92標準:僅僅支持內連接
內連接:
等值連接
非等值連接
自連接
2、sql99標準【推薦】:支持內連接+外連接(左外和右外)+交叉連接
按功能分類:
內連接: (INNER) JOIN
等值連接
非等值連接
自連接
外連接:查詢一個表中有,另一個表中沒有的數據
左外連接:LEFT (OUTER) JOIN 左邊的是主表
右外連接:RIGHT (OUTER )JOIN 右邊的是主表
全外連接:FULL (OUTER) JOIN :mysql數據庫不支持
交叉連接:CROSS (OUTER) JOIN 得到的結果就是一個笛卡爾積
SQL92和SQL99的區別:
SQL99,使用JOIN關鍵字代替了之前的逗號,並且將連接條件和篩選條件進行了分離,提高閱讀性!!!
#---------------------------------sql92標準------------------------------------
#一、內連接
語法:
select 查詢列表
from 表1 別名,表2 別名
where 連接條件
and 篩選條件
group by 分組列表
having 分組後篩選
order by 排序列表
執行順序:
1、from子句
2、where子句
3、and子句
4、group by子句
5、having子句
6、select子句
7、order by子句
#一)等值連接
① 多表等值連接的結果爲多表的交集部分
②n表連接,至少需要n-1個連接條件
③ 多表的順序沒有要求
④一般需要爲表起別名
⑤可以搭配前面介紹的所有子句使用,比如排序、分組、篩選
#案例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`;
#2、爲表起別名
①提高語句的簡潔度
②區分多個重名的字段
注意:如果爲表起了別名,則查詢的字段就不能使用原來的表名去限定
#查詢員工名、工種號、工種名
SELECT e.last_name,e.job_id,j.job_title
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`;
#3、可以加篩選
#案例:查詢有獎金的員工名、部門名
SELECT last_name,department_name,commission_pct
FROM employees e,departments d
WHERE e.`department_id`=d.`department_id`
AND e.`commission_pct` IS NOT NULL;
#案例2:查詢城市名中第二個字符爲o的部門名和城市名
SELECT department_name,city
FROM departments d,locations l
WHERE d.`location_id` = l.`location_id`
AND city LIKE '_o%';
#4、可以加分組
#案例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 departments d,employees e
WHERE d.`department_id`=e.`department_id`
AND commission_pct IS NOT NULL
GROUP BY department_name,d.`manager_id`;
#5、可以加排序
#案例:查詢每個工種的工種名和員工的個數,並且按員工個數降序
SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;
#6、可以實現三表連接?
#案例:查詢員工名、部門名和所在的城市
SELECT last_name,department_name,city
FROM employees e,departments d,locations l
WHERE e.`department_id`=d.`department_id`
AND d.`location_id`=l.`location_id`
AND city LIKE 's%'
ORDER BY department_name DESC;
#二)非等值連接(無 = 進行連接)
#案例1:查詢員工的工資和工資級別
SELECT salary,grade_level
FROM employees e,job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_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 別名
【INNER】 JOIN 表名2 別名
ON 連接條件
WHERE 篩選條件
GROUP BY 分組列表
HAVING 分組後篩選
ORDER BY 排序列表;
#一)等值連接
#①簡單連接
#案例:查詢員工名和部門名
SELECT last_name,department_name
FROM departments d
INNER JOIN employees e
ON e.department_id =d.department_id;
#②添加篩選條件
#案例1:查詢部門編號>100的部門名和所在的城市名
SELECT department_name,city
FROM departments d
JOIN locations l
ON d.`location_id` = l.`location_id`
WHERE d.`department_id`>100;
#③添加分組+篩選
#案例1:查詢每個城市的部門個數
SELECT COUNT(*) 部門個數,l.`city`
FROM departments d
INNER JOIN locations l
ON d.`location_id`=l.`location_id`
GROUP BY l.`city`;
#④添加分組+篩選+排序
#案例1:查詢(每個)部門中員工個數>10的部門名,並按員工個數降序
SELECT COUNT(*) 員工個數,d.department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`
GROUP BY d.`department_id`
HAVING 員工個數>10
ORDER BY 員工個數 DESC;
#二)非等值連接
#案例:查詢部門編號在10-90之間的員工的工資級別,並按級別進行分組
SELECT COUNT(*) 個數,grade
FROM employees e
INNER JOIN sal_grade g
ON e.`salary` BETWEEN g.`min_salary` AND g.`max_salary`
WHERE e.`department_id` BETWEEN 10 AND 90
GROUP BY g.grade;
#三)自連接
#案例:查詢員工名和對應的領導名
SELECT e.`last_name`,m.`last_name`
FROM employees e
INNER JOIN employees m
ON e.`manager_id`=m.`employee_id`;
#二、外連接
說明:查詢結果爲主表中所有的記錄,如果從表有匹配項,則顯示匹配項;如果從表沒有匹配項,則顯示null
應用場景:一般用於查詢主表中有但從表沒有的記錄
特點:
1、外連接分主從表,兩表的順序不能任意調換
2、左外連接的話,left join左邊爲主表
右外連接的話,right join右邊爲主表
語法:
select 查詢列表
from 表1 別名
left|right|full 【outer】 join 表2 別名
on 連接條件
where 篩選條件;
USE girls;
#案例1:查詢所有女神記錄(主表),以及對應的男神名,如果沒有對應的男神,則顯示爲null
#左外連接
SELECT b.*,bo.*
FROM beauty b
LEFT JOIN boys bo
ON b.`boyfriend_id` = bo.`id`;
#右連接
SELECT b.*,bo.*
FROM boys bo
RIGHT JOIN beauty b ON b.`boyfriend_id` = bo.`id`;
#案例2:查哪個女神沒有男朋友
#左連接
SELECT b.`name`
FROM beauty b
LEFT JOIN boys bo ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id` IS NULL;
#右連接(同上)
SELECT b.*,bo.*
FROM boys bo
RIGHT JOIN beauty b ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id` IS NULL;
#案例3:查詢哪個部門沒有員工,並顯示其部門編號和部門名
SELECT COUNT(*) 部門個數
FROM departments d
LEFT JOIN employees e ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;
8、子查詢
說明:當一個查詢語句中又嵌套了另一個完整的select語句,則被嵌套的select語句稱爲子查詢或內查詢
外面的select語句稱爲主查詢或外查詢。
分類:
按子查詢出現的位置進行分類:
1、select後面
要求:子查詢的結果爲單行單列(標量子查詢)
2、from後面
要求:子查詢的結果可以爲多行多列
3、where或having後面 ★
要求:子查詢的結果必須爲單列
單行子查詢
多行子查詢
4、exists後面
要求:子查詢結果必須爲單列(相關子查詢)
特點:
1、子查詢放在條件中,要求必須放在條件的右側
2、子查詢一般放在小括號中
3、子查詢的執行優先於主查詢
4、單行子查詢對應了 單行操作符:> < >= <= = <>
多行子查詢對應了 多行操作符:any/some all in
*/
#一、放在where或having後面
#一)單行子查詢
#案例1:誰的工資比 Abel 高?
#①查詢Abel的工資
SELECT salary
FROM employees
WHERE last_name = 'Abel'
#②查詢salary>①的員工信息
SELECT last_name,salary
FROM employees
WHERE salary>(
SELECT salary
FROM employees
WHERE last_name <> 'Abel'
);
#案例2:返回job_id與141號員工相同,salary比143號員工多的員工姓名,job_id 和工資
#①查詢141號員工的job_id
SELECT job_id
FROM employees
WHERE employee_id = 141
#②查詢143號員工的salary
SELECT salary
FROM employees
WHERE employee_id = 143
#③查詢job_id=① and salary>②的信息
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 MIN(salary)
FROM employees
#②查詢salary=①的員工的last_name,job_id和salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(
SELECT MIN(salary)
FROM employees
);
#案例4:查詢最低工資大於50號部門最低工資的部門id和其最低工資
#①查詢50號部門的最低工資
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
#②查詢各部門的最低工資,篩選看哪個部門的最低工資>①
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
#二)多行子查詢
in:判斷某字段是否在指定列表內
x in(10,30,50)
any/some:判斷某字段的值是否滿足其中任意一個
x>any(10,30,50)
x>min()
x=any(10,30,50)
x in(10,30,50)
all:判斷某字段的值是否滿足裏面所有的
x >all(10,30,50)
x >max()
#案例1:返回location_id是1400或1700的部門中的所有員工姓名
#①查詢location_id是1400或1700的部門
SELECT department_id
FROM departments
WHERE location_id IN(1400,1700)
#②查詢department_id = ①的姓名
SELECT last_name
FROM employees
WHERE department_id IN(
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
);
#題目:返回其它部門中比job_id爲‘IT_PROG’部門任一工資低的員工的員工號、姓名、job_id 以及salary
#①查詢job_id爲‘IT_PROG’部門的工資
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
#②查詢其他部門的工資<任意一個①的結果
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<ANY(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
);
等價於
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<(
SELECT MAX(salary)
FROM employees
WHERE job_id = 'IT_PROG'
);
#案例3:返回其它部門中比job_id爲‘IT_PROG’部門所有工資都低的員工 的員工號、姓名、job_id 以及salary
#①查詢job_id爲‘IT_PROG’部門的工資
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
#②查詢其他部門的工資<所有①的結果
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<ALL(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
);
等價於
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<(
SELECT MIN(salary)
FROM employees
WHERE job_id = 'IT_PROG'
);
#二、放在select後面
#案例;查詢部門編號是50的員工個數
SELECT
(
SELECT COUNT(*)
FROM employees
WHERE department_id = 50
) 個數;
#三、放在from後面(子查詢的結果就是一張表)
#案例:查詢每個部門的平均工資的工資級別
#①查詢每個部門的平均工資
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#②將①和sal_grade兩表連接查詢
SELECT dep_ag.department_id,dep_ag.ag,g.grade
FROM sal_grade g
JOIN (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) dep_ag ON dep_ag.ag BETWEEN g.min_salary AND g.max_salary;
#四、放在exists後面
#案例1 :查詢有無名字叫“Abel”的員工信息
SELECT EXISTS(
SELECT *
FROM employees
WHERE last_name = 'Abel'
) 有無Abel;
#案例2:查詢沒有女朋友的男神信息
USE girls;
SELECT bo.*
FROM boys bo
WHERE bo.`id` NOT IN(
SELECT boyfriend_id
FROM beauty b
)
SELECT bo.*
FROM boys bo
WHERE NOT EXISTS(
SELECT boyfriend_id
FROM beauty b
WHERE bo.id = b.boyfriend_id
);
9、分頁查詢(重要)
應用場景:當頁面上的數據,一頁顯示不全,則需要分頁顯示
分頁查詢的sql命令請求數據庫服務器——>服務器響應查詢到的多條數據——>前臺頁面
語法:
select 查詢列表
from 表1 別名
join 表2 別名
on 連接條件
where 篩選條件
group by 分組
having 分組後篩選
order by 排序列表
limit 起始條目索引,顯示的條目數
執行順序:
1》from子句
2》join子句
3》on子句
4》where子句
5》group by子句
6》having子句
7》select子句
8》order by子句
9》limit子句
特點:
①起始條目索引如果不寫,默認是0
②limit後面支持兩個參數
參數1:顯示的起始條目索引
參數2:條目數
公式:
假如要顯示的頁數是page,每頁顯示的條目數爲size
select *
from employees
limit (page-1)*size,size;
page size=10
1 limit 0,10
2 limit 10,10
3 limit 20,10
4 limit 30,10
10、union聯合查詢
說明:當查詢結果來自於多張表,但多張表之間沒有關聯,這個時候往往使用聯合查詢,也稱爲union查詢
語法:
select 查詢列表 from 表1 where 篩選條件
union
select 查詢列表 from 表2 where 篩選條件
特點:
1、多條待聯合的查詢語句的查詢列數必須一致,查詢類型、字段意義最好一致
2、union實現去重查詢
union all 實現全部查詢,包含重複項
#案例:查詢所有國家的年齡>20歲的用戶信息
SELECT * FROM usa WHERE uage >20
UNION
SELECT * FROM chinese WHERE age >20 ;