MySql基础学习
七、数据查询【重点】
7.1 数据库表的基本结构
关系数据库是以表格(Table)进行数据存储,表格由“行”和“列”组成
- 经验:执行查询语句返回的结果是一张虚拟表
7.2 基本查询
语法:SELECT列名FROM表名
关键字 | 描述 |
---|---|
SELECT | 指定要查询的列 |
FROM | 指定要查询的表 |
7.2.1 查询部分列
# 查询员工表中所有员工的编号】你名字、邮箱
select employee_id fist_name, email
from t_employee
7.2.2查询所有列
# 查询所有列
# 1、使用*的方式
SELECT * FROM t_employees;
# 2、使用列名的方式
SELECT 所有列的列名 FROM t_employees;
- 注意:生产环境下,优先使用列名查询,*的方式需要转换成全列名。效率低,可读性差
7.2.3 对列中的数据进行运算
# 查询员工的编号、名字、年薪
SELECT EMPLOYEE_ID,FIRST_NAME,SALARY * 12 FROM t_employees
算数运算符 | 描述 |
---|---|
+ | 两列做加法运算 |
- | 两列做减法运算 |
* | 两列做乘法运算 |
/ | 两列做除法运算 |
- % 是占位符。而并非模运算符
7.2.4 列的别名
列 as 列名
SELECT EMPLOYEE_ID '编号',FIRST_NAME AS '姓氏',SALARY * 12 AS '年薪' FROM t_employees;
7.2.5 查询结果去重
distinct 列名
# 查询员工表中有多少个经理
SELECT DISTINCT MANAGER_ID FROM t_employees;
7.3 排序查询
语法:SELECT 列名 FROM 表名
ORDER BY排序列[排序规则]
排序规则 | 描述 |
---|---|
ASC | 对前面排序列做升序排列 |
desc | 对前面排序列做降序排序 |
7.3.1 依据单列排序
# 对员工工资进行升序排序
SELECT EMPLOYEE_ID,salary FROM t_employees ORDER BY salary + 0 ASC;
# 对员工工资进行降序排序
SELECT EMPLOYEE_ID,salary FROM t_employees ORDER BY salary + 0 DESC;
7.3.2 依据多列排序
# 按照工资高低进行降序排序,如果工资相等,按照员工编号升序进行排序
SELECT EMPLOYEE_ID,salary FROM t_employees ORDER BY salary + 0 DESC, EMPLOYEE_ID DESC;
7.4 条件查询
语法: SELECT 列名 FROM 表名 WHERE 条件
关键字 | 描述 |
---|---|
where 条件 | 在查询结果中,筛选符合查询条件的查询结果,条件为布尔表达式 |
7.4.1 等值判断
# 查询符合条件的数据
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY = 11000
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY = 24000
- 注意:与java不同(==),mysql中等值判断使用=
7.4.2 逻辑判断(and 、or、 not)
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY = 11000 AND COMMISSION_PCT = 0.30 AND EMPLOYEE_ID = '148';
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY = 11000 OR COMMISSION_PCT = 0.30;
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE NOT SALARY = 11000;
7.4.3 不等值判断(>、 <、>=、<=、<>、!=)
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY != 11000;
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY <> 11000;
# 查询工资区间在[6000, 10000]之间
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY >= 6000 AND salary <= 10000;
7.4.4 区间判断(between 起始and 终止)
# 查询工资区间在[6000, 10000]之间
SELECT EMPLOYEE_ID, FIRST_NAME,salary
FROM t_employees
WHERE SALARY BETWEEN 6000 AND 10000;
- 注意:在区间判断中,小值在前,大值在后,反之,得不到结果
7.4.5 null值判断(is null、is not null)
# 查询出经理编号为null的员工信息
SELECT employee_id, FIRST_NAME,MANAGER_ID
FROM t_employees
WHERE MANAGER_ID IS NULL;
SELECT employee_id, FIRST_NAME,MANAGER_ID
FROM t_employees
WHERE MANAGER_ID IS NOT NULL;
7.4.6 枚举查询(IN(值1, 值2,值3))
# 查询部门编号为70,80,90 的员工信息
SELECT EMPLOYEE_ID, FIRST_NAME,SALARY,department_id
FROM t_employees
WHERE department_id = 70 OR department_id = 80 OR department_id = 90;
SELECT EMPLOYEE_ID, FIRST_NAME,SALARY,department_id
FROM t_employees
WHERE department_id IN (70,80,90);
# in 的效率在大数据面前较低
7.4.7 模糊查询
- LIKE_(单个任由字符)
列名 LIKE ‘张__’
LIKE %(任意长度的任意字符)
列名 LIKE ‘张%’
- 注意:模糊查询只能和LIKE关键字结合使用
# 查询L开头的三个字的员工信息
SELECT EMPLOYEE_ID, FIRST_NAME, SALARY
FROM t_employees
WHERE FIRST_NAME LIKE 'L__';
# 查询所有以L开头的员工信息
SELECT EMPLOYEE_ID,FIRST_NAME,SALARY
FROM t_employees
WHERE first_name LIKE '张%';
7.4.8 分支结构查询
CASE
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
WHEN 条件3 THEN 结果3
ELSE 结果
END
- 注意:通过使用case end进行条件判断,每条数据对应生成一个值
- 经验:类似java中的switch
# 查询员工信息
SELECT EMPLOYEE_ID, FIRST_NAME, SALARY,department_id,
CASE
WHEN SALARY >= 10000 THEN 'A'
WHEN SALARY >= 8000 AND SALARY < 10000 THEN 'B'
WHEN SALARY >= 6000 AND SALARY < 8000 THEN 'C'
WHEN SALARY >= 4000 AND SALARY < 6000 THEN 'D'
ELSE 'E'
END AS "level"
FROM t_employees;
7.5 时间查询
select 时间函数([参数列表])
- 经验:执行时间函数查询,会自动生成一张虚表
时间函数 | 描述 |
---|---|
SYSDATE | 当前系统时间(日月年时分秒) |
CURDATE | 获取当前日期 |
CURTIME | 获取当前时间 |
WEEK(DATE) | 获取指定日期为一年中的第几周 |
YEAR(DATE) | 获取指定日期的年份 |
HOUR(TIME) | 获取指定时间的小时值 |
MINUTE(TIME) | 获取时间的分钟值 |
DATEDIFF(DATE,DATE2) | 获取DATE1和DATE2之间相隔的天数 |
ADDDATE(DATE,N) | 计算DATE加上N天后的日期 |
# 当前系统的时间
SELECT SYSDATE();
# 当前系统的ri期
SELECT CURDATE();
# 获取系统时间
SELECT CURTIME();
# 获取指定日期为一年中的第几周
SELECT WEEK(SYSDATE());
# 获取指定日期忠厚的年份
SELECT YEAR(SYSDATE());
# 获取小时值
SELECT HOUR(CURTIME());
# 获取分钟值
SELECT MINUTE(CURTIME());
# 指定日期之间的相隔天数
SELECT DATEDIFF('2020-4-1','2019-4-1');
# 计算date日期加上n天后的日期
SELECT ADDDATE('2020-4-1', 5);
7.6 字符串查询
语法: SELECT 字符串函数([参数列表])
字符串函数 | 说明 |
---|---|
concat(str1, …) | 将多个字符串拼接 |
insert(str, pos, len, newStr) | 将str中指定pos位置开始len长度的内容替换为newStr |
lower(str) | 将指定字符串转换诶小写 |
upper(str) | 将指定字符串转换为大写 |
substring(str, num, len) | 将str字符串指定num位置开始截取len个内容 |
# 多个字符串拼接
SELECT CONCAT('My', 'S,', 'QAL');
SELECT CONCAT(FIRST_NAME,'-', last_name) FROM t_employees;
# 字符串替换
SELECT INSERT('这是一个数据库',3, 2, 'MySql')
# 字符串转小写
SELECT LOWER('LOWER')
# 字符串转大写
SELECT UPPER('shdiuashdui')
# 指定内容截取
SELECT SUBSTRING('JaavaMySqlStrSub',6,6);
# MySqlS
7.7 聚合函数
语法: SELECT 聚合函数(列名) FROM 表名;
- 经验:对多条数据的单列进行统计,返回统计后的一行结果
聚合函数 | 说明 |
---|---|
SUM() | 求所有行中单列结果的总和 |
AVG() | 平均值 |
MAX() | 最大值 |
MIN() | 最小值 |
COUNT() | 求总行数 |
# 聚合函数
# 求单列所有数据的和
SELECT SUM(SALARY) FROM t_employees;
# 求单列所有数据的平均值
SELECT AVG(SALARY) FROM t_employees;
# 求单列最大值
SELECT MAX(SALARY + 0) FROM t_employees;
# 求单列最小值
SELECT MIN(salary + 0) FROM t_employees;
# 求总行数 员工总数
SELECT COUNT(EMPLOYEE_ID) FROM t_employees;
# 统计有提成的人数 会自动忽略null值,不进行统计
SELECT COUNT(COMMISSION_PCT) FROM t_employees;
- 注意:聚合函数会自动忽略null值,不进行统计
7.8 分组查询
语法:
SELECT 列名 FROM 表名 WHERE 条件 GROUP BY 分组依据(列);
关键字 | 说明 |
---|---|
GROUP BY | 分组依据,必须在WHERE之后生效 |
# 查询各个部门的额总人数
SELECT department_id, COUNT(employee_id)
FROM t_employees
GROUP BY department_id;
# 查询各个部门的平局工资
SELECT department_id, AVG(salary)
FROM t_employees
GROUP BY department_id;
# 查询各个部门、各个岗位的总人数
SELECT department_id,job_id, COUNT(employee_id)
FROM t_employees
GROUP BY department_id, job_id;
# 常见问题:查询各个部门id,总人数、first_name
SELECT department_id,COUNT(employee_id), first_name
FROM t_employees
GROUP BY department_id;
- 分组查询中,select显示的列只能是分组依据列,或者聚合函数列,不能出现其他列
7.9 分组过滤查询
语法:
SELECT 列名 FROM 表名 WHERE 条件 GROUNP BY 分组列 HAVING 过滤规则
关键字 | 说明 |
---|---|
HAVING过滤规则 | 过滤规则定义对分组后的数据进行过滤 |
统计部门的最高工资
#思路
#1.确定分组依据(DEPARTMENT_ID)
#2.对分组后的数据,过滤出部门编号是60、70、90信息
#3.MAX()函数
SELECT DEPARTMENT_ID,MAX(SALARY)
FROM t_employees GROUP BY DEPARTMENT_ID
HAVING DEPARTMENT_ID IN (60,70,90);
#GROUP确定分组依据DEPARTMENT_ID
#HAVING过滤出60,70,90的部门
#SELECT查看部门编号和MAX函数
7.10 限定查询
语法:
SELECT 列名 FROM 表名 LIMIT 起始行,查询行数
关键字 | 说明 |
---|---|
LIMIT offset_start,row_count | 限定查询结果的起始行和总行数 |
7.10.1 查询前5行记录
#查询表中前五名员工的所有信息
SELECT * FROM t_employees LIMIT 0,5;
- 注意:起始行是从0开始,代表了第一行,第二个参数代表的是从指定行开始查询几行。
7.10.2 查询范围记录
#查询表中从第四行开始,查询10行
SELECT * FROM t_employees LIMIT 3,10;
7.10.3 LIMIT典型应用
分页查询:一页显示10条,一共查询三页。
#思路:第一页是从0开始,显示10条
SELECT * FROM t_employees LIMIT 0,10;
#第二页是从10条开始,显示10条
SELECT * FROM t_employees LIMIT 10,10;
#第三页是从20条开始,显示10条
SELECT * FROM t_employees LIMIT 20,10;
- 在分页应用场景中,起始行是变化的,但是一页显示的页数是不变的
7.11 查询总结
7.11.1 SQL语句编写顺序
COPYSELECT 列名 FROM 表名 WHERE 条件 GROUP BY 分组 HAVING 过滤条件 ORDER BY 排序列(ASC|DESC) LIMIT 起始行,查询行数
7.11.2 SQL语句执行顺序
COPY1.FROM:指定数据来源表
2.WHERE:对查询数据第一次过滤
3.GROUP BY:分组
4.HAVING:对分组后的数据第二次过滤
5.SELECT:查询各字段的值
6.ORDER BY:排序
7.LIMIT:限定查询结果
7.12 子查询(作为条件判断)
语法:
SELECT 列名 FROM 表名 WHERE 条件(子查询结果)
7.12.1 查询工资大于Bruce的员工信息
#1.先查询到Bruce的工资(一行一列)
SELECT SALARY FROM t_employees WHERE FIRST_NAME = 'Bruce';
#2.查询工资大于Bruce的员工信息
SELECT * FROM t_employees WHERE SALARY > 6000;
#3.将前两句整合
SELECT * FROM t_employees
WHERE SALARY >
(SELECT SALARY FROM t_employees WHERE FIRST_NAME = 'Bruce');
- 注意:将子查询“一行一列”的结果作为外部查询的条件,做第二次查询。
- 子查询得到一行一列的结果才能作为外部查询的等值判断条件或不等值判断条件
7.13 子查询(作为枚举查询的条件)
语法:
SELECT 列名 FROM 表名 WHERE 列名 IN (子查询结果);
7.13.1 查询与名为“KING”同一部门的员工信息
#思路
#1.先查询KING所在的部门编号
SELECT DEPARTMENT_ID FROM t_employees WHERE LAST_NAME = 'King';#80,90
#2.再查询80,90号部门的员工信息
SELECT * FROM t_employees WHERE DEPARTMENT_ID IN(80,90);
#3.SQL:合并
SELECT * FROM t_employees
WHERE DEPARTMENT_ID IN
(SELECT DEPARTMENT_ID FROM t_employees WHERE LAST_NAME = 'King');
- 将子查询“多行一列”的结果作为外部查询的枚举查询条件,做第二次查询。
7.13.2 工资高于60编号部门的员工信息
#1.查询60编号部门所有人的工资(多行单列)
SELECT SALARY FROM t_employees WHERE DEPARTMENT_ID = 60;
#2.查询工资高于60编号部门所有人的工资的员工信息(高于所有)
SELECT * FROM t_employees
WHERE SALARY >
ALL(SELECT SALARY FROM t_employees WHERE DEPARTMENT_ID = 60);
#3.查询工资高于60编号部门的员工信息(高于部分)
SELECT * FROM t_employees
WHERE SALARY >
ANY(SELECT SALARY FROM t_employees WHERE DEPARTMENT_ID = 60);
-
注意:当子查询结果集形式为多行单列时可以使用ANY或ALL关键字。
-
ALL表示查询高于部门所有员工工资的员工信息;ANY表示查询只需要高于部门中任意一名员工工资的员工信息
7.14 子查询(作为一张表)
查询到一张多行多列的临时表,这张表也可以作为查询数据源。
语法:
SELECT 列名 FROM (子查询的结果集) WHERE 条件;
7.14.1 查询员工表中工资排名前5名的员工信息
#思路:
#1.先对所有员工的薪资进行排序(排序后的临时表)
SELECT EMPLOYEE_ID,FIRST_NAME,SALARY FROM t_employees ORDER BY SALARY DESC;
#2.再查询临时表中前5行员工信息
SELECT EMPLOYEE_ID,FIRST_NAME,SALARY FROM (临时表) LIMIT 0,5;
#3.合并
SELECT * FROM
(SELECT EMPLOYEE_ID,FIRST_NAME,SALARY FROM t_employees ORDER BY SALARY DESC) AS 临时表 LIMIT 0,5;
- 将子查询“多行多列“的结果作为外部查询的一张表,做第二次查询。
- 注意:子查询作为临时表,需要为其赋予一个临时表名。
7.15 合并查询
SELECT * FROM 表名1 UNION SELECT * FROM 表名2
SELECT * FROM 表名1 UNION ALL SELECT * FROM 表名2
- 返回的查询结果是将表1的结果和表2的结果做了一个合并。
15.1 合并两张表的结果(去除重复记录)
#合并两张表的结果,去除重复记录
SELECT * FROM T1 UNION SELECT * FROM T2;
- 注意:合并结果的两张表,列数必须相同,列的数据类型可以不同。
列数必须相同是因为该合并做了一个纵向合并,两个4列多行的结果集表合并后也是一个4列多行的表,但是合并后的列名以第一个结果集表为准。
7.15.2 合并两张表的结果(保留重复记录)
#合并两张表的结果,不去除重复记录(显示所有)
SELECT * FROM T1 UNION ALL SELECT * FROM T2;
该合并结果会保留两张查询表中重复的记录,而UNION只保留第一个不重复的记录
7.16 表连接查询
语法:
SELECT 列名 FROM 表1 连接方式 表2 ON 连接条件
7.16.1 内连接查询(INNER JOIN ON)
#1.查询所有员工的职员和职位信息 SQL标准
SELECT * FROM t_employees INNER JOIN t_jobs
ON t_employees.JOB_ID = t_jobs.JOB_ID;
#2.查询所有员工的职员和职位信息 MYSQL
SELECT * FROM t_employees,t_jobs WHERE t_employees.JOB_ID = t_jobs.JOB_ID;
如果没有指定连接条件,则会造成笛卡尔积的结果,第一张表中的每行数据都会和第二张表进行连接。
- 经验:在MySQL中,第二种方式也可以作为内连接查询,但是不符合SQL标准。
- 而第一种属于SQL标准,与其他关系型数据库通用。
7.16.2 三表连接查询
#查询所有员工工号、名字、部门名称、部门所在国家ID
SELECT EMPLOYEE_ID,FIRST_NAME,t_departments.DEPARTMENT_NAME,t_locations.COUNTRY_ID
FROM t_employees
INNER JOIN t_departments ON
t_employees.DEPARTMENT_ID=t_departments.DEPARTMENT_ID
INNER JOIN t_locations ON
t_departments.LOCATION_ID=t_locations.LOCATION_ID;
该语句查询出来的结果没有员工编号为178的员工信息,该名员工的部门ID为NULL,不符合连接条件,所以不包含在匹配出的结果集中,你可以自己动手尝试并查看结果。之所以提这个是因为可以与下节的语句区分开来。
7.16.3 左外连接(LEFT JOIN ON)
#查询所有员工的工号、名字、工资及其对应的部门名称(没有部门的员工也在查询结果中,部门名称以NULL值补充)
SELECT EMPLOYEE_ID,FIRST_NAME,SALARY,DEPARTMENT_NAME
FROM t_employees
LEFT JOIN t_departments
ON t_departments.DEPARTMENT_ID=t_employees.DEPARTMENT_ID;
该语句查询出来的结果包含没有部门的178号员工,DEPARTMENT_NAME的值被填充为NULL。
- 注意:左外连接,是以左表作为主表,依次向右匹配,匹配到则返回结果;
- 匹配不到则返回NULL值填充。
7.16.4 右外连接(RIGHT JOIN ON)
#查询所有部门信息,以及此部门中的所有员工信息(没有员工的部门也在查询结果中,员工信息以NULL值填充)
SELECT EMPLOYEE_ID,FIRST_NAME,SALARY,DEPARTMENT_NAME
FROM t_employees
RIGHT JOIN t_departments
ON t_departments.DEPARTMENT_ID=t_employees.DEPARTMENT_ID;
该查询结果以部门表作为主表,有些部门没有员工,其员工信息全部为NULL。
- 注意:右外连接,是以右表为主表,依次向左匹配,匹配到返回结果。
- 匹配不到,则返回NULL值填充。