欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL学习笔记_上(select查询)

程序员文章站 2022-03-27 09:45:10
...

  上次整理了一些练习发到博客上了,也说要发基础的,整理了一下午才算是把查询那块的勉强整理完,下次再整理其他的,另外还在写设计模式和数据结构的草稿,写的差不多会慢慢发的,这两项算是副线发展,主线还是按JavaSE–JavaWeb–JavaEE的方向来。因为Java后面都需要数据库,所以就先把数据库先抽空写出来,要成体系嘛,我也会坚持的哈。废话不说了,进入主题吧。


关于查询所需要的表,直接将表贴到这里供大家参考。

employees表:
MySQL学习笔记_上(select查询)
departments表:
MySQL学习笔记_上(select查询)
job_grades表:
MySQL学习笔记_上(select查询)
jobs表:
MySQL学习笔记_上(select查询)
locations表:
MySQL学习笔记_上(select查询)


第1章:SQL概述

SQL:Structured Query Language结构化查询语言,它是使用关系模型的数据库应用语言。

1. SQL的语言规范

  • mysql对于SQL语句不区分大小写,SQL语句关键字尽量大写。
  • SQL 可以写在一行或者多行。为了提高可读性,各子句分行写,必要时使用缩进。
  • 关键字不能被缩写也不能分行。
  • 值,除了数值型,字符串型和日期时间类型使用单引号(’ ')
  • 别名,尽量使用双引号(" "),而且不建议省略as。
  • 所有标点符号使用英文状态下的半角输入方式。
  • 必须保证所有(),单引号,双引号是成对结束的。
  • 可以使用(1)#单行注释 (2)–空格单行注释 (3)/* 多行注释 */。

2. 命名规则

  • 数据库、表名不得超过30个字符,变量名限制为29个。
  • 必须只能包含 A–Z, a–z, 0–9, _共63个字符。
  • 不能在对象名的字符间留空格。
  • 必须不能和用户定义的其他对象重名。
  • 必须保证你的字段没有和保留字、数据库系统或常用方法冲突。
  • 保持字段名和类型的一致性,在命名字段并为其指定数据类型的时候一定要保证一致性。假如数据类型在一个表里是整数,那在另一个表里可就别变成字符型了。

说明:一个语句可以分开多行编写,以;或\g结束

3. SQL分类

  • DDL(Data Definition Languages):数据定义语言,这些语句定义了不同的数据段、数据库、表、列、索引等数据库对象。

    • 主要的语句关键字包括CREATEDROPALTER等。
  • DML(Data Manipulation Language):数据操作语言,用于添加、删除、更新和查询数据库记录,并检查数据完整性。

    • 主要的语句关键字包括INSERTDELETEUPDATESELECT等。
    • SELECT是SQL语言的基础,最为重要。
  • DCL(Data Control Language):数据控制语言,用于控制不同数据段直接的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。

    • 主要的语句关键字包括GRANTREVOKECOMMITROLLBACKSAVEPOINT等。

下面主要说的是DML中的select,关于其他的下篇博客会介绍到。


第2章:数据处理之查询

2.1 基本的SELECT语句

2.1.1 SELECT … FROM

SELECT   标识选择哪些列
FROM     标识从哪个表中选择
  • 选择全部列:
SELECT *
FROM   departments;

MySQL学习笔记_上(select查询)

  • 选择特定的列:
SELECT department_id, location_id
FROM   departments;

MySQL学习笔记_上(select查询)

2.1.2 列的别名

  • 重命名一个列

  • 便于计算

  • 紧跟列名,也可以在列名和别名之间加入关键字AS,别名使用双引号,以便在别名中包含空格或特殊的字符并区分大小写。

使用别名

SELECT last_name AS name, commission_pct comm
FROM   employees;

MySQL学习笔记_上(select查询)

SELECT last_name "Name", salary*12 "Annual Salary"
FROM   employees;

MySQL学习笔记_上(select查询)

2.1.3 去除重复行

默认情况下,查询会返回全部行,包括重复行。

SELECT department_id
FROM   employees;

MySQL学习笔记_上(select查询)

在SELECT语句中使用关键字DISTINCT去除重复行。

SELECT DISTINCT department_id
FROM   employees;

MySQL学习笔记_上(select查询)

2.1.4 空值参与运算

  • 所有运算符或列值遇到null值,运算的结果都为null
SELECT employee_id,salary,commission_pct,
12 * salary * (1 + commission_pct) "annual_sal"
FROM employees;

MySQL学习笔记_上(select查询)

2.1.5 显示表结构

使用DESCRIBE 或 DESC 命令,表示表结构。

DESCRIBE employees;

MySQL学习笔记_上(select查询)

2.2 过滤数据

2.2.1 SELECT … FROM … WHERE

  • 使用WHERE 子句,将不满足条件的行过滤掉
  • WHERE子句紧随 FROM子句
#选择department_id=90的员工信息
SELECT employee_id, last_name, job_id, department_id
FROM   employees
WHERE  department_id = 90 ;

MySQL学习笔记_上(select查询)

2.2.2 比较运算符

① 基本操作符
操作符 含义
= 等于(不是==)
> 大于
>= 大于、等于
< 小于
<= 小于、等于
<> 或 != 不等于

说明:赋值符号使用 :=

#选择工资小于等于3000的员工姓名和工资
SELECT last_name, salary
FROM   employees
WHERE  salary <= 3000;

MySQL学习笔记_上(select查询)

② 其它比较运算符
操作符 含义
BETWEEN … AND 在两个值之间(包含边界)
IN(set) 等于值列表中的一个
LIKE 模糊查询
IS NULL 空值

1)BETWEEN … AND

使用 BETWEEN 运算来显示在一个区间内的值

SELECT last_name, salary
FROM   employees
WHERE  salary BETWEEN 2500 AND 3500;

MySQL学习笔记_上(select查询)

2)IN

使用 IN运算显示列表中的值。

#选择管理Id为100,101,201的员工信息
SELECT employee_id, last_name, salary, manager_id
FROM   employees
WHERE  manager_id IN (100, 101, 201);

MySQL学习笔记_上(select查询)

3)LIKE

  • 使用 LIKE 运算选择类似的值

  • 选择条件可以包含字符或数字:

    • % 代表零个或多个字符(任意个字符)
    • _ 代表一个字符
#选择first_name第一个字母为S的first_name
SELECT	first_name
FROM 	employees
WHERE	first_name LIKE 'S%';

MySQL学习笔记_上(select查询)

  • ‘%’和‘_’可以同时使用。
#第二个字母为o的last_name
SELECT last_name
FROM   employees
WHERE  last_name LIKE '_o%';

MySQL学习笔记_上(select查询)

ESCAPE

  • 回避特殊符号的:使用转义符。例如:将[%]转为[%]、[]转为[],然后再加上[ESCAPE‘$’]即可。
SELECT job_id
FROM   jobs
WHERE  job_id LIKE ‘IT\_%;

如果使用\表示转义,要省略ESCAPE。如果不是\,则要加上ESCAPE。

SELECT job_id
FROM   jobs
WHERE  job_id LIKE ‘IT$_%escape ‘$‘;

4)NULL

使用 IS (NOT) NULL 判断空值。

#选择manager_id为NULL的员工的last_name,manager_id
SELECT last_name, manager_id
FROM   employees
WHERE  manager_id IS NULL;

2.2.3 逻辑运算符

操作符 含义
&& (或AND) 逻辑且
||(或OR) 逻辑或
NOT 逻辑否
XOR 逻辑异或

1)&& (或AND)

AND要求并的关系为真。

#查询金额大于等于10000并且job_id中有MAN字段的员工信息
SELECT employee_id, last_name, job_id, salary
FROM   employees
WHERE  salary >=10000
AND    job_id LIKE '%MAN%';

MySQL学习笔记_上(select查询)

2)||(或OR)

OR要求或关系为真。

##查询金额大于等于10000或者job_id中有MAN字段的员工信息
SELECT employee_id, last_name, job_id, salary
FROM   employees
WHERE  salary >= 10000
OR     job_id LIKE '%MAN%';

MySQL学习笔记_上(select查询)

3)NOT

#查询不在IT_PROG,'ST_CLERK,SA_REP'部门的员工的last_name和job_id
SELECT last_name, job_id
FROM   employees
WHERE  job_id NOT IN ('IT_PROG', 'ST_CLERK', 'SA_REP');

MySQL学习笔记_上(select查询)

4)XOR

select last_name,department_id,salary 
from employees
where department_id in (10,20) XOR salary > 8000;

MySQL学习笔记_上(select查询)

2.2.4 算术运算符

运算符 说明
+ 加法
- 减法
* 乘法
/ (或div) 除法
%(或mod) 取模
#查询部门id%2等于0的员工信息
SELECT employee_id,salary,department_id
FROM employees
WHERE department_id MOD 2 = 0;

MySQL学习笔记_上(select查询)

2.3 排序数据和分页

2.3.1 排序数据

  • 使用 ORDER BY 子句排序

    • ASC(ascend): 升序
    • DESC(descend):降序
  • ORDER BY 子句在SELECT语句的结尾。

#查询按金额升序排序的员工信息
SELECT employee_id, last_name, salary
FROM   employees
ORDER BY salary;

MySQL学习笔记_上(select查询)

#查询按部门id升序排列,相同则按金额降序排列的员工信息。
SELECT last_name, department_id, salary
FROM   employees
ORDER BY department_id, salary DESC;

MySQL学习笔记_上(select查询)

  • 可以使用不在SELECT列表中的列排序。

2.3.2 分页

  • MySQL中使用limit实现分页
    所谓分页显示,就是将数据库中的结果集,一段一段显示出来需要的条件。
--前10条记录:
SELECT * FROM table LIMIT 0,10;

--第11至20条记录:
SELECT * FROM table LIMIT 10,10;

--第21至30条记录: 
SELECT * FROM table LIMIT 20,10;
  • 公式**:(当前页数-1)每页条数,每页条数*
SELECT * FROM table 
LIMIT(PageNo - 1)*PageSize,PageSize;
  • 注意:limit子句必须放在整个查询语句的最后!

2.4 多表查询

2.4.1 MySQL连接

使用连接在多个表中查询数据。

SELECT	table1.column, table2.column
FROM	table1, table2
WHERE	table1.column1 = table2.column2;
  • 在 WHERE子句中写入连接条件。

  • 在表中有相同列时,在列名之前加上表名前缀。

2.4.2 等值连接

SELECT employees.employee_id, employees.last_name, 
       employees.department_id, departments.department_id,
       departments.location_id
FROM   employees, departments
WHERE  employees.department_id = departments.department_id;

多个连接条件用 AND 操作符

区分重复的列名

  • 使用表名前缀在多个表中区分相同的列

  • 在不同表中具有相同列名的列可以用表的别名加以区分。

表的别名

  • 使用别名可以简化查询。

  • 使用表名前缀可以提高执行效率。

SELECT e.employee_id, e.last_name, e.department_id,
       d.department_id, d.location_id
FROM   employees e , departments d
WHERE  e.department_id = d.department_id;

MySQL学习笔记_上(select查询)

连接多个表
连接 n个表,至少需要n-1个连接条件。
例如:连接三个表,至少需要两个连接条件。
查询出公司员工的 last_name,department_name, city

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

MySQL学习笔记_上(select查询)

2.4.3 自连接 vs 非自连接

  • 当两张表是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询

题目:查询employees表,返回“Xxx works for Xxx”

SELECT CONCAT(worker.last_name ,' works for ' 
       , manager.last_name)
FROM   employees worker, employees manager
WHERE  worker.manager_id = manager.employee_id ;

MySQL学习笔记_上(select查询)

2.4.4 分类3:内连接 vs 外连接

  • 内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行

  • 外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。

① SQL99:使用ON子句创建连接
  • 自然连接中是以具有相同名字的列为连接条件的。

  • 可以使用 ON 子句指定额外的连接条件

  • 这个连接条件是与其它条件分开的。

  • ON 子句使语句具有更高的易读性

SELECT e.employee_id, e.last_name, e.department_id, 
       d.department_id, d.location_id
FROM   employees e JOIN departments d
ON     (e.department_id = d.department_id);

MySQL学习笔记_上(select查询)

SELECT employee_id, city, department_name
FROM   employees e 
JOIN   departments d
ON     d.department_id = e.department_id 
JOIN   locations l
ON     d.location_id = l.location_id;

MySQL学习笔记_上(select查询)

② 左外连接
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) ;

MySQL学习笔记_上(select查询)

③ 右外连接
SELECT e.last_name, e.department_id, d.department_name
FROM   employees e
RIGHT OUTER JOIN departments d
ON    (e.department_id = d.department_id) ;

MySQL学习笔记_上(select查询)

总结:SQL JOINS

MySQL学习笔记_上(select查询)

补充:

UNION操作符

MySQL学习笔记_上(select查询)

UNION 操作符返回两个查询的结果集的并集。

UNION ALL操作符

MySQL学习笔记_上(select查询)

UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。

2.5 单行函数

2.5.1 介绍

MySQL学习笔记_上(select查询)

两种SQL函数

MySQL学习笔记_上(select查询)

单行函数

  • 操作数据对象

  • 接受参数返回一个结果

  • 只对一行进行变换

  • 每行返回一个结果

  • 可以嵌套

  • 参数可以是一列或一个值

2.5.2 字符串函数

函数 用法
CONCAT(S1,S2,…,Sn) 连接S1,S2,…,Sn为一个字符串
CONCAT_WS(s, S1,S2,…,Sn) 同CONCAT(s1,s2,…)函数,但是每个字符串之间要加上s
CHAR_LENGTH(s) 返回字符串s的字符数
LENGTH(s) 返回字符串s的字节数,和字符集有关
INSERT(str, index , len, instr) 将字符串str从第index位置开始,len个字符长的子串替换为字符串instr
UPPER(s) 或 UCASE(s) 将字符串s的所有字母转成大写字母
LOWER(s) 或LCASE(s) 将字符串s的所有字母转成小写字母
LEFT(s,n) 返回字符串s最左边的n个字符
RIGHT(s,n) 返回字符串s最右边的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(【BOTH 】s1 FROM s) 去掉字符串s开始与结尾的s1
TRIM(LEADING s1 FROM s) 去掉字符串s开始处的s1
TRIM(TRAILING s1 FROM s) 去掉字符串s结尾处的s1
REPEAT(str, n) 返回str重复n次的结果
REPLACE(str, a, b) 用字符串b替换字符串str中所有出现的字符串a
STRCMP(s1,s2) 比较字符串s1,s2
SUBSTRING(s,index,len) 返回从字符串s的index位置其len个字符
  • 举例1:大小写控制函数
函数 结果
LOWER(‘SQL Course’) sql course
UPPER(‘SQL Course’) SQL COURSE

这类函数改变字符的大小写。

  • 举例2:字符控制函数
函数 结果
CONCAT(‘Hello’,‘World’) HelloWorld
SUBSTR(‘HelloWorld’,1,5) Hello
LENGTH(‘HelloWorld’) 10
INSTR(‘HelloWorld’,‘W’) 6
LPAD(salary,10,’*’) *****24000
RPAD(salary,10, ‘*’) 24000*****
TRIM(‘H’ FROM ‘HelloWorld’) elloWorld
REPLACE(‘abcd’,‘b’,‘m’) amcd

2.5.3 数值函数

函数 用法
ABS(x) 返回x的绝对值
CEIL(x) 返回大于x的最小整数值
FLOOR(x) 返回小于x的最大整数值
MOD(x,y) 返回x/y的模
RAND() 返回0~1的随机值
ROUND(x,y) 返回参数x的四舍五入的有y位的小数的值
TRUNCATE(x,y) 返回数字x截断为y位小数的结果
SQRT(x) 返回x的平方根
POW(x,y) 返回x的y次方
  • 举例1:ROUND:四舍五入
ROUND(45.926, 2)     -->  45.93
  • 举例2:TRUNCATE:截断
TRUNCATE(45.926)      --> 45
  • 举例3:MOD:求余
MOD(1600, 300)	 --> 100

2.5.4 日期函数

函数 用法
CURDATE() 或 CURRENT_DATE() 返回当前日期
CURTIME() 或 CURRENT_TIME() 返回当前时间
NOW() / SYSDATE() / CURRENT_TIMESTAMP() / LOCALTIME() / LOCALTIMESTAMP() 返回当前系统日期时间
YEAR(date) / MONTH(date) / DAY(date) / HOUR(time) / MINUTE(time) / SECOND(time) 返回具体的时间值
WEEK(date) / WEEKOFYEAR(date) 返回一年中的第几周
DAYOFWEEK() 返回周几,注意:周日是1,周一是2,。。。周六是7
WEEKDAY(date) 返回周几,注意,周1是0,周2是1,。。。周日是6
DAYNAME(date) 返回星期:MONDAY,TUESDAY…SUNDAY
MONTHNAME(date) 返回月份:January,。。。。。
DATEDIFF(date1,date2) / TIMEDIFF(time1, time2) 返回date1 - date2的日期间隔 / 返回time1 - time2的时间间隔
DATE_ADD(datetime, INTERVAL expr type) 返回与给定日期时间相差INTERVAL时间段的日期时间
DATE_FORMAT(datetime ,fmt) 按照字符串fmt格式化日期datetime值
STR_TO_DATE(str, fmt) 按照字符串fmt对str进行解析,解析为一个日期

其中:

(1)DATE_ADD(datetime,INTERVAL expr type)

表达式类型:

参数类型 参数类型
YEAR YEAR_MONTH
MONTH DAY_HOUR
DAY DAY_MINUTE
HOUR DAY_SECOND
MINUTE HOUR_MINUTE
SECOND HOUR_SECOND
MINUTE_SECOND

举例:

SELECT DATE_ADD(NOW(), INTERVAL 1 YEAR);
SELECT DATE_ADD(NOW(), INTERVAL -1 YEAR);   #可以是负数
SELECT DATE_ADD(NOW(), INTERVAL '1_1' YEAR_MONTH);   #需要单引号

(2)DATE_FORMAT(datetime,fmt) 和 STR_TO_DATE(str, fmt)

格式符 说明 格式符 说明
%Y 4位数字表示年份 %y 表示两位数字表示年份
%M 月名表示月份(January,…) %m 两位数字表示月份(01,02,03。。。)
%b 缩写的月名(Jan.,Feb.,…) %c 数字表示月份(1,2,3,…)
%D 英文后缀表示月中的天数(1st,2nd,3rd,…) %d 两位数字表示月中的天数(01,02…)
%e 数字形式表示月中的天数(1,2,3,4,5…)
%H 两位数字表示小数,24小时制(01,02…) %h和%I 两位数字表示小时,12小时制(01,02…)
%k 数字形式的小时,24小时制(1,2,3) %l 数字形式表示小时,12小时制(1,2,3,4…)
%i 两位数字表示分钟(00,01,02) %S和%s 两位数字表示秒(00,01,02…)
%W 一周中的星期名称(Sunday…) %a 一周中的星期缩写(Sun.,Mon.,Tues.,…)
%w 以数字表示周中的天数(0=Sunday,1=Monday…)
%j 以3位数字表示年中的天数(001,002…) %U 以数字表示年中的第几周,(1,2,3。。)其中Sunday为周中第一天
%u 以数字表示年中的第几周,(1,2,3。。)其中Monday为周中第一天
%T 24小时制 %r 12小时制
%p AM或PM %% 表示%

2.5.5 流程函数

函数 用法
IF(value,t ,f) 如果value是真,返回t,否则返回f
IFNULL(value1, value2) 如果value1不为空,返回value1,否则返回value2
CASE WHEN 条件1 THEN result1 WHEN 条件2 THEN result2 … [ELSE resultn] END 相当于Java的if…else if…else…
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 … [ELSE 值n] END 相当于Java的switch…case…
SELECT employee_id,salary, CASE WHEN salary>=15000 THEN '高薪' 
				  WHEN salary>=10000 THEN '潜力股'  
				  WHEN salary>=8000 THEN '屌丝' 
				  ELSE '草根' END  "描述"
FROM employees; 
SELECT oid,`status`, CASE `status` WHEN 1 THEN '未付款' 
								   WHEN 2 THEN '已付款' 
								   WHEN 3 THEN '已发货'  
								   WHEN 4 THEN '确认收货'  
								   ELSE '无效订单' END 
FROM t_order;
  • 举例1:
SELECT employee_id,12 * salary * (1 + IFNULL(commission_pct,0))
FROM employees;
  • 举例2:
SELECT last_name, job_id, salary,
       CASE job_id WHEN 'IT_PROG'  THEN  1.10*salary
                   WHEN 'ST_CLERK' THEN  1.15*salary
                   WHEN 'SA_REP'   THEN  1.20*salary
       ELSE      salary END     "REVISED_SALARY"
FROM   employees;

MySQL学习笔记_上(select查询)

2.5.6 其他函数

函数 用法
database() 返回当前数据库名
version() 返回当前数据库版本
user() 返回当前登录用户名
password(str) 返回字符串str的加密版本,41位长的字符串
md5(str) 返回字符串str的md5值,也是一种加密方式

2.6 分组函数

2.6.1 组函数介绍

  • 什么是分组函数

分组函数作用于一组数据,并对一组数据返回一个值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mkacU4ZN-1571548409205)(SQL开发.assets/1554980924940.png)]

  • 组函数类型
    • AVG()
    • SUM()
    • MAX()
    • MIN()
    • COUNT()

2.6.2 AVG和SUM函数

可以对数值型数据使用AVG 和 SUM 函数。

#查询job_id中有REP字符串的员工工资的平均值、最大值、最小值、总数
SELECT AVG(salary), MAX(salary),MIN(salary), SUM(salary)
FROM   employees
WHERE  job_id LIKE '%REP%';

MySQL学习笔记_上(select查询)

2.6.3 MIN和MAX函数

可以对任意数据类型的数据使用 MIN 和 MAX 函数。

SELECT MIN(salary), MAX(salary)
FROM employees;

MySQL学习笔记_上(select查询)

2.6.4 COUNT函数

COUNT(*)返回表中记录总数,适用于任意数据类型

SELECT COUNT(*)
FROM	  employees
WHERE  department_id = 50;

MySQL学习笔记_上(select查询)
•COUNT(expr) 返回expr不为空的记录总数。

SELECT COUNT(salary)
FROM   employees
WHERE  department_id = 50;

MySQL学习笔记_上(select查询)

  • 问题:用count(*),count(1)谁好呢?

    其实,对于myisam引擎的表是没有区别的。这种引擎内部有一计数器在维护着行数。

    Innodb引擎的表用count(*)直接读行数,效率很低,因为innodb真的要去数一遍。

2.6.5 GROUP BY

可以使用GROUP BY子句将表中的数据分成若干组

SELECT column, group_function(column)
FROM table
[WHERE	condition]
[GROUP BY	group_by_expression]
[ORDER BY	column];

明确:WHERE一定放在FROM后面

在SELECT列表中所有未包含在组函数中的列都应该包含在 GROUP BY子句中

SELECT   department_id, AVG(salary)
FROM     employees
GROUP BY department_id ;

MySQL学习笔记_上(select查询)

包含在 GROUP BY 子句中的列不必包含在SELECT 列表中

SELECT   AVG(salary)
FROM     employees
GROUP BY department_id ;

MySQL学习笔记_上(select查询)

使用多个列分组

SELECT   department_id dept_id, job_id, SUM(salary)
FROM     employees
GROUP BY department_id, job_id ;

MySQL学习笔记_上(select查询)

2.6.6 HAVING

  • 非法使用组函数
    • 不能在 WHERE 子句中使用组函数。
    • 可以在 HAVING 子句中使用组函数。
SELECT   department_id, AVG(salary)
FROM     employees
WHERE    AVG(salary) > 8000
GROUP BY department_id;

MySQL学习笔记_上(select查询)

过滤分组:HAVING子句

  1. 行已经被分组。
  2. 使用了组函数。
  3. 满足HAVING 子句中条件的分组将被显示。
SELECT   department_id, MAX(salary)
FROM     employees
GROUP BY department_id
HAVING   MAX(salary)>10000 ;

MySQL学习笔记_上(select查询)

第3章:子查询

3.1 基本介绍

  • 子查询 (内查询) 在主查询之前一次执行完成。

  • 子查询的结果被主查询(外查询)使用 。

  • 子查询的类型:

    • 单行子查询
      MySQL学习笔记_上(select查询)

    • 多行子查询
      MySQL学习笔记_上(select查询)

  • 注意事项

    • 子查询要包含在括号内.
    • 将子查询放在比较条件的右侧.
    • 单行操作符对应单行子查询,多行操作符对应多行子查询.

3.2 单行子查询

3.2.1 单行比较操作符

操作符 含义
= equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
<> not equal to
SELECT last_name
FROM   employees
WHERE  salary >
               (SELECT salary
                FROM   employees
                WHERE  last_name = 'Abel');

MySQL学习笔记_上(select查询)

题目:返回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);

MySQL学习笔记_上(select查询)

题目:返回公司工资最少的员工的last_name,job_id和salary

SELECT last_name, job_id, salary
FROM   employees
WHERE  salary = 
                (SELECT MIN(salary)
                 FROM   employees);

MySQL学习笔记_上(select查询)

3.2.2 子查询中的 HAVING 子句

  • 首先执行子查询。
  • 向主查询中的HAVING 子句返回结果。

题目:查询最低工资大于50号部门最低工资的部门id和其最低工资

SELECT   department_id, MIN(salary)
FROM     employees
GROUP BY department_id
HAVING   MIN(salary) >
                       (SELECT MIN(salary)
                        FROM   employees
                        WHERE  department_id = 50);

MySQL学习笔记_上(select查询)

3.2.3 子查询中的空值问题

SELECT last_name, job_id
FROM   employees
WHERE  job_id =
                (SELECT job_id
                 FROM   employees
                 WHERE  last_name = 'Haas');

=MySQL学习笔记_上(select查询)

子查询不返回任何行

3.2.4 非法使用子查询

SELECT employee_id, last_name
FROM   employees
WHERE  salary =
                (SELECT   MIN(salary)
                 FROM     employees
                 GROUP BY department_id);

MySQL学习笔记_上(select查询)

多行子查询使用单行比较符

3.2 多行子查询

  • 返回多行。

  • 使用多行比较操作符。

操作符 含义
IN 等于列表中的任意一个
ANY 和子查询返回的某一个值比较
ALL 和子查询返回的所有值比较

体会any和all的区别

3.2.1 使用ANY或ALL操作符

题目:返回其它job_id中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、姓名、job_id 以及salary

SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ANY (SELECT salary
		    FROM employees
		    WHERE job_id = 'IT_PROG')
AND job_id <> 'IT_PROG';

MySQL学习笔记_上(select查询)

题目:返回其它job_id中比job_id为‘IT_PROG’部门所有工资都低的员工的员工号、姓名、job_id以及salary

SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ALL (SELECT salary
		    FROM employees
		    WHERE job_id = 'IT_PROG')
AND job_id <> 'IT_PROG';

MySQL学习笔记_上(select查询)

3.3 相关子查询

相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。
MySQL学习笔记_上(select查询)

题目:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
方式一:相关子查询

SELECT last_name,salary,department_id
FROM employees outers
WHERE salary > (SELECT AVG(salary)
		FROM employees
		WHERE department_id=outers.`department_id`)

方式二:在from中使用子查询

SELECT last_name,salary,e1.department_id
FROM employees e1,(SELECT department_id,AVG(salary) dept_avg_sal FROM employees GROUP BY department_id) e2
WHERE e1.`department_id` = e2.department_id
AND e2.dept_avg_sal < e1.`salary`;

MySQL学习笔记_上(select查询)

题目:查询员工的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`
	);

MySQL学习笔记_上(select查询)

3.4 EXISTS操作符

  • EXISTS 操作符检查在子查询中是否存在满足条件的行

  • 如果在子查询中存在满足条件的行:

    • 不在子查询中继续查找
    • 条件返回 TRUE
  • 如果在子查询中不存在满足条件的行:

    • 条件返回 FALSE
    • 继续在子查询中查找

题目:查询公司管理者的employee_id,last_name,job_id,department_id信息

方式一:

SELECT employee_id, last_name, job_id, department_id
FROM   employees e1
WHERE  EXISTS ( SELECT 'X'
                 FROM   employees e2
                 WHERE  e2.manager_id = 
                        e1.employee_id);

方式二:

SELECT DISTINCT e1.employee_id, e1.last_name, e1.job_id, e1.department_id
FROM   employees e1 JOIN employees e2
WHERE e1.employee_id = e2.manager_id;

方式三:

SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE employee_id IN (
		     SELECT DISTINCT manager_id
		     FROM employees
		     
		     );

MySQL学习笔记_上(select查询)

题目:查询departments表中,不存在于employees表中的部门的department_id和department_name

SELECT department_id, department_name
FROM departments d
WHERE NOT EXISTS (SELECT 'X'
                  FROM   employees
                  WHERE  department_id = d.department_id);

MySQL学习笔记_上(select查询)

3.5 相关更新

UPDATE table1 alias1
SET    column = (SELECT expression
                 FROM   table2 alias2
                 WHERE  alias1.column = alias2.column);

使用相关子查询依据一个表中的数据更新另一个表的数据。

练习:

1ALTER TABLE employees
ADD(department_name VARCHAR2(14));
2UPDATE employees e
SET    department_name =  (SELECT department_name 
	                       FROM   departments d
	                       WHERE  e.department_id = d.department_id);

3.6 相关删除

 DELETE FROM table1 alias1
 WHERE column operator (SELECT expression
                        FROM   table2 alias2
                        WHERE  alias1.column = alias2.column);

使用相关子查询依据一个表中的数据删除另一个表的数据

题目:删除表employees中,其与emp_history表皆有的数据

DELETE FROM employees e
WHERE employee_id in  
           (SELECT employee_id
            FROM   emp_history 
            WHERE  employee_id = e.employee_id);

今天就先到这,查询这块的内容也差不多说完了。其它的下次再说。欢迎大家一起学习交流。