MySQL數據庫
全部SQL源文件鏈接:https://pan.baidu.com/s/1wc51qkVetSRybFzcIYGBIg
提取碼:3wpt
DQL語言
連接查詢
-
含義:又稱多表查詢,當查詢的數據來自多個表時,就會用到連接查詢
-
笛卡爾乘積現象:表1 有m行,表2有n行,結果=m*n行
-
發生原因:沒有有效的連接條件
-
如何避免:添加有效的連接條件
-
分類
按年代分類:
sql92標準:僅僅支持內連接
sql99標準【推薦】:支持內連接+外連接(左外和右外)+交叉連接
按功能分類:
內連接:
等值連接
非等值連接
自連接
外連接:
左外連接
右外連接
全外連接
交叉連接
sql92標準案例
#1、等值連接
/*
1.多表等值連接的結果爲多表的交集部分
2.n表連接,至少需要n-1個連接條件
3.多表的順序沒有要求
4.一般需要爲表起別名
5.可以搭配前面介紹的所有子句使用,比如排序、分組、篩選
*/
#案例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、爲表起別名
/*
1.提高語句的簡潔度
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 e.last_name,e.job_id,j.job_title
FROM jobs j,employees e
WHERE e.`job_id`=j.`job_id`;
#4、可以加篩選
#案例:查詢有獎金的員工名、部門名
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%';
#5、可以加分組
#案例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`;
#6、可以加排序
#案例:查詢每個工種的工種名和員工的個數,並且按員工個數降序
SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;
#7、可以實現三表連接?
#案例:查詢員工名、部門名和所在的城市
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;
#2、非等值連接
#案例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 salary,employee_id from employees;
select * from job_grades;
CREATE TABLE job_grades
(grade_level VARCHAR(3),
lowest_sal int,
highest_sal int);
INSERT INTO job_grades
VALUES ('A', 1000, 2999);
INSERT INTO job_grades
VALUES ('B', 3000, 5999);
INSERT INTO job_grades
VALUES('C', 6000, 9999);
INSERT INTO job_grades
VALUES('D', 10000, 14999);
INSERT INTO job_grades
VALUES('E', 15000, 24999);
INSERT INTO job_grades
VALUES('F', 25000, 40000);
*/
#3、自連接
#案例:查詢 員工名和上級的名稱
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
外連接
左外(★):left 【outer】
右外(★):right 【outer】
全外:full【outer】
交叉連接:cross
- 案例
#一、內連接
/*
語法:
select 查詢列表
from 表1 別名
inner join 表2 別名
on 連接條件;
分類:
等值
非等值
自連接
特點:
①添加排序、分組、篩選
②inner可以省略
③ 篩選條件放在where後面,連接條件放在on後面,提高分離性,便於閱讀
④inner join連接和sql92語法中的等值連接效果是一樣的,都是查詢多表的交集
*/
#1、等值連接
#案例1.查詢員工名、部門名
SELECT last_name,department_name FROM departments d
INNER JOIN employees e
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
HAVING 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`
ORDER BY department_name DESC;
#二、非等值連接
#查詢員工的工資級別
SELECT salary,grade_level
FROM employees e
JOIN job_grades g
ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
#查詢工資級別的個數>20的個數,並且按工資級別降序
SELECT COUNT(*),grade_level
FROM employees e
JOIN job_grades g
ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
GROUP BY grade_level
HAVING COUNT(*)>20
ORDER BY grade_level DESC;
#三、自連接
#查詢員工的名字、上級的名字
SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m
ON e.`manager_id`= m.`employee_id`;
#查詢姓名中包含字符k的員工的名字、上級的名字
SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m
ON e.`manager_id`= m.`employee_id`
WHERE e.`last_name` LIKE '%k%';
#二、外連接
/*
應用場景:用於查詢一個表中有,另一個表沒有的記錄
特點:
1、外連接的查詢結果爲主表中的所有記錄
如果從表中有和它匹配的,則顯示匹配的值
如果從表中沒有和它匹配的,則顯示null
外連接查詢結果=內連接結果+主表中有而從表沒有的記錄
2、左外連接,left join左邊的是主表
右外連接,right join右邊的是主表
3、左外和右外交換兩個表的順序,可以實現同樣的效果
4、全外連接=內連接的結果+表1中有但表2沒有的+表2中有但表1沒有的
*/
#引入:查詢男朋友 不在男神表的的女神名
SELECT * FROM beauty;
SELECT * FROM boys;
#左外連接
SELECT b.*,bo.* FROM boys bo
LEFT OUTER JOIN beauty b
ON b.`boyfriend_id` = bo.`id`
WHERE b.`id` IS 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;
#右外
SELECT d.*,e.employee_id
FROM employees e
RIGHT OUTER JOIN departments d
ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;
#全外
USE girls;
SELECT b.*,bo.* FROM beauty b
FULL OUTER JOIN boys bo
ON b.`boyfriend_id` = bo.id;
#交叉連接
SELECT b.*,bo.* FROM beauty b
CROSS JOIN boys bo;
sql92和sql99對比
- 功能:sql99支持的較多
- 可讀性:sql99實現連接條件和篩選條件的分離,可讀性較高
子查詢
- 含義:出現在其他語句中的select語句,稱爲子查詢或內查詢外部的查詢語句,稱爲主查詢或外查詢。
- 分類
- 案例
#一、where或having後面
/*
1、標量子查詢(單行子查詢)
2、列子查詢(多行子查詢)
3、行子查詢(多列多行)
特點:
①子查詢放在小括號內
②子查詢一般放在條件的右側
③標量子查詢,一般搭配着單行操作符使用
> < >= <= = <>
列子查詢,一般搭配着多行操作符使用
in、any/some、all
④子查詢的執行優先於主查詢執行,主查詢的條件用到了子查詢的結果
*/
#1.標量子查詢★
#案例1:誰的工資比 Abel 高?
#①查詢Abel的工資
SELECT salary
FROM employees
WHERE last_name = 'Abel';
#②查詢員工的信息,滿足 salary>①結果
SELECT *
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 和工資,要求job_id=①並且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;
#②查詢last_name,job_id和salary,要求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;
#③ 在②基礎上篩選,滿足min(salary)>①
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 = 250
);
#2.列子查詢(多行子查詢)★
#案例1:返回location_id是1400或1700的部門中的所有員工姓名
#①查詢location_id是1400或1700的部門編號
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700);
#②查詢員工姓名,要求部門號是①列表中的某一個
SELECT last_name
FROM employees
WHERE department_id <>ALL(
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
);
#案例2:返回其它工種中比job_id爲‘IT_PROG’工種任一工資低的員工的員工號、姓名、job_id 以及salary
#①查詢job_id爲‘IT_PROG’部門任一工資
SELECT DISTINCT salary FROM employees
WHERE job_id = 'IT_PROG';
#②查詢員工號、姓名、job_id 以及salary,salary<(①)的任意一個
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';
#案例3:返回其它部門中比job_id爲‘IT_PROG’部門所有工資都低的員工 的員工號、姓名、job_id 以及salary
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ALL(
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 MIN( salary)
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
#3、行子查詢(結果集一行多列或多行多列)
#案例:查詢員工編號最小並且工資最高的員工信息
SELECT * FROM employees
WHERE (employee_id,salary)=(
SELECT MIN(employee_id),MAX(salary)
FROM employees
);
#①查詢最小的員工編號
SELECT MIN(employee_id) FROM employees;
#②查詢最高工資
SELECT MAX(salary) FROM employees;
#③查詢員工信息
SELECT * FROM employees
WHERE employee_id=(
SELECT MIN(employee_id)
FROM employees
)AND salary=(
SELECT MAX(salary)
FROM employees
);
#二、select後面
/*
僅僅支持標量子查詢
*/
#案例:查詢每個部門的員工個數
SELECT d.*,(
SELECT COUNT(*)
FROM employees e
WHERE e.department_id = d.`department_id`
) 個數
FROM departments d;
#案例2:查詢員工號=102的部門名
SELECT (
SELECT department_name,e.department_id
FROM departments d
INNER JOIN employees e
ON d.department_id=e.department_id
WHERE e.employee_id=102
) 部門名;
#三、from後面
/*
將子查詢結果充當一張表,要求必須起別名
*/
#案例:查詢每個部門的平均工資的工資等級
#①查詢每個部門的平均工資
SELECT AVG(salary),department_id
FROM employees GROUP BY department_id;
SELECT * FROM job_grades;
#②連接①的結果集和job_grades表,篩選條件平均工資 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_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
#四、exists後面(相關子查詢)
/*
語法:
exists(完整的查詢語句)
結果:
1或0
*/
SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=300000);
#案例1:查詢有員工的部門名
#in
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
SELECT department_id
FROM employees
);
#exists
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE d.`department_id`=e.`department_id`
);
#案例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`
);
分頁查詢
- 應用場景:當要顯示的數據,一頁顯示不全,需要分頁提交sql請求。
- 語法
select 查詢列表
from 表
【join type join 表2
on 連接條件
where 篩選條件
group by 分組字段
having 分組後的篩選
order by 排序的字段】
limit 【offset,】size;
注意
offset要顯示條目的起始索引(起始索引從0開始)
size 要顯示的條目個數
- 特點
①limit語句放在查詢語句的最後
②公式
要顯示的頁數 page,每頁的條目數size
select 查詢列表 from 表
limit (page-1)*size,size;
size=10
page
1 0
2 10
3 20
- 案例
#案例1:查詢前五條員工信息
SELECT * FROM employees LIMIT 0,5;
SELECT * FROM employees LIMIT 5;
#案例2:查詢第11條——第25條
SELECT * FROM employees LIMIT 10,15;
#案例3:有獎金的員工信息,並且工資較高的前10名顯示出來
SELECT * FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC LIMIT 10 ;
聯合查詢
- 含義:union (聯合、合併):將多條查詢語句的結果合併成一個結果。
- 語法
查詢語句1
union 【all】
查詢語句2
union 【all】
...
-
意義
- 1、將一條比較複雜的查詢語句拆分成多條語句
- 2、適用於查詢多個表的時候,查詢的列基本是一致。
-
特點
- 1、要求多條查詢語句的查詢列數是一致的!
- 2、要求多條查詢語句的查詢的每一列的類型和順序最好一致
- 3、union關鍵字默認去重,如果使用union all 可以包含重複項
-
案例
#引入的案例:查詢部門編號>90或郵箱包含a的員工信息
SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90;
#案例:查詢中國用戶中男性的信息以及外國用戶中年男性的用戶信息
SELECT id,cname,csex FROM t_ca WHERE csex='男'
UNION
SELECT t_id,tName,tGender FROM t_ua WHERE tGender='male';
- 此處需要的數據庫源文件
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50145
Source Host : localhost:3306
Source Schema : test
Target Server Type : MySQL
Target Server Version : 50145
File Encoding : 65001
Date: 03/07/2020 11:08:32
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_ca
-- ----------------------------
DROP TABLE IF EXISTS `t_ca`;
CREATE TABLE `t_ca` (
`id` int(20) NOT NULL,
`cname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`csex` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of t_ca
-- ----------------------------
INSERT INTO `t_ca` VALUES (1, '韓梅梅', '女');
INSERT INTO `t_ca` VALUES (2, '李雷', '男');
INSERT INTO `t_ca` VALUES (3, '李明', '男');
SET FOREIGN_KEY_CHECKS = 1;
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50145
Source Host : localhost:3306
Source Schema : test
Target Server Type : MySQL
Target Server Version : 50145
File Encoding : 65001
Date: 03/07/2020 11:09:05
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_ua
-- ----------------------------
DROP TABLE IF EXISTS `t_ua`;
CREATE TABLE `t_ua` (
`t_id` int(11) NOT NULL,
`tName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`tGender` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`t_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of t_ua
-- ----------------------------
INSERT INTO `t_ua` VALUES (1, 'john', 'male');
INSERT INTO `t_ua` VALUES (2, 'lucy', 'female');
INSERT INTO `t_ua` VALUES (3, 'lily', 'female');
INSERT INTO `t_ua` VALUES (4, 'jack', 'male');
INSERT INTO `t_ua` VALUES (5, 'rose', 'female');
SET FOREIGN_KEY_CHECKS = 1;