1.select,2.运算符,3.排序和分页,4.多表查询(重要),5.单行函数,6.多行函数,7.子查询(重要)
数据表格式如图
1.select
SQL的规范 ----建议遵守
- MySQL 在 Windows 环境下是大小写不敏感的
- MySQL 在 Linux 环境下是大小写敏感的- 数据库名、表名、表的别名、变量名是严格区分大小写的
- 关键字、函数名、列名(或字段名)、列的别名(字段的别名) 是忽略大小写的。
- 推荐采用统一的书写规范: - 数据库名、表名、表别名、字段名、字段别名等都小写
- SQL 关键字、函数名、绑定变量等都大写
. 导入现有的数据表、表的数据。
方式1:source 文件的全路径名
举例:source d:\atguigudb.sql;
最基本的SELECT语句: SELECT 字段1,字段2,… FROM 表名
:表中的所有的字段(或列)
SELECT * FROM employees;
列的别名
as:全称:alias(别名),可以省略
列的别名可以使用一对""引起来,不要使用’'。
SELECT employee_id emp_id,last_name AS lname,department_id “部门id”,salary * 12 AS “annual sal”
FROM employees;
去除重复行
#查询员工表中一共有哪些部门id呢?
#错误的:没有去重的情况
SELECT department_id
FROM employees;
#正确的:去重的情况
SELECT DISTINCT department_id
FROM employees;
#8. 空值参与运算
#1. 空值:null
2. null不等同于0,‘’,‘null’
SELECT * FROM employees;
#3. 空值参与运算:结果一定也为空。
SELECT employee_id,salary “月工资”,salary * (1 + commission_pct) * 12 “年工资”,commission_pct
FROM employees;
#实际问题的解决方案:引入IFNULL
SELECT employee_id,salary “月工资”,salary * (1 + IFNULL(commission_pct,0)) * 12 “年工资”,commission_pct
FROM employees
;
过滤数据
SELECT *
FROM employees
#过滤条件,声明在FROM结构的后面
WHERE department_id = 90;
查询last_name为’King’的员工信息
SELECT *
FROM EMPLOYEES
WHERE LAST_NAME = ‘King’;
select练习
#1.查询员工12个月的工资总和,并起别名为ANNUAL SALARY
#理解1:计算12月的基本工资
SELECT employee_id,last_name,salary * 12 “ANNUAL SALARY”
FROM employees;
#理解2:计算12月的基本工资和奖金
SELECT employee_id,last_name,salary * 12 * (1 + IFNULL(commission_pct,0)) “ANNUAL SALARY”
FROM employees;
2.查询employees表中去除重复的job_id以后的数据
SELECT DISTINCT job_id
FROM employees;
3.查询工资大于12000的员工姓名和工资
SELECT last_name,salary
FROM employees
WHERE salary > 12000;
4.查询员工号为176的员工的姓名和部门号
SELECT last_name,department_id
FROM employees
WHERE employee_id = 176;
5.显示表 departments 的结构,并查询其中的全部数据
DESCRIBE departments;
SELECT * FROM departments;
2.运算符
算术运算符: + - * / div % mod
SELECT 100 + NULL # null值参与运算,结果为null
FROM DUAL;
#练习:查询员工id为偶数的员工信息
SELECT employee_id,last_name,salary
FROM employees
WHERE employee_id % 2 = 0;
#2. 比较运算符
#2.1 = <=> <> != < <= > >=
<=> :安全等于。 记忆技巧:为NULL而生。
#① IS NULL \ IS NOT NULL \ ISNULL
#练习:查询表中commission_pct为null的数据有哪些
SELECT last_name,salary,commission_pct
FROM employees
WHERE commission_pct IS NULL;
#练习:查询表中commission_pct不为null的数据有哪些
SELECT last_name,salary,commission_pct
FROM employees
WHERE commission_pct IS NOT NULL;
#③ BETWEEN 条件下界1 AND 条件上界2 (查询条件1和条件2范围内的数据,包含边界)
#查询工资在6000 到 8000的员工信息
SELECT employee_id,last_name,salary
FROM employees
#where salary between 6000 and 8000;
WHERE salary >= 6000 && salary <= 8000;
#练习:查询部门为10,20,30部门的员工信息
SELECT last_name,salary,department_id
FROM employees
#where department_id = 10 or department_id = 20 or department_id = 30;
WHERE department_id IN (10,20,30);
#练习:查询工资不是6000,7000,8000的员工信息
SELECT last_name,salary,department_id
FROM employees
WHERE salary NOT IN (6000,7000,8000);
#⑤ LIKE :模糊查询
% : 代表不确定个数的字符 (0个,1个,或多个)
#练习:查询last_name中包含字符’a’的员工信息
SELECT last_name
FROM employees
WHERE last_name LIKE ‘%a%’;
#练习:查询last_name中以字符’a’开头的员工信息
SELECT last_name
FROM employees
WHERE last_name LIKE ‘a%’;
#练习:查询last_name中包含字符’a’且包含字符’e’的员工信息
#写法1:
SELECT last_name
FROM employees
WHERE last_name LIKE ‘%a%’ AND last_name LIKE ‘%e%’;
_ :代表一个不确定的字符
#练习:查询第3个字符是’a’的员工信息
SELECT last_name
FROM employees
WHERE last_name LIKE ‘__a%’;
#练习:查询第2个字符是_且第3个字符是’a’的员工信息
#需要使用转义字符: \
SELECT last_name
FROM employees
WHERE last_name LIKE ‘__a%’;
#3. 逻辑运算符: OR || AND && NOT ! XOR
#or and
SELECT last_name,salary,department_id
FROM employees
#where department_id = 10 or department_id = 20;
#where department_id = 10 and department_id = 20;
WHERE department_id = 50 AND salary > 6000;
#not
SELECT last_name,salary,department_id
FROM employees
#where salary not between 6000 and 8000;
#where commission_pct is not null;
WHERE NOT commission_pct <=> NULL;
#XOR :追求的"异"
SELECT last_name,salary,department_id
FROM employees
WHERE department_id = 50 XOR salary > 6000;
#注意:AND的优先级高于OR
#4. 位运算符: & | ^ ~ >> <<
SELECT 12 & 5, 12 | 5,12 ^ 5
FROM DUAL;
SELECT 10 & ~1 FROM DUAL;
#在一定范围内满足:每向左移动1位,相当于乘以2;每向右移动一位,相当于除以2。
SELECT 4 << 1 , 8 >> 1
FROM DUAL;
运算符练习
#1.选择工资不在5000到12000的员工的姓名和工资
SELECT last_name,salary
FROM employees
#where salary not between 5000 and 12000;
WHERE salary < 5000 OR salary > 12000;
#2.选择在20或50号部门工作的员工姓名和部门号
SELECT last_name,department_id
FROM employees
#where department_id in (20,50);
WHERE department_id = 20 OR department_id = 50;
#3.选择公司中没有管理者的员工姓名及job_id
SELECT last_name,job_id,manager_id
FROM employees
WHERE manager_id IS NULL;
#4.选择公司中有奖金的员工姓名,工资和奖金级别
SELECT last_name,salary,commission_pct
FROM employees
WHERE commission_pct IS NOT NULL;
#5.选择员工姓名的第三个字母是a的员工姓名
SELECT last_name
FROM employees
WHERE last_name LIKE ‘__a%’;
#6.选择姓名中有字母a和k的员工姓名
SELECT last_name
FROM employees
WHERE last_name LIKE ‘%a%k%’ OR last_name LIKE ‘%k%a%’;
#where last_name like ‘%a%’ and last_name LIKE ‘%k%’;
#7.显示出表 employees 表中 first_name 以 'e’结尾的员工信息
SELECT first_name,last_name
FROM employees
WHERE first_name LIKE ‘%e’;
#8.显示出表 employees 部门编号在 80-100 之间的姓名、工种
SELECT last_name,job_id
FROM employees
WHERE department_id BETWEEN 80 AND 100;
#9.显示出表 employees 的 manager_id 是 100,101,110 的员工姓名、工资、管理者id
SELECT last_name,salary,manager_id
FROM employees
WHERE manager_id IN (100,101,110);
3.排序和分页
使用 ORDER BY 对查询到的数据进行排序操作。
升序:ASC (ascend)
降序:DESC (descend)
#练习:按照salary从高到低的顺序显示员工信息
SELECT employee_id,last_name,salary
FROM employees
ORDER BY salary DESC;
#练习:按照salary从低到高的顺序显示员工信息
SELECT employee_id,last_name,salary
FROM employees
ORDER BY salary ASC;
#2. 我们可以使用列的别名,进行排序
SELECT employee_id,salary,salary * 12 annual_sal
FROM employees
ORDER BY annual_sal;
#列的别名只能在 ORDER BY 中使用,不能在WHERE中使用。
#3. 强调格式:WHERE 需要声明在FROM后,ORDER BY之前。
SELECT employee_id,salary
FROM employees
WHERE department_id IN (50,60,70)
ORDER BY department_id DESC;
#练习:显示员工信息,按照department_id的降序排列,salary的升序排列
SELECT employee_id,salary,department_id
FROM employees
ORDER BY department_id DESC,salary ASC;
#2.1 mysql使用limit实现数据的分页显示
需求:每页显示20条记录,此时显示第1页
SELECT employee_id,last_name
FROM employees
LIMIT 0,20;
需求2:每页显示20条记录,此时显示第2页
SELECT employee_id,last_name
FROM employees
LIMIT 20,20;
需求3:每页显示20条记录,此时显示第3页
SELECT employee_id,last_name
FROM employees
LIMIT 40,20;
需求:每页显示pageSize条记录,此时显示第pageNo页:
公式:LIMIT (pageNo-1) * pageSize,pageSize;
排序和分页练习;
#1. 查询员工的姓名和部门号和年薪,按年薪降序,按姓名升序显示
SELECT last_name,department_id,salary * 12 annual_salary
FROM employees
ORDER BY annual_salary DESC,last_name ASC;
#2. 选择工资不在 8000 到 17000 的员工的姓名和工资,按工资降序,显示第21到40位置的数据
SELECT last_name,salary
FROM employees
WHERE salary NOT BETWEEN 8000 AND 17000
ORDER BY salary DESC
LIMIT 20,20;
#3. 查询邮箱中包含 e 的员工信息,并先按邮箱的字节数降序,再按部门号升序
SELECT employee_id,last_name,email,department_id
FROM employees
#where email like ‘%e%’
WHERE email REGEXP ‘[e]’
ORDER BY LENGTH(email) DESC,department_id;
多表查询*
标准顺序
SELECT …,…,…
FROM …
WHERE … AND / OR / NOT…
ORDER BY … (ASC/DESC),…,…
LIMIT …,…
#查询员工名为’Abel’的人在哪个城市工作?
SELECT *
FROM employees
WHERE last_name = ‘Abel’;
#3. 多表查询的正确方式:需要有连接条件
SELECT employee_id,department_name
FROM employees,departments
#两个表的连接条件
WHERE employees.department_id
= departments.department_id;
#4. 如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表。
SELECT employees.employee_id,departments.department_name,employees.department_id
FROM employees,departments
WHERE employees.department_id
= departments.department_id;
#5. 可以给表起别名,在SELECT和WHERE中使用表的别名。
SELECT emp.employee_id,dept.department_name,emp.department_id
FROM employees emp,departments dept
WHERE emp.department_id
= dept.department_id;
#6. 结论:如果有n个表实现多表的查询,则需要至少n-1个连接条件
#练习:查询员工的employee_id,last_name,department_name,city
SELECT e.employee_id,e.last_name,d.department_name,l.city,e.department_id,l.location_id
FROM employees e,departments d,locations l
WHERE e.department_id
= d.department_id
AND d.location_id
= l.location_id
;
角度1:等值连接 vs 非等值连接
角度2:自连接 vs 非自连接
角度3:内连接 vs 外连接
#非等值连接的例子:
SELECT e.last_name,e.salary,j.grade_level
FROM employees e,job_grades j
#where e.salary
between j.lowest_sal
and j.highest_sal
;
WHERE e.salary
>= j.lowest_sal
AND e.salary
<= j.highest_sal
;
#自连接的例子:
#练习:查询员工id,员工姓名及其管理者的id和姓名
SELECT emp.employee_id,emp.last_name,mgr.employee_id,mgr.last_name
FROM employees emp ,employees mgr
WHERE emp.manager_id
= mgr.employee_id
;
#内连接:合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.department_id
= d.department_id;
#外连接的分类:左外连接、右外连接、满外连接
#左外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回左表中不满足条件的行,这种连接称为左外连接。
#右外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回右表中不满足条件的行,这种连接称为右外连接。
#SQL99语法实现内连接:
SELECT last_name,department_name
FROM employees e INNER JOIN departments d
ON e.department_id
= d.department_id
;
#SQL99语法实现外连接:
#练习:查询所有的员工的last_name,department_name信息
#左外连接:
SELECT last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id
= d.department_id
;
#右外连接:
SELECT last_name,department_name
FROM employees e RIGHT OUTER JOIN departments d
ON e.department_id
= d.department_id
;
#8. UNION 和 UNION ALL的使用
#UNION:会执行去重操作
#UNION ALL:不会执行去重操作
中图:内连接
SELECT employee_id,department_name
FROM employees e JOIN departments d
ON e.department_id
= d.department_id
;
左上图:左外连接
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id
= d.department_id
;
右上图:右外连接
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id
= d.department_id
;
左中图:
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id
= d.department_id
WHERE d.department_id
IS NULL;
右中图:
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id
= d.department_id
WHERE e.department_id
IS NULL;
左下图:满外连接
方式1:左上图 UNION ALL 右中图
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id
= d.department_id
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id
= d.department_id
WHERE e.department_id
IS NULL;
右下图:左中图 UNION ALL 右中图
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id
= d.department_id
WHERE d.department_id
IS NULL
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id
= d.department_id
WHERE e.department_id
IS NULL;
多表查询练习:
#1.显示所有员工的姓名,部门号和部门名称。
SELECT e.last_name,e.department_id,d.department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.department_id
= d.department_id
;
#2.查询90号部门员工的job_id和90号部门的location_id
SELECT e.job_id,d.location_id
FROM employees e JOIN departments d
ON e.department_id
= d.department_id
WHERE d.department_id
= 90;
#3.选择所有有奖金的员工的 last_name , department_name , location_id , city
SELECT e.last_name ,e.commission_pct
, d.department_name , d.location_id , l.city
FROM employees e LEFT JOIN departments d
ON e.department_id
= d.department_id
LEFT JOIN locations l
ON d.location_id
= l.location_id
WHERE e.commission_pct
IS NOT NULL;
#4.选择city在Toronto工作的员工的 last_name , job_id , department_id , department_name
SELECT e.last_name , e.job_id , e.department_id , d.department_name
FROM employees e JOIN departments d
ON e.department_id
= d.department_id
JOIN locations l
ON d.location_id
= l.location_id
WHERE l.city
= ‘Toronto’;
#5.查询员工所在的部门名称、部门地址、姓名、工作、工资,其中员工所在部门的部门名称为’Executive’
SELECT d.department_name,l.street_address,e.last_name,e.job_id,e.salary
FROM departments d LEFT JOIN employees e
ON e.department_id
= d.department_id
LEFT JOIN locations l
ON d.location_id
= l.location_id
WHERE d.department_name
= ‘Executive’;
#6.选择指定员工的姓名,员工号,以及他的管理者的姓名和员工号,结果类似于下面的格式
employees Emp# manager Mgr#
kochhar 101 king 100
SELECT emp.last_name “employees”,emp.employee_id “Emp#”,mgr.last_name “manager”, mgr.employee_id “Mgr#”
FROM employees emp LEFT JOIN employees mgr
ON emp.manager_id = mgr.employee_id;
#7.查询哪些部门没有员工
SELECT d.department_id
FROM departments d LEFT JOIN employees e
ON d.department_id
= e.department_id
WHERE e.department_id
IS NULL;
#8. 查询哪个城市没有部门
SELECT l.location_id,l.city
FROM locations l LEFT JOIN departments d
ON l.location_id
= d.location_id
WHERE d.location_id
IS NULL;
#9. 查询部门名为 Sales 或 IT 的员工信息
SELECT e.employee_id,e.last_name,e.department_id
FROM employees e JOIN departments d
ON e.department_id
= d.department_id
WHERE d.department_name
IN (‘Sales’,‘IT’);
单行函数
#1.数值函数
#基本的操作
SELECT ABS(-123),ABS(32),SIGN(-23),SIGN(43),PI(),CEIL(32.32),CEILING(-43.23),FLOOR(32.32),
FLOOR(-43.23),MOD(12,5),12 MOD 5,12 % 5
FROM DUAL;
#3.1 获取日期、时间
SELECT CURDATE(),CURRENT_DATE(),CURTIME(),NOW(),SYSDATE(),
UTC_DATE(),UTC_TIME()
FROM DUAL;
#3.3 获取月份、星期、星期数、天数等函数
SELECT YEAR(CURDATE()),MONTH(CURDATE()),DAY(CURDATE()),
HOUR(CURTIME()),MINUTE(NOW()),SECOND(SYSDATE())
FROM DUAL;
#4.流程控制函数
#4.1 IF(VALUE,VALUE1,VALUE2)
SELECT last_name,salary,IF(salary >= 6000,‘高工资’,‘低工资’) “details”
FROM employees;
#4.3 CASE WHEN … THEN …WHEN … THEN … ELSE … END
#类似于java的if … else if … else if … else
SELECT last_name,salary,CASE WHEN salary >= 15000 THEN ‘白骨精’
WHEN salary >= 10000 THEN ‘潜力股’
WHEN salary >= 8000 THEN ‘小屌丝’
ELSE ‘草根’ END “details”,department_id
FROM employees;
练习1
查询部门号为 10,20, 30 的员工信息,
若部门号为 10, 则打印其工资的 1.1 倍,
20 号部门, 则打印其工资的 1.2 倍,
30 号部门,打印其工资的 1.3 倍数,
其他部门,打印其工资的 1.4 倍数
*/
SELECT employee_id,last_name,department_id,salary,CASE department_id WHEN 10 THEN salary * 1.1
WHEN 20 THEN salary * 1.2
WHEN 30 THEN salary * 1.3
ELSE salary * 1.4 END “details”
FROM employees;
练习2
查询部门号为 10,20, 30 的员工信息,
若部门号为 10, 则打印其工资的 1.1 倍,
20 号部门, 则打印其工资的 1.2 倍,
30 号部门打印其工资的 1.3 倍数
*/
SELECT employee_id,last_name,department_id,salary,CASE department_id WHEN 10 THEN salary * 1.1
WHEN 20 THEN salary * 1.2
WHEN 30 THEN salary * 1.3
END “details”
FROM employees
WHERE department_id IN (10,20,30);
单行函数练习:
1.显示系统时间(注:日期+时间)
SELECT NOW(),SYSDATE()
FROM DUAL;
#2.查询员工号,姓名,工资,以及工资提高百分之20%后的结果(new salary)
SELECT employee_id,last_name,salary,salary * 1.2 “new salary”
FROM employees;
#3.将员工的姓名按首字母排序,并写出姓名的长度(length)
SELECT last_name,LENGTH(last_name) “name_length”
FROM employees
#order by last_name asc;
ORDER BY name_length ASC;
#4.查询员工id,last_name,salary,并作为一个列输出,别名为OUT_PUT
SELECT CONCAT(employee_id,‘,’,last_name,‘,’,salary) “OUT_PUT”
FROM employees;
#5.查询公司各员工工作的年数、工作的天数,并按工作年数的降序排序
SELECT employee_id,DATEDIFF(CURDATE(),hire_date)/365 “worked_years”,DATEDIFF(CURDATE(),hire_date) “worked_days”,
TO_DAYS(CURDATE()) - TO_DAYS(hire_date) “worked_days1”
FROM employees
ORDER BY worked_years DESC;
#6.查询员工姓名,hire_date , department_id,满足以下条件:
#雇用时间在1997年之后,department_id 为80 或 90 或110, commission_pct不为空
SELECT last_name,hire_date,department_id
FROM employees
WHERE department_id IN (80,90,110)
AND commission_pct IS NOT NULL
#and hire_date >= ‘1997-01-01’; #存在着隐式转换
#and date_format(hire_date,‘%Y-%m-%d’) >= ‘1997-01-01’; # 显式转换操作,格式化:日期—> 字符串
#and date_format(hire_date,‘%Y’) >= ‘1997’; # 显式转换操作,格式化
AND hire_date >= STR_TO_DATE(‘1997-01-01’,‘%Y-%m-%d’);# 显式转换操作,解析:字符串 ----> 日期
#7.查询公司中入职超过10000天的员工姓名、入职时间
SELECT last_name,hire_date
FROM employees
WHERE DATEDIFF(CURDATE(),hire_date) >= 10000;
#8.做一个查询,产生下面的结果
#<last_name> earns monthly but wants <salary*3>
SELECT CONCAT(last_name,’ earns ',TRUNCATE(salary,0), ’ monthly but wants ',TRUNCATE(salary * 3,0)) “Dream Salary”
FROM employees;
#9.使用case-when,按照下面的条件:
/*job grade
AD_PRES A
ST_MAN B
IT_PROG C
SA_REP D
ST_CLERK E
产生下面的结果:
*/
SELECT last_name “Last_name”,job_id “Job_id”,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 “Grade”
FROM employees;
SELECT last_name “Last_name”,job_id “Job_id”,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’
ELSE “undefined” END “Grade”
FROM employees;
六多行函数(聚合函数)
#1. 常见的几个聚合函数
#1.1 AVG / SUM :只适用于数值类型的字段(或变量)
SELECT AVG(salary),SUM(salary),AVG(salary) * 107
FROM employees;
#1.2 MAX / MIN :适用于数值类型、字符串类型、日期时间类型的字段(或变量)
SELECT MAX(salary),MIN(salary)
FROM employees;
SELECT MAX(last_name),MIN(last_name),MAX(hire_date),MIN(hire_date)
FROM employees;
#1.3 COUNT:
#① 作用:计算指定字段在查询结构中出现的个数(不包含NULL值的)
SELECT COUNT(employee_id),COUNT(salary),COUNT(2 * salary),COUNT(1),COUNT(2),COUNT(*)
FROM employees ;
SELECT *
FROM employees;
#如果计算表中有多少条记录,如何实现?
#方式1:COUNT(*)
#③ 公式:AVG = SUM / COUNT
SELECT AVG(salary),SUM(salary)/COUNT(salary),
AVG(commission_pct),SUM(commission_pct)/COUNT(commission_pct),
SUM(commission_pct) / 107
FROM employees;
#2. GROUP BY 的使用
#需求:查询各个部门的平均工资,最高工资
SELECT department_id,AVG(salary),SUM(salary)
FROM employees
GROUP BY department_id
#需求:查询各个job_id的平均工资
SELECT job_id,AVG(salary)
FROM employees
GROUP BY job_id;
#需求:查询各个department_id,job_id的平均工资
#方式1:
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id,job_id;
#方式2:
SELECT job_id,department_id,AVG(salary)
FROM employees
GROUP BY job_id,department_id;
#3. HAVING的使用 (作用:用来过滤数据的)
#练习:查询各个部门中最高工资比10000高的部门信息
#错误的写法:
SELECT department_id,MAX(salary)
FROM employees
WHERE MAX(salary) > 10000
GROUP BY department_id;
#要求1:如果过滤条件中使用了聚合函数,则必须使用HAVING来替换WHERE。否则,报错。
#要求2:HAVING 必须声明在 GROUP BY 的后面。
#要求3:开发中,我们使用HAVING的前提是SQL中使用了GROUP BY。
#正确的写法:
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) > 10000;
#练习:查询部门id为10,20,30,40这4个部门中最高工资比10000高的部门信息
SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10,20,30,40)
GROUP BY department_id
HAVING MAX(salary) > 10000;
WHERE 与 HAVING 的对比
- 从适用范围上来讲,HAVING的适用范围更广。
- 如果过滤条件中没有聚合函数:这种情况下,WHERE的执行效率要高于HAVING
SELECT …,…,…(存在聚合函数)
FROM … (LEFT / RIGHT)JOIN …ON 多表的连接条件
(LEFT / RIGHT)JOIN … ON …
WHERE 不包含聚合函数的过滤条件
GROUP BY …,…
HAVING 包含聚合函数的过滤条件
ORDER BY …,…(ASC / DESC )
LIMIT …,…
#4.2 SQL语句的执行过程:
#FROM …,…-> ON -> (LEFT/RIGNT JOIN) -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> ORDER BY -> LIMIT
多行函数练习
#1.where子句可否使用组函数进行过滤? No!
#2.查询公司员工工资的最大值,最小值,平均值,总和
SELECT MAX(salary) max_sal ,MIN(salary) mim_sal,AVG(salary) avg_sal,SUM(salary) sum_sal
FROM employees;
#3.查询各job_id的员工工资的最大值,最小值,平均值,总和
SELECT job_id,MAX(salary),MIN(salary),AVG(salary),SUM(salary)
FROM employees
GROUP BY job_id;
#4.选择具有各个job_id的员工人数
SELECT job_id,COUNT(*)
FROM employees
GROUP BY job_id;
#5.查询员工最高工资和最低工资的差距(DIFFERENCE) #DATEDIFF
SELECT MAX(salary) - MIN(salary) “DIFFERENCE”
FROM employees;
#6.查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
SELECT manager_id,MIN(salary)
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING MIN(salary) >= 6000;
#7.查询所有部门的名字,location_id,员工数量和平均工资,并按平均工资降序
SELECT d.department_name,d.location_id,COUNT(employee_id),AVG(salary)
FROM departments d LEFT JOIN employees e
ON d.department_id
= e.department_id
GROUP BY department_name,location_id
#8.查询每个工种、每个部门的部门名、工种名和最低工资
SELECT d.department_name,e.job_id,MIN(salary)
FROM departments d LEFT JOIN employees e
ON d.department_id
= e.department_id
GROUP BY department_name,job_id
子查询
#1. 由一个具体的需求,引入子查询
#需求:谁的工资比Abel的高?
#方式1:
SELECT salary
FROM employees
WHERE last_name = ‘Abel’;
SELECT last_name,salary
FROM employees
WHERE salary > 11000;
#方式2:自连接
SELECT e2.last_name,e2.salary
FROM employees e1,employees e2
WHERE e2.salary
> e1.salary
#多表的连接条件
AND e1.last_name = ‘Abel’;
#方式3:子查询
SELECT last_name,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE last_name = ‘Abel’
);
#子查询的编写技巧:① 从里往外写 ② 从外往里写
#4. 单行子查询
#4.1 单行操作符: = != > >= < <=
#题目:查询工资大于149号员工工资的员工的信息
SELECT employee_id,last_name,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE employee_id = 149
);
#题目:返回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
);
#题目:返回公司工资最少的员工的last_name,job_id和salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary = (
SELECT MIN(salary)
FROM employees
);
#题目:查询与141号员工的manager_id和department_id相同的其他员工
#的employee_id,manager_id,department_id。
#方式1:
SELECT employee_id,manager_id,department_id
FROM employees
WHERE manager_id = (
SELECT manager_id
FROM employees
WHERE employee_id = 141
)
AND department_id = (
SELECT department_id
FROM employees
WHERE employee_id = 141
)
AND employee_id <> 141;
#题目:查询最低工资大于110号部门最低工资的部门id和其最低工资
SELECT department_id,MIN(salary)
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id
HAVING MIN(salary) > (
SELECT MIN(salary)
FROM employees
WHERE department_id = 110
);
#题目:显式员工的employee_id,last_name和location。
#其中,若员工department_id与location_id为1800的department_id相同,
#则location为’Canada’,其余则为’USA’。
SELECT employee_id,last_name,CASE department_id WHEN (SELECT department_id FROM departments WHERE location_id = 1800) THEN ‘Canada’
ELSE ‘USA’ END “location”
FROM employees;
#4.2 子查询中的空值问题
SELECT last_name, job_id
FROM employees
WHERE job_id =
(SELECT job_id
FROM employees
WHERE last_name = ‘Haas’);
#5.2举例:
IN:
SELECT employee_id, last_name
FROM employees
WHERE salary IN
(SELECT MIN(salary)
FROM employees
GROUP BY department_id);
ANY / ALL:
#题目:返回其它job_id中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、
#姓名、job_id 以及salary
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE job_id <> ‘IT_PROG’
AND salary < ANY (
SELECT salary
FROM employees
WHERE job_id = ‘IT_PROG’
);
#题目:返回其它job_id中比job_id为‘IT_PROG’部门所有工资低的员工的员工号、
#姓名、job_id 以及salary
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE job_id <> ‘IT_PROG’
AND salary < ALL (
SELECT salary
FROM employees
WHERE job_id = ‘IT_PROG’
);
#题目:查询平均工资最低的部门id
#MySQL中聚合函数是不能嵌套使用的。
#方式1:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(avg_sal)
FROM(
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
) t_dept_avg_sal
);
#5.3 空值问题
SELECT last_name
FROM employees
WHERE employee_id NOT IN (
SELECT manager_id
FROM employees
);
#6. 相关子查询
#回顾:查询员工中工资大于公司平均工资的员工的last_name,salary和其department_id
#6.1
SELECT last_name,salary,department_id
FROM employees
WHERE salary > (
SELECT AVG(salary)
FROM employees
);
#题目:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
#方式1:使用相关子查询
SELECT last_name,salary,department_id
FROM employees e1
WHERE salary > (
SELECT AVG(salary)
FROM employees e2
WHERE department_id = e1.department_id
);
#题目:查询员工的id,salary,按照department_name 排序
SELECT employee_id,salary
FROM employees e
ORDER BY (
SELECT department_name
FROM departments d
WHERE e.department_id
= d.department_id
) ASC;
#题目:若employees表中employee_id与job_history表中employee_id相同的数目不小于2,
#输出这些相同id的员工的employee_id,last_name和其job_id
SELECT *
FROM job_history;
SELECT employee_id,last_name,job_id
FROM employees e
WHERE 2 <= (
SELECT COUNT(*)
FROM job_history j
WHERE e.employee_id
= j.employee_id
)
#6.2 EXISTS 与 NOT EXISTS关键字
#题目:查询公司管理者的employee_id,last_name,job_id,department_id信息
#方式1:自连接
SELECT DISTINCT mgr.employee_id,mgr.last_name,mgr.job_id,mgr.department_id
FROM employees emp JOIN employees mgr
ON emp.manager_id = mgr.employee_id;
#题目:查询departments表中,不存在于employees表中的部门的department_id和department_name
#方式1:
SELECT d.department_id,d.department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id
= d.department_id
WHERE e.department_id
IS NULL;
#方式2:
SELECT department_id,department_name
FROM departments d
WHERE NOT EXISTS (
SELECT *
FROM employees e
WHERE d.department_id
= e.department_id
);
SELECT COUNT(*)
FROM departments;
子查询练习
#1.查询和Zlotkey相同部门的员工姓名和工资
SELECT last_name,salary
FROM employees
WHERE department_id IN (
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.选择工资大于所有JOB_ID = 'SA_MAN’的员工的工资的员工的last_name, job_id, salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary > ALL(
SELECT salary
FROM employees
WHERE job_id = ‘SA_MAN’
);
#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 IN (
SELECT department_id
FROM departments
WHERE location_id = 1700
);
#6.查询管理者是King的员工姓名和工资
SELECT last_name,salary,manager_id
FROM employees
WHERE manager_id IN (
SELECT employee_id
FROM employees
WHERE last_name = ‘King’
);
#7.查询工资最低的员工信息: last_name, salary
SELECT last_name,salary
FROM employees
WHERE salary = (
SELECT MIN(salary)
FROM employees
);
#8.查询平均工资最低的部门信息
#方式1:
SELECT *
FROM departments
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary ) = (
SELECT MIN(avg_sal)
FROM (
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
) t_dept_avg_sal
)
);
#方式2:
SELECT *
FROM departments
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary ) <= ALL(
SELECT AVG(salary)
FROM employees
GROUP BY department_id
)
);
#方式3: LIMIT
SELECT *
FROM departments
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary ) =(
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal ASC
LIMIT 1
)
);
#方式4:
SELECT d.*
FROM departments d,(
SELECT department_id,AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal ASC
LIMIT 0,1
) t_dept_avg_sal
WHERE d.department_id
= t_dept_avg_sal.department_id
#9.查询平均工资最低的部门信息和该部门的平均工资(相关子查询)
#方式1:
SELECT d.*,(SELECT AVG(salary) FROM employees WHERE department_id = d.department_id
) avg_sal
FROM departments d
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary ) = (
SELECT MIN(avg_sal)
FROM (
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
) t_dept_avg_sal
)
);
#方式2:
SELECT d.*,(SELECT AVG(salary) FROM employees WHERE department_id = d.department_id
) avg_sal
FROM departments d
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary ) <= ALL(
SELECT AVG(salary)
FROM employees
GROUP BY department_id
)
);
#方式3: LIMIT
SELECT d.*,(SELECT AVG(salary) FROM employees WHERE department_id = d.department_id
) avg_sal
FROM departments d
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary ) =(
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal ASC
LIMIT 1
)
);
#方式4:
SELECT d.*,(SELECT AVG(salary) FROM employees WHERE department_id = d.department_id
) avg_sal
FROM departments d,(
SELECT department_id,AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal ASC
LIMIT 0,1
) t_dept_avg_sal
WHERE d.department_id
= t_dept_avg_sal.department_id
#10.查询平均工资最高的 job 信息
#方式1:
SELECT *
FROM jobs
WHERE job_id = (
SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (
SELECT MAX(avg_sal)
FROM (
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY job_id
) t_job_avg_sal
)
);
#方式2:
SELECT *
FROM jobs
WHERE job_id = (
SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) >= ALL(
SELECT AVG(salary)
FROM employees
GROUP BY job_id
)
);
#方式3:
SELECT *
FROM jobs
WHERE job_id = (
SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) =(
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY job_id
ORDER BY avg_sal DESC
LIMIT 0,1
)
);
#方式4:
SELECT j.*
FROM jobs j,(
SELECT job_id,AVG(salary) avg_sal
FROM employees
GROUP BY job_id
ORDER BY avg_sal DESC
LIMIT 0,1
) t_job_avg_sal
WHERE j.job_id = t_job_avg_sal.job_id
#11.查询平均工资高于公司平均工资的部门有哪些?
SELECT department_id
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id
HAVING AVG(salary) > (
SELECT AVG(salary)
FROM employees
);
#12.查询出公司中所有 manager 的详细信息
#方式1:自连接 xxx worked for yyy
SELECT DISTINCT mgr.employee_id,mgr.last_name,mgr.job_id,mgr.department_id
FROM employees emp JOIN employees mgr
ON emp.manager_id = mgr.employee_id;
#方式2:子查询
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE employee_id IN (
SELECT DISTINCT manager_id
FROM employees
);
#方式3:使用EXISTS
SELECT employee_id,last_name,job_id,department_id
FROM employees e1
WHERE EXISTS (
SELECT *
FROM employees e2
WHERE e1.employee_id
= e2.manager_id
);
#13.各个部门中 最高工资中最低的那个部门的 最低工资是多少?
#方式1:
SELECT MIN(salary)
FROM employees
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING MAX(salary) = (
SELECT MIN(max_sal)
FROM (
SELECT MAX(salary) max_sal
FROM employees
GROUP BY department_id
) t_dept_max_sal
)
);
SELECT *
FROM employees
WHERE department_id = 10;
#方式2:
SELECT MIN(salary)
FROM employees
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING MAX(salary) <= ALL (
SELECT MAX(salary)
FROM employees
GROUP BY department_id
)
);
#方式3:
SELECT MIN(salary)
FROM employees
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING MAX(salary) = (
SELECT MAX(salary) max_sal
FROM employees
GROUP BY department_id
ORDER BY max_sal ASC
LIMIT 0,1
)
);
#方式4:
SELECT MIN(salary)
FROM employees e,(
SELECT department_id,MAX(salary) max_sal
FROM employees
GROUP BY department_id
ORDER BY max_sal ASC
LIMIT 0,1
) t_dept_max_sal
WHERE e.department_id = t_dept_max_sal.department_id
#14.查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary
#方式1:
SELECT last_name, department_id, email, salary
FROM employees
WHERE employee_id = ANY (
SELECT DISTINCT manager_id
FROM employees
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MAX(avg_sal)
FROM (
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
) t_dept_avg_sal
)
)
);
#方式2:
SELECT last_name, department_id, email, salary
FROM employees
WHERE employee_id = ANY (
SELECT DISTINCT manager_id
FROM employees
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) >= ALL (
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
)
)
);
#方式3:
SELECT last_name, department_id, email, salary
FROM employees
WHERE employee_id IN (
SELECT DISTINCT manager_id
FROM employees e,(
SELECT department_id,AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal DESC
LIMIT 0,1
) t_dept_avg_sal
WHERE e.department_id
= t_dept_avg_sal.department_id
);
#15. 查询部门的部门号,其中不包括job_id是"ST_CLERK"的部门号
#方式1:
SELECT department_id
FROM departments
WHERE department_id NOT IN (
SELECT DISTINCT department_id
FROM employees
WHERE job_id = ‘ST_CLERK’
);
#方式2:
SELECT department_id
FROM departments d
WHERE NOT EXISTS (
SELECT *
FROM employees e
WHERE d.department_id
= e.department_id
AND e.job_id
= ‘ST_CLERK’
);
#16. 选择所有没有管理者的员工的last_name
SELECT last_name
FROM employees emp
WHERE NOT EXISTS (
SELECT *
FROM employees mgr
WHERE emp.manager_id
= mgr.employee_id
);
#17.查询员工号、姓名、雇用时间、工资,其中员工的管理者为 ‘De Haan’
#方式1:
SELECT employee_id,last_name,hire_date,salary
FROM employees
WHERE manager_id IN (
SELECT employee_id
FROM employees
WHERE last_name = ‘De Haan’
);
#方式2:
SELECT employee_id,last_name,hire_date,salary
FROM employees e1
WHERE EXISTS (
SELECT *
FROM employees e2
WHERE e1.manager_id
= e2.employee_id
AND e2.last_name = ‘De Haan’
);
#18.查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资(相关子查询)
#方式1:使用相关子查询
SELECT last_name,salary,department_id
FROM employees e1
WHERE salary > (
SELECT AVG(salary)
FROM employees e2
WHERE department_id = e1.department_id
);
#方式2:在FROM中声明子查询
SELECT e.last_name,e.salary,e.department_id
FROM employees e,(
SELECT department_id,AVG(salary) avg_sal
FROM employees
GROUP BY department_id) t_dept_avg_sal
WHERE e.department_id = t_dept_avg_sal.department_id
AND e.salary > t_dept_avg_sal.avg_sal
#19.查询每个部门下的部门人数大于 5 的部门名称(相关子查询)
SELECT department_name
FROM departments d
WHERE 5 < (
SELECT COUNT(*)
FROM employees e
WHERE d.department_id = e.department_id
);
#20.查询每个国家下的部门个数大于 2 的国家编号(相关子查询)
SELECT * FROM locations;
SELECT country_id
FROM locations l
WHERE 2 < (
SELECT COUNT(*)
FROM departments d
WHERE l.location_id
= d.location_id
);
子查询的编写技巧(或步骤):① 从里往外写 ② 从外往里写
如何选择?
① 如果子查询相对较简单,建议从外往里写。一旦子查询结构较复杂,则建议从里往外写
② 如果是相关子查询的话,通常都是从外往里写。