mysql数据查询语言DQL

时间:2023-03-09 23:01:14
mysql数据查询语言DQL

DB(database)数据库:存储数据的'仓库',保存了一系列有组织的数据

DBMS(Database Management System)数据库管理系统:用于创建或管理DB

SQL(Structure Query Language):结构化查询语言,专门用来与数据库通信的语言

数据库的特点

1.将数据放入表中,表再放到库中

2.一个数据库中可以有多个表,每个表都有唯一的名字

3.表具有一些特性,这些特性定义了数据在表中如何存储,类似java中"类"的设计

4.表由列组成,称为字段。类似java中的属性

5.表中的数据按行存储,每一行类似于java中的"对象"

Mysql服务端的基本操作

查看Mysql版本号

cmd下:mysql --version (dos命令) / mysql -V

mysql语句: select version();

Mysql服务的启动与停止

方式一:计算机管理 - 服务与应用程序 - 服务 - 找到Mysql右击启动/停止

方式二:命令行cmd,管理员身份进入

停止: net stop mysql(服务名)

开启: net start mysql(我的服务名是mysql)

Mysql服务端的登录与退出

登录前必须保证服务是启动的

[]连接本机和端口为3366时可以省略

登录:mysql [-h 主机名] [-P 端口号] -u 用户名 -p(密码可以回车输入,也可以不加空格写在这后面)

退出:exit

Mysql的常用命令

每条命令的结尾加上分号

查看数据库:shwo databases;

进入数据库:use test;

查看当前库里的表:show tables;

查看其他库的表:show tables from 数据库名;

创建表:create table 表名(字段名 字段类型,字段名 字段类型));

查看表的结构:desc 表名

查看表里的数据:select * from 表名

shwo databases;
use sys;
show tables from mysql;#此时在test库里查看mysql库里的表
select database(); #查看当前的所在的库 sys
create table stuinfo(
-> id int,
-> name varchar(20));
desc stuinfo;
insert into stuinfo(id,name) values(1,'john');#插入数据
select * from stuinfo;
update stuinfo set name='' where id=1;#修改名字
delete from stuinfo where id=1;

插入已有的sql脚本

用户右键 - 执行SQL脚本

MySQL的语法规范

1.不区分大小写,但建议关键字大写,其他小写。

2.每条命令用分号结尾

3.每条命令根据需要,可以进行缩进或换行

4.注释 单行注释:# 或 --空格 多行注释/注释文字/

DQL数据查询语言(Data Query Language)

做笔记用的练习数据库的信息

mysql数据查询语言DQL

commission_pct可能为NULL

引号:

1.单引号包裹字符

2.当别名识别不出来的时,加上双引号

基础查询

语法:select 查询列表 from 表名;

查询列表:表中的字段、常量值、表达式、函数 -> 字段名默认值为查询列表

查询的结果是一个虚拟的表格

补充说明

1.``着重号,当字段被识别成关键字时可以使用

2.起别名的好处①便于理解②区分重名情况。

3.当别名识别不出来的时,加上双引号(特殊情况)

4.mysql中的+号只作运算符

如果其中一个为字符型,字符型->数值型,成功做加运算,失败则将字符串转换为0。

如果一方为null,则结果为null

# 基础查询
USE myemployees;
# 1.查询表中的单个字段
SELECT last_name FROM employees; # 2.查询表中的多个字段
SELECT last_name,salary,email FROM employees; # 3.查询表中的所有字段
# 方式一:使用*输出的顺序和原始表的顺序一样
SELECT * FROM employees;
# 方式二:可以自定义顺序
SELECT
`first_name`,
`last_name`,
`email`,
`phone_number`,
`manager_id`,
`salary`,
`job_id`,
`department_id`,
`hiredate`,
`commission_pct`
FROM
employees; # 字段名默认值为查询列表,如100+5、VERSION()
# 4.查询常量值:单引号
SELECT 'join'; # 5.查询表达式:employees有多少行,就输出多少行
SELECT 100+5 from employees; # 6.查询函数:值为返回值.执行函数查询返回值
SELECT VERSION(); # 字段名起别名
# 方式1 as
SELECT 100%98 AS 结果;
# 方式2: 使用空格
SELECT 100%98 结果;
# 特殊情况:当别名识别不出来的时,加上双引号
SELECT 100%98 AS "out put";

案例

1.去重:关键字DISTINCT

2.拼接字符串:函数concat(参数列表)

3.判断是否为null,设置默认值: 函数ifnull(表达式,为null之后的返回值)

4.判断是否为nul:isnull(一个参数),返回函数结果1真0假

# 查询员工表中涉及到的所有部门编号
SELECT DISTINCT department_id FROM employees; # 查询员工名和姓连接成一个字段,并显示为姓名
SELECT CONCAT(last_name,first_name) AS 姓名 FROM employees; SELECT CONCAT(last_name,",",first_name,",",IFNULL(commission_pct,0)) AS out_put FROM employees;

条件查询

语法:select 查询列表 from 表名 where 筛选条件;

说明:先定位到表,在筛选条件,最后执行查询语句。

分类

1.按条件表达式筛选(> < = !=/<> >= <=)

2.按逻辑表达式筛选(&&/and ||/or !/not)

3.模糊查询(like, between and, in, is null)

like

说明

1.一般和通配符搭配使用,

2.通配符:

%代表零个或多个字符

_任意单个字符

3.ESCAPE关键字 自定义转移符

4.可以判断数值型和字符型,都写在引号里

# 模糊查询
# 1.查询员工名中包含字符a(模糊条件)的员工信息
SELECT * FROM employees WHERE last_name LIKE '%a%'; # 2.查询员工名中第三个字符为e,第五个字符为a的员工名和工资
SELECT last_name,salary
FROM employees
WHERE last_name LIKE '__e_a%'; # 3.查询员工名中第二个字符为_的员工名
# 方法一:\转义字符
# 方法二:ESCAPE关键字 自定义转移符
SELECT last_name
FROM employees
# where last_name like '_\_%'、
WHERE last_name LIKE '_$_%' ESCAPE 'S';

between and

betwenn相当于>= and相当于<=

注意事项

1.包含临界值

2.顺序不能乱

# 查询员工编号在100到120之间的员工信息
SELECT * FROM employees WHERE employee_id BETWEEN 100 AND 120;

in()

in相当于等于

含义:判断某字段的值是否属于in列表中的某一项

特点:

1.in列表的值类型必须一致或兼容

2.不支持通配符

# 查询员工的工种编号 IT_PROG,AD_VP,AD_PRES中的一个员工名和工种编号
SELECT last_name,job_id
FROM employees
# where job_id = 'IT_PROG' or job_id ='AD_VP' or job_id ='AD_PRES';
WHERE job_id IN('IT_PROG' , 'AD_VP' , 'AD_PRES');

is null

类型 普通类型的数值 null型
赋值 = != ×
关键字 is ×
安全等于 <=>
# 模糊查询
# 查询没有奖金的员工名和奖金率
SELECT last_name ,commission_pct
FROM employees
# where commission_pct is NOT null ;
WHERE commission_pct IS NULL ;
# WHERE commission_pct<=> NULL;

习题

以下两种结果是一样的吗?

如果判断的字段有null值则不一样,commission_pct可以为null,所以结果不一样

SELECT * FROM employees;
SELECT * FROM employees WHERE commission_pct LIKE '%%' AND last_name LIKE '%%'; # 补充:以下情况是一样的
SELECT * FROM employees WHERE commission_pct LIKE '%%' OR last_name LIKE '%%';

排序查询

语法:select 查询列表 from 表 [where 筛选条件] order by 排序列表 [asc|desc]

说明:

1.asc代表升序,desc代表降序,默认是升序

2.order by 后可以跟表达式、别名、函数

3.支持多个字段排序,先按第一个排,第一个相同按第二个排

4.order by 子句一般放在查询语句最后。limit子句除外

5.执行顺序先from表再where再select查询最后order by

# 查询员工信息,要求工资从高到低排序
SELECT * FROM employees ORDER BY salary DESC;
# 查询员工信息,先按工资排序再按员工编号排序[按多个字段排序]
SELECT * FROM employees ORDER BY salary ASC,employee_id DESC;

常见函数

概念:将一组逻辑语句封装在方法体中,对外暴露方法名

调用: selsect 函数名() [from 表] 函数中的参数使用到了表中属性时需要添加

分类

  • 单行函数 对于每一行数据进行计算后得到一行输出结果
    • 字符函数
    • 数学函数
    • 日期函数
    • 其他函数
    • 流程控制函数
  • 分组函数 做统计使用,有称为统计函数、聚合函数,一组数据输出一个结果

单行函数

字符函数

length(str):获取参数值的字节个数,如果是数字会自动添加''

concat(参数列表):拼接字符串

upper(str)/lower(str):将字符转换成大小写

substr/substring(参数列表):截取字符,mysql中索引从1开始

instr(str,substr):返回子串在str中第一次出现的起始索引,没有就返回0

trim('去除的字符' from '字符串'):去除前后的字符,默认去空格

lpad/rpad(str,总长度,填充字符): 根据总长度进行填充与截取。当str不足总长度用填充符号左/右填充,超了则截取

replace(str,from_str,to_str):把str中的所有from_str替换成to_str

# concat(参数列表)
SELECT CONCAT(last_name,'_',first_name) FROM employees; # substr/substring(str,pos) 从pos位置(包含)开始截取str(光标左开始) 输出 冉ranan
SELECT SUBSTR('冉冉ranan',2) 结果;
# substr/substring(str,pos,length) 从1开始截取长度2 输出 ra
SELECT SUBSTR('ranan',1,2) 结果; # instr(str,substr) 输出 2
SELECT INSTR('ranran','an'); # trim 规定去掉前后的a 输出 xxxaaxxx
SELECT TRIM('a' FROM 'aaaxxxxaaxxxaaaa'); # lpad:根据总个数进行填充与截取 输出 ***xxxr
SELECT LPAD('xxxr',7,'*'); # repalce 替换 输出 ccccxxxxrancc
SELECT REPLACE("ababxxxxranab",'ab','cc');

日期函数

now() 返回当前系统日期 + 时间

curdate() 返回当前系统日期

curtime() 返回当前的时间

year/month/monthname/day/hour(data/1998-1-1) 获取指定data的年份、月份...

str_to_date():将日期格式的字符串转换成指定格式的日期

date_format():将日期转换成字符串

相差天数 datediff(日期1,日期2),日期1-日期2

# 2019-09-13
SELECT STR_TO_DATE('9-13-1999','%m-%d-%y');
# %Y四位数年份 %y2位数年份 %m月份01 %c月份1 %d日 %H24小时 %h12小时 %i分钟 %s秒 # 2018年06月06日
SELECT date_format('2018/6/6','%Y年%m月%d日')

数学函数

round() 四舍五入

ceil(x) 向上取整,返回>=该参数的最小整数

floor(x) 向下取整,返回<=该参数的最大整数

truncate() 截断,小数点后保留几位

mod(a,b) 取余 a%b(a-a/b*b),被除数符号与结果符号相同

rand 获取随机数,返回0-1之间的小数

# round()负数先绝对值四舍五入再加负号
SELECT ROUND(1.33); # 默认往整数四舍五入,结果1
SELECT ROUND(1.33,2); # 小数点后保留几位 1.33 # ceil(x) 向上取整
SELECT CEIL(-1.001);; # 结果-1
SELECT CEIL(1.001); # 结果2 # truncate 截断
SELECT TRUNCATE(1.65,1) # 输出1.6

其他函数

version() 版本号

database() 当前库

user() 当前用户

password(str) 给str加密

md5(str) 返回该str的md5形式

流程控制函数

格式:if(表达式,成立执行,不成立执行)

case函数的使用一:swich case -> 适用于等值判断

格式:case 要判断的字段或表达式

when 常量1 then 要显示的值1或语句1 (;是语句时添加)

when 常量2 then 要显示的值2或语句2 (;是语句时添加)

else 默认情况

end

注意:

case做表达式时,then后是显示的值

case做语句时,then后是语句

case函数的使用二:类似于多重if -> 使用于不等式的判断

case

when 条件1 then 满足条件1要显示的值1或语句1(;是语句时添加)

when 条件2 then 满足条件2要显示的值2或语句2(;是语句时添加)

else 要显示的值n或语句n

end

/* 查询员工的工资
部门号 = 30,显示的工资为1.1
部门号 = 40,显示的工资为1.2
部门号 = 50,显示的工资为1.3
其他部门,为原工资
*/
SELECT salary * CASE department_id
WHEN 30 THEN 1.1
WHEN 40 THEN 1.2
WHEN 50 THEN 1.3
ELSE 1
END AS 工资
FROM employees; 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 1 * salary
END AS 工资
FROM employees; /* 查询员工的工资情况
如果工资>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;

多行函数

说明:做统计使用,有称为统计函数、聚合函数,一组数据输出一个结果

sum 求和、avg 平均值、max 最大值、min 最小值、count 计算非null个数

注意:

1.参数支持类型 sum/avg 数值型 max/min/count 任何类型

2.以上分组函数都忽略null值

3.可以和distinct搭配使用实现去重

4.COUNT(*)常用于统计行数

5.和分组函数一同查询的字段要求是本表中group by后的字段 - 结果要求是规整的表格

# 去重之后再求和
SELECT SUM(DISTINCT salary) FROM employees;
# 保留2位,一般后面跟数字就是保留小数点后几位
SELECT AVG(salary,2) FROM employees;
# 统计非空行数
SELECT COUNT(*) FROM employees;
# 相当于多了列,一列全部是常数值,统计非空行数
SELECT COUNT(1/常数值) FROM employees; SELECT DATEDIFF('2017-10-1','2017-9-29') # 2 (9.30 10.1)

分组查询

语法

SElECT 分组之后执行的函数,列(要求出现在group by的后面,分组条件,不需要显示就不写)

FROM table

[where condition]

[group by group_by_expression]

[order by 子句];

注意:

1.where一定放在from后面 -- 执行顺序先from再where再select查询构成基础查询,基础查询后面进行其他约束

2.查询列表特殊,要求是分组之后执行的函数和group by后面出现的字段(根据什么分组/每组条件)

有条件的分组

1.先筛选后分组

原始表中就能找到筛选的条件

2.先分组后筛选

原始表中找不到筛选的条件,分组后才能找到筛选的条件。筛选条件的关键词用having(理解为分组后是否有某个条件的行)

说明

1.分组之后执行的函数作为筛选条件,肯定是放在having后面

2.能先筛选的就先筛选

先筛选后分组

原始表中就能找到筛选的条件

# 案例1:查询每个工种的最高工资  分组条件每个工种
SELECT MAX(salary),job_id
FROM employees
GROUP BY job_id; # 先筛选再分组 - 此时筛选的字段在from表里
/*
案例1.查询邮箱中包含a字符的,每个部门的平均工资
分组条件每个部门
*/
SELECT AVG(salary),department_id
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;

先分组后筛选

原始表中找不到筛选的条件,分组后才能找到筛选的条件。筛选条件的关键词用having(理解为分组后是否有某个条件的行)

# 先分组在筛选
/*
案例:查询哪个部门的员工个数>2
1.查询每个部门的员工个数
2.筛选>2的部门
*/
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>2;
/*
案例:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
1.查询每个工种有奖金的员工的最高工资
2.最高工资>12000
*/
SELECT MAX(salary) 最高工资,job_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING 最高工资>12000; # 按表达式或者是函数分组
/*
案例:按员工姓名的长度分组,查询每组的员工个数,筛选员工个数>5的
*/
SELECT COUNT(*) 员工个数,LENGTH(last_name) 姓名长度
FROM employees
GROUP BY 姓名长度
HAVING 员工个数>5;

按多个字段分组

多个字段之间用逗号隔开并没有顺序要求

/*
案例:查询每个部门(不为null)每个工种的员工的平均工资,并按平均工资的高低显示
*/
SELECT AVG(salary) 平均工资,department_id,job_id
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id,job_id
ORDER BY 平均工资 DESC;

连接查询/多表查询

说明:

1.用于查询的字段来自于多个表

2.通常使用sql99标准

按功能分类

  • 内连接
    • 等值连接
    • 非等值连接
    • 自连接
  • 外连接
    • 左外连接
    • 右外连接
    • 全外连接(mysql不支持)
  • 交叉连接

sql92标准

等值连接

实现原理:用第一张的表的一行去匹配第二张表的每一行,匹配成功则留下来

说明:where后面添加连接条件

特点:

1.多表等值连接的结果为多表的交集部分

2.多表的顺序没有要求,一般为表起别名

注意:

1.先走from,起了别名后就不认识原表名了,所以就不能使用原表名去限定

2.有筛选条件就在where后面添加and

/*
案例1:查询员工名、工种号、工种名
*/
SELECT last_name,e.`job_id`,job_title # 这里的job_id有歧义,需要表来限定
FROM employees e,jobs j # 当多次使用表名限定时,可以给表起别名
WHERE e.`job_id` = j.`job_id`; # 有筛选条件使用and
/*
案例2.查询有奖金的员工名,部门名
*/
SELECT last_name,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.`department_id`
AND commission_pct IS NOT NULL; # 添加分组
/*
案例1:查询每个城市的部门个数
*/
SELECT COUNT(*) 个数,city
FROM departments d,locations l
WHERE d.`location_id` = l.`location_id`
GROUP BY city; # 添加排序
/*
案例:查询每个工种的工种名和员工的个数,并按员工的个数降序
*/
SELECT job_title,COUNT(*) AS 员工个数
FROM employees e,jobs j
WHERE e.`job_id` = j.`job_id`
GROUP BY job_title
ORDER BY 员工个数 DESC;

非等值连接

where条件之后不是通过等于连接的

自连接

自连接相当与等值连接,区别在于等值连接是多表连接,自连接是单表自己连接自己。

/*
案例1:查询员工名和上级的名称 同一张表需要寻找两遍
第一遍找员工的领导编号是是多少,第二遍找这个编号对应的人是谁
*/
SELECT
e.employee_id 员工编号,
e.last_name 员工名,
m.employee_id 领导编号,
m.last_name 领导名
FROM
employees e,employees m
WHERE m.employee_id =e.manager_id;

sql99标准

语法

select 查询列表

from 表1 别名

[连接类型] join 表2 别名

on 连接条件

[where 筛选条件]

连接类型

内连接:inner

外连接

左外 left [outer]

右外 right [outer]

全外 full [outer]

交叉连接 cross

等值连接

inner可以省略

# 等值连接
/*
案例.查询部门个数>3的城市名和部门个数
*/
SELECT city,COUNT(*) 部门个数
FROM departments d
INNER JOIN locations l
ON d.`location_id`= l.`location_id`
GROUP BY city
HAVING 部门个数>3;

非等值连接

# 查询员工的工资级别
SELECT salary,grade_level
FROM employees e
JOIN job_grades g
ON e.salary BETWEEN g.lowest_sal AND highest_sal'

自连接

/*
案例1:查询员工名和上级的名称 同一张表需要寻找两遍
第一遍找员工的领导编号是是多少,第二遍找这个编号对应的人是谁
*/
SELECT
e.employee_id 员工编号,
e.last_name 员工名,
m.employee_id 领导编号,
m.last_name 领导名
FROM
employees e
INNER JOIN
employees m
ON m.employee_id =e.manager_id;

外连接

应用场景:内连接连接的是交集部分;外连接用于查询一个表中有,另外一个表没有的记录。

说明

1.有主从表之分,主表会全部显示出来

2.左外连接 左边的是主表、右外连接 右边的是主表

3.全外不分主从表 = 内连接的结果 + 表1中2没有的 + 表2中有1没有的

/*
案例1.查询哪个部门没有员工
*/
SELECT department_name
FROM departments d
LEFT JOIN employees e
ON d.`department_id` = e.`department_id`
WHERE employee_id IS NULL;

交叉连接

表1 4行 表2 11行 结果 44行

表1一行对应表2 11行 - 笛卡尔连接、

子查询

说明:出现在其他语句中的select语句,称为子查询或内查询,一般放在小括号里。

# select后面 相关子查询
# 仅支持标量子查询 结果集只有一行一列
# from 后面
# 表子查询 一般为多行多列
# where或having后面 ★
# 标量子查询(单行) √
# 列子查询(多行) 结果集只有一列多行 √
# 行子查询 较少 结果集有一行多列
# exists后面(相关子查询)
# 表子查询 一般为多行多列

where或having后面

标量子查询-单行子查询 列子查询-多行子查询

特点:

1.标量子查询,一般搭配单行操作符使用(> <...)

2.列子查询,一般单配多行操作符使用(in,any/some,all)

IN/NOT IN 等于列表中的任意一个

ANY/SOME 和子查询返回的某一个值比较

ALL 和子查询返回的所有值比较

3.子查询的执行先于主查询

# 标量子查询

/*
案例1:谁的工资比Abel高
*/
#①查询Abel的工资 ②查询员工的信息,满足salary>①
SELECT *
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
) # 列子查询 /*
案例1.返回其他部门中比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 DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
); # 行子查询(结果集一行多列或多行多列)
/*
查询员工编号最小并且工资最高的员工信息
*/ SELECT *
FROM employees
WHERE employee_id=(
SELECT MIN(employee_id)
FROM employees
)
AND salary = (
SELECT MAX(salary)
FROM employees
);
# 需要筛选条件都是相同的,可以用行查询代替
SELECT *
FROM employees
WHERE (employee_id,salary) = (
SELECT MIN(employee_id),MAX(salary)
FROM employees
)

select后面

不常用,仅仅支持标量子查询

/*
案例1:查询员工号=102的部门号
*/
SELECT(
SELECT department_name
FROM departments d
INNER JOIN employees e
ON d.department_id = e.department_id
WHERE e.employee_id=102
); /*
案例2:查询每个部门的员工个数
*/
SELECT d.*,
(
SELECT COUNT(*)
FROM employees e
WHERE d.`department_id` = e.`department_id`
) 个数
FROM departments d; # d表中department_id的个数更多

from后面

一般from后面接着表,所以相当于将子查询的结果集充当表格使用。

要求该表必须其别名

/*
案例:查询每个部门的平均工资的工资等级
*/
#①查询每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id #②连接①的结果和job_grades进行等级匹配 SELECT dep.*,g.grade_level
FROM( # 这个表一定要起别名,不然找不到
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) dep
INNER JOIN job_grades g
ON dep.ag BETWEEN lowest_sal ANG highest_sal;

exists后面(相关子查询)

语法:exists(完整的查询语句)

结果:1或者0

一般可以使用exists的都可以使用IN使用,所以使用频率不高

/*
案例:查询有员工的部门名
*/
# 先执行外查询,通过子查询过滤
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 department_id
FROM employees
)

分页查询

使用场景:当需要显示的数据,一页显示不全,需要分页提交sql请求

语法:

select 查询列表

from 表

limit [offset要显示条目的起始索引(从0开始)],size显示的条目个数

注意:

1.limit需要放在最后,执行的顺序也是最后执行

2.要显示的页数page,每页的条目数size limit size*(page-1),size

/*
案例1:查询前五条员工信息
*/
SELECT * FROM employees LIMIT 0,5;
SELECT * FROM employees LIMIT 5; # 从第一条开始可以省略 /*
案例2:有奖金的员工信息,并且工资较高的前10名显示出来
*/
SELECT * FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10;

执行顺序

中途每步都会生成虚拟表

1.from

2.join-on

3.where

4.group-by

5.having

6.select

7.order-by

8.limit

习题

/*
查询平均工资最高的job信息
*/
# ①查询平均最高工资
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id
ORDER BY AVG(salary) DESC
LIMIT 1
# ②查询job信息
SELECT j.*
FROM jobs j
WHERE j.job_id = (
SELECT e.job_id
FROM employees e
GROUP BY e.job_id
ORDER BY AVG(salary) DESC
LIMIT 1
) /*
查询平均工资高于公司平均工资的部门有哪些
*/
# 1.查询公司的平均工资
SELECT AVG(salary)
FROM employees
# 2.查询平均工资高于公司平均工资的部门id
SELECT AVG(salary) 部门平均工资,department_id
FROM employees
GROUP BY department_id
HAVING 部门平均工资>(
SELECT AVG(salary)
FROM employees
)

union联合查询

说明:将多条查询语句的结果合并成一个结果

语法:

查询语句1

union

查询语句2

union

....

使用场景:要查询的结果来自多个表,且多个表没有直接的连接关系,查询的信息顺序需要一样

注意:

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;