一、学习目标
二、DQL查询单表中数据
1.数据准备
# 创建员工表格式
表名 emp
表中字段:
eid 员工id,int
ename 姓名,varchar(20)
sex 性别,char(1)
salary 薪资,double(7,1)
hire_date 入职时间,date
dept_name 部门名称,varchar(20)
# 1.创建bjsxt02数据库
create database bjsxt02;
# 2.选择bjsxt02
use bjsxt02;
# 3.创建员工表
create table emp(
eid int,
ename varchar(20),
sex char(1),
salary double(7,1),
hire_date date,
dept_name varchar(20)
);
添加测试数据
# 添加测试数据
insert into emp VALUES(1,'孙悟空','男',7200,'2013-02-04','教学部');
insert into emp VALUES(2,'猪八戒','男',3600,'2010-12-02','教学部');
insert into emp VALUES(3,'唐僧','男',9000,'2008-08-08','教学部');
insert into emp VALUES(4,'白骨精','女',5000,'2015-10-07','市场部');
insert into emp VALUES(5,'蜘蛛精','女',5000,'2011-03-14','市场部');
insert into emp VALUES(6,'玉兔精','女',200,'2000-03-14','市场部');
insert into emp VALUES(7,'林黛玉','女',10000,'2019-10-07','财务部');
insert into emp VALUES(8,'黄蓉','女',3500,'2011-09-14','财务部');
insert into emp VALUES(9,'吴承恩','男',20000,'2000-03-14',null);
insert into emp VALUES(10,'孙悟饭','男', 10,'2020-03-14','财务部');
insert into emp VALUES(11,'兔八哥','女', 300,'2010-03-14','财务部');
insert into emp VALUES(12,'Tom','男', null,'2010-03-14','财务部');
2.简单查询
select 字段名 1, 字段名 2,... from 表名 ;
案例1:查询emp中所有的数据
-- 1. 将要查询的字段全部列出select eid ,ename, sex, salary, hire_date, dept_name from emp;-- 2. 查询所有的字段可以使用 * , * 代表所有的字段select * from emp;
案例2:查询emp表中所有的记录,只显示eid和ename字段
select eid, ename from emp;
需求3: 查询所有的员工信息, 将字段名显示为中文
SELECT
eid AS 编号,
ename AS 姓名,
sex AS 性别,
salary AS 薪资,
hire_date AS 入职日期,
dept_name AS 部门名称
FROM
emp;![]()
需求4: 查询有多少个部门
-- 查询所有的部门 ( 出现重复部门 )select dept_name from emp;-- 使用去重查询 关键字 distinctselect distinct dept_name from emp;
需求5:将所有的员工薪资加1000显示
-- 支持算术运算符 + - * / % 的运算select eid, ename, salary, salary + 1000 from emp;![]()
3.条件查询(精确查询、模糊查询)
如果查询语句中没有设置条件, 就会查询所有的行信
在实际应用中, 通常会指定查询的条件, 对记录进行过滤
语法格式:
select 列名 from 表名 where 条件 ;
3.1 比较运算符
运算符 |
说明 |
> < <= >= = <> != |
大于 小于 小于等于 大于等于 等于 不等于 |
between...and... |
显示在某一区间的值 |
in(集合) |
集合表示多个值,使用逗号分隔,例如name in (悟空,八戒); in中的每个数据都会作为一次条件,只要满足条件就会显示 |
like '%张%' |
模糊查询 |
is null |
查询某一列为null的值,注意,不能写 = null |
3.2 逻辑运算符
运算符 |
说明 |
and && |
多个条件同时成立 |
or || |
多个条件任一成立 |
not |
取反 |
案例1:精确查询
#1 查询员工姓名为黄蓉的员工信息select * from emp where ename = ' 黄蓉 ' ;#2 查询薪水价格为 5000 的员工信息select * from emp where salary = 5000 ;#3 查询薪水价格不是 5000 的所有员工信息select * from emp where salary != 5000 ;select * from emp where salary <> 5000 ;#4 查询薪水价格大于 6000 元的所有员工信息select * from emp where salary > 6000 ;#5 查询薪水价格在 5000 到 10000 之间的员工信息select * from emp where salary >= 5000 and salary <= 10000 ;select * from emp where salary between 5000 and 10000 ;#6 查询薪水价格是 3600 或 7200 或者 20000 的员工信息select * from emp where salary = 3600 or salary = 7200 or salary = 20000 ;select * from emp where salary in ( 3600 , 7200 , 20000 ) ;
案例2:模糊查询
模糊查询,通配符
通配符 |
说明 |
% |
表示匹配任意多个字符 |
_ |
表示匹配任意一个字符 |
#1 查询含有'八'字的员工信息
select * from emp where ename like '% 八 %' ;#2 查询以 ' 孙 ' 字开头的员工信息select * from emp where ename like ' 孙 %' ;#3 查询第二个字为 ' 兔 ' 的员工信息select * from emp where ename like '_ 兔 %' ;#4 查询没有部门的员工信息select * from emp where dept_name is null ;#5 查询有部门的员工信息select * from emp where dept_name is not null ;
4.排序
通过order by子语句, 可以将查询出的结果进行排序(排序只是显示效果, 并不会影响真实的数据)。
语法格式:
select 字段名 from 表名 [ where 条件 ] order by 字段名 [ asc | desc ] ;-- asc 升序 ( 默认 )-- desc 降序
4.1 单列排序
只按照某一个字段进行性排序。
案例:查询所有员工信息,使用salary进行排序。
-- 升序排序 ( 默认 asc)select * from emp order by salary;-- 降序排序 (desc)select * from emp order by salary desc ;
4.2 组合排序
同时对多个字段进行排序,如果第一个字段相同,就按照第二个字段排序,以此类推。
-- 组合排序select * from emp order by salary, hire_date desc ;
5.函数
5.1 单行函数
5.1.1 字符串函数
函数 |
描述 |
CONCAT(str1, str2, ···, strn) |
将str1、str2···strn拼接成一个新的字符串 |
INSERT(str, index, n, newstr) |
将字符串str从第index位置(从1开始计算)开始n个字符替换成字符串newstr |
LENGTH(str) |
获取字符串str的长度(字节) |
LOWER(str) |
将字符串str中的每个字符转换为小写 |
UPPER(str) |
将字符串str中的每个字符转换为大写 |
LEFT(str, n) |
获取字符串str最左边的n个字符 |
RIGHT(str, n) |
获取字符串str最右边的n个字符 |
LPAD(str, n, pad) |
使用字符串pad在str的最左边进行填充,直到长度为n个字符为止 |
RPAD(str, n, pad) |
使用字符串pad在str的最右边进行填充,直到长度为n个字符为止 |
LTRIM(str) |
去除字符串str左侧的空格 |
RTRIM(str) |
去除字符串str右侧的空格 |
TRIM(str) |
去除字符串str左右两侧的空格 |
REPLACE(str,oldstr,newstr) |
用字符串newstr替换字符串str中所有的子字符串oldstr |
REVERSE(str) |
将字符串str中的字符逆序 |
STRCMP(str1, str2) |
比较字符串str1和str2的大小 |
SUBSTRING(str,index,n) |
获取从字符串str的index(从1开始)位置开始的n个字符 |
#1 查询 emp 表所有数据 , 将 eid, ename, sex 显示格式为 编号 : x 姓名 : xx 性别 : xselect concat ( ' 编号 :' , eid ) , concat ( ' 姓名 :' , ename ) , concat ( ' 性别 :' , sex ) from emp;#2 查询 emp 表所有数据 , 将 ename 第二个字符都换为 某select eid, insert ( ename, 2 , 1 , 某 '), sex from emp;#3 查询 emp 表所有数据 , 显示 ename 的长度select eid, ename, length(ename), sex from emp;#4 查询 emp 表所有数据 , 将 ename 有英文的改为都是大写select eid, ename, upper(ename), sex from emp;#5 查询 emp 表所有数据 , 将 ename 有英文的改为都是小写select eid, ename, lower(ename), sex from emp;#6 查询 emp 表所有数据 , ename 只显示姓select eid, ename, substring(ename, 1, 1), sex from emp;
5.1.2 数值函数
函数 |
描述 |
ABS(num) |
返回num的绝对值 |
CEIL(num) |
返回大于num的最小整数(向上取整) |
FLOOR(num) |
返回小于num的最大整数(向下取整) |
MOD(num1, num2) |
返回num1/num2的余数(取模) |
PI() |
返回圆周率的值 |
POW(num,n)/POWER(num, n) |
返回num的n次方 |
RAND() |
返回0~1之间的随机数 |
ROUND(num, n) |
返回x四舍五入后的值,该值保留到小数点后n位 |
TRUNCATE(num, n) |
返回num被舍去至小数点后n位的值 |
select abs ( - 1 ) , ceil ( 3.2 ) , floor ( 3.7 ) , round ( 3.5 ) , mod ( 10 , 3 ) , pi () , pow ( 2 , 5 ) ,sqrt ( 25 ) from dual ;select abs ( - 1 ) , ceil ( 3.2 ) , floor ( 3.7 ) , round ( 3.5 ) , mod ( 10 , 3 ) , pi () , pow ( 2 , 5 ) ,sqrt ( 25 ) ;
5.1.3日期与时间函数
函数 |
描述 |
CURDATE() |
返回当前日期 |
CURTIME() |
返回当前时间 |
NOW() |
返回当前日期和时间 |
SYSDATE() |
返回该函数执行时的日期和时间 |
DAYOFYEAR(date) |
返回日期date为一年中的第几天 |
WEEK(date)/WEEKOFYEAR(date) |
返回日期date为一年中的第几周 |
DATE_FORMAT(date, format) |
返回按字符串format格式化后的日期 date |
DATE_ADD(date, INTERVAL expr unit) /ADDDATE(date, INTERVAL expr unit) |
返回date加上一个时间间隔后的新时间值 |
DATE_SUB(date, INTERVAL expr unit) /SUBDATE(date, INTERVAL expr unit) |
返回date减去一个时间间隔后的新时间值 |
DATEDIFF(date1, date2) |
返回起始日期date1与结束日期date2之间的间隔天数 |
select curdate () , curtime () , now () , sysdate () ;select curdate () , curtime () , now () , sleep ( 2 ) , sysdate () ;
5.1.3流程控制函数
间隔类型 |
描述 |
IF(condition, t, f) |
如果条件condition为真,则返回t,否则返回f |
IFNULL(value1, value2) |
如果value1不为null,则返回 value1,否则返回value2 |
NULLIF(value1, value2) |
如果value1等于value2,则返回 null,否则返回value1 |
CASE value WHEN [value1] THEN result1 [WHEN [value2] THEN result2 ...] [ELSE result] END |
如果value等于value1,则返回 result1,···,否则返回result |
CASE WHEN [condition1] THEN result1 [WHEN [condition2] THEN result2 ...] [ELSE result] END |
如果条件condition1为真,则返回 result1,···,否则返回result |
#1 查询 emp 表所有数据 , 薪资 >= 10000 高工资 其他 低工资select eid, ename, salary, if ( salary >= 10000 , ' 高工资 ' , ' 低工资 ' ) from emp;#2 查询 emp 表所有数据 , 计算出员工的年薪 薪资 *12 加年终奖 ( 每人 30k)select eid, ename, salary, salary * 12 + 30000 ' 年薪 ' from emp; -- 需要考虑 nullselect eid, ename, salary, ifnull ( salary, 0 ) * 12 + 30000 ' 年薪 ' from emp;#3 查询 emp 表所有数据 , 薪资 >=3000 加把劲 >=5000 加油哦 >=9000 坚持住 >= 15000 优秀 其 他 不及格select eid, ename, salary,casewhen salary >= 15000 then ' 优秀 'when salary >= 9000 then ' 坚持住 'when salary >= 5000 then ' 加油哦 'when salary >= 3000 then ' 加把劲 'else ' 努力奋斗吧骚年 'endfrom emp;
5.1.5 其它函数
函数 |
描述 |
DATABASE() |
返回当前数据库名 |
VERSION() |
返回当前MySQL的版本号 |
USER() |
返回当前登录的用户名 |
INET_ATON(IP) |
返回IP地址的数字表示 |
INET_NTOA |
返回数字代表的IP地址 |
PASSWORD(str) |
实现对字符串str的加密操作 |
FORMAT(num, n) |
实现对数字num的格式化操作,保留n位小数 |
CONVERT(data, type) |
实现将数据data转换成type类型的操 |
selectdatabase () , user () ,version () ,inet_aton ( "192.168.10.1" ) ,inet_ntoa ( 3232238081 ) ;
5.2 多行函数
多行函数 |
作用 |
count(字段) |
统计指定列不为null的记录行数 |
sum(字段) |
计算指定列的数值和 |
max(字段) |
计算指定列的最大值 |
min(字段) |
计算指定列的最小值 |
avg(字段) |
计算指定列的平均值 |
#1 查询员工的总数-- 使用某个字段查询,聚合函数会忽略 null, 需要注意为 null 的字段select count ( eid ) from emp;-- 所有字段匹配查询select count ( * ) form emp;-- 增加一列select 1 from emp;-- 效率更高推荐使用select count ( 1 ) from emp;#2 查看员工总薪水、最高薪水、最小薪水、薪水的平均值 , 显示为总薪水 , ...selectsum ( salary ) ' 总薪水 ' ,max ( salary ) ' 最高薪水 ' ,min ( salary ) ' 最小薪水 ' ,avg ( salary ) ' 平均薪水 'from emp;#3 查询薪水大于 4000 员工的个数select count ( 1 ) from emp where salary > 4000 ;#4 查询部门为 ' 教学部 ' 的所有员工的个数select count ( 1 ) from emp where dept_name = ' 教学部 ' ;#5 查询部门为 ' 市场部 ' 所有员工的平均薪水select avg ( salary ) from emp where dept_name = ' 市场部 ' ;#6 查询部门的个数select dept_name from emp; -- 9 个select count ( dept_name ) from emp; -- 8 个-- 部门去重之后, 统计个数select count ( distinct dept_name ) from emp; -- 3 个
5.3 经典面试题


创建表及测试数据:
create table student (id int ( 11 ) primary key auto_increment ,name varchar ( 20 ) ,subject varchar ( 20 ) ,score double) ;insert into student values ( 1 , ' 张三 ' , ' 语文 ' , 20 ) ;insert into student values ( 2 , ' 张三 ' , ' 数学 ' , 30 ) ;insert into student values ( 3 , ' 张三 ' , ' 英语 ' , 40 ) ;insert into student values ( 4 , ' 李四 ' , ' 语文 ' , 50 ) ;insert into student values ( 5 , ' 李四 ' , ' 数学 ' , 60 ) ;insert into student values ( 6 , ' 李四 ' , ' 英语 ' , 70 ) ;
方式一:使用if(表达式,值1,值2)函数。如果表达式成立返回值1,否则返回值2。其中值可以是列。
selectmax ( if ( subject = ' 语文 ' ,score, 0 )) 语文 ,max ( if ( subject = ' 数学 ' ,score, 0 )) 数学 ,max ( if ( subject = ' 英语 ' ,score, 0 )) 英语 ,namefrom student group by name;
方式二:使用case 条件 when 条件取值 then 结果 ... else 结果 end
selectmax ( case subject when ' 语文 ' then score else 0 end ) 语文 ,max ( case subject when ' 数学 ' then score else 0 end ) 数学 ,max ( case subject when ' 英语 ' then score else 0 end ) 英语 ,namefrom student group by name;
6. 分组
select 分组字段 / 聚合函数 from 表名 group by 分组字段 [ having 条件 ] ;
需求1: 通过性别分组
# 按照性别分组查询select * from emp group by sex; -- 能查到结果 , 但是没有意义select sex from emp group by sex; -- 正确操作
分析:group by分组过程。
#1 查询每个部门的名称select dept_name from emp group by dept_name;#2 查询每个部门名称及部门的平均薪资select dept_name, avg ( salary ) from emp group by dept_name;#3 查询每个部门名称及部门的平均薪资 , 部门名称不能为空select dept_name, avg ( salary ) from emp where dept_name is not null group bydept_name;
案例2:
#4 查询每个部门名称及部门的平均薪资 , 只显示平均工资在 4000 以上的select dept_name, avg ( salary ) from emp where avg ( salary ) > 4000 group bydept_name;-- Invalid use of group function 报错分析 :1. 需要在分组后 , 对数据进行过滤 , where 的作用是在分组前过滤2. select 语句的执行顺序from -- where -- group by -- having –- select -- order by3. 分组操作中的 having 子语句 , 适用于对分组后的数据进行过滤的 , 作用类似于 where#4 查询每个部门名称及部门的平均薪资 , 只显示平均工资在 4000 以上的select dept_name, avg ( salary ) from emp group by dept_name having avg ( salary ) >4000 ;
过滤方式 |
特点 |
where |
分组之前的过滤后边不能写多行函数 |
having |
分组之后的过滤后边可以写多行函数 |
案例3:
#1 统计每个部门中的最小工资 , 列出最小工资小于 4000 的部门名称及最小薪资-- 每个部门的最小工资select dept_name, min ( salary ) from emp group by dept_name;select dept_name, min ( salary ) from emp group by dept_name having min ( salary ) <4000 ;#2 统计平均工资大于 6000 的部门名称-- 每个部门的平均工资select dept_name, max ( salary ) from emp group by dept_name;select dept_name, max ( salary ) from emp group by dept_name having max ( salary ) >6000 ;#3 统计人数小于 4 个人部门的平均工资-- 每个部门的平均工资和人数select dept_name, avg ( salary ) , count ( 1 ) from emp group by dept_name;select dept_name, avg ( salary ) , count ( 1 ) from emp group by dept_name havingcount ( 1 ) < 4 ;#4 统计每个部门最高工资 , 排除最高工资小于 10000 的部门-- 每个部门的最高工资select dept_name, max ( salary ) from emp group by dept_name;select dept_name, max ( salary ) from emp group by dept_name having max ( salary ) >=10000 ;
7. limit关键字
select 字段 1, 字段 2 ... from 表名 limit offset , length;
#1 查询 emp 表中的前 5 条数据select * from emp limit 5 ; -- 不指定从哪行还是 , 默认从 0 开始select * from emp limit 0 , 5 ;#2 查询 emp 表中 从第 4 条开始 , 查询 6 条select * from emp limit 3 , 6 ; -- 从 0 开始 , 所以第四条数据为 3
相关案例知识点来源于<<尚学堂MySQL数据库知识讲解>>