一、基础查询

1、SELECT语句

(1)DQL(数据查询语言)

SQL语句的构成

(2)案例概述

一对多:城市和学生,班级和学生

多对多:学生和课程(创建新的关联关系表)-----中间表

数据库DQL案例

SELECT基本语法
SELECT column1, column2, ...
FROM table_name
[JOIN … ON … ] -- 连接到其他关联表
[WHERE condition] -- 查询条件,对表中的数据进行筛选
[GROUP BY column1, column2, ...]  -- 按指定的列进行分组
[HAVING condition]  -- 对分组后的结果进行过滤
[ORDER BY column1, column2, ... [ASC | DESC]]  -- 对结果按指定的列进行排序
[LIMIT ]  -- 限制结果集的返回行数
-- 查询语句基本语法:SELECT 列名1, 列名2,...FROM 表名;
SELECT name,age,title FROM teacher;

SELECT * FROM teacher; -- 查询表的所有列,开发时一般禁止使用*
SELECT 语句的执行顺序

1、FROM:指定要检索数据的表或视图

2、WHERE:对表中的数据进行筛选,只返回满足条件的记录

3、JOIN ON: 连接到其他关联表

4、GROUP BY:按照指定的列对结果进行分组

5、HAVING:对分组后的结果进行过滤

6、SELECT:选择需要检索的列,并计算聚合函数(如SUM、AVG等)

7、ORDER BY:按照指定的列对结果进行排序

8、LIMIT:限制结果集的返回行数

2、过滤查询结果

(1)WHERE子句

-- 使用WHERE子句 过滤查询结果
-- 查询一级讲师的名字,性别,年龄,工资
SELECT name, gender, age, salary
FROM teacher
WHERE title = '一级讲师';

-- 查看除了刘苍松以外的所有讲师名字,年龄,工资
-- 推荐使用<>表示不等于
SELECT name, age, salary
FROM teacher
WHERE name <> '刘苍松';

-- 查询职位为大队长的学生的名字,性别,年龄
SELECT name, gender, age
FROM student
WHERE job = '大队长';

-- 查询年龄在30(含)岁以上的老师的名字,年龄,工资,性别
SELECT name, age, salary, gender
FROM teacher
WHERE age > 30;

(2)使用AND和OR连接多个条件

AND的优先级大于OR

-- 年龄是7岁,职位是大队长列出姓名,年龄,性别,职位
SELECT name, age, gender, job
FROM student
WHERE age = 7
  AND job = '大队长';
  
-- 查询所有一级讲师和三级讲师,名字,职称,工资
SELECT name, title, salary
FROM teacher
WHERE title = '一级讲师'
   OR title = '三级讲师';
   
-- 查看所有的大队长中队长小队长的名字,性别,年龄,职位
SELECT name, gender, age, job
FROM student
WHERE job = '大队长'
   OR job = '中队长'
   OR job = '小队长';

(3)使用()调整优先级

因为AND的优先级高于OR,在sql语句中可以使用()来调整优先级

-- 查询班级编号在6(含)以下的
-- 所有大队长和中队长的名字,年龄,性别和职务
SELECT name, age, gender, job, class_id
FROM student
WHERE class_id <= 6
  AND (job = '大队长'
    OR job = '中队长');

(4)IN操作符

-- 查看所有大队长,中队长和小队长的名字,职位,年龄
SELECT name, job, age
FROM student
WHERE job IN ('大队长', '中队长', '小队长');

-- 查询所有的一级讲师和二级讲师和三级讲师的名字,职称,工资,性别
SELECT name, title, salary, gender
FROM teacher
WHERE title IN ('一级讲师', '二级讲师', '三级讲师');

(5)NOT IN 操作符

-- 查看除一级讲师和二级讲师之外所有老师的名字,职称,工资
SELECT name, title, salary
FROM teacher
WHERE title NOT IN ('一级讲师', '二级讲师');

-- 查看除了大队长中队长小队长之外的学生,名字,职位,性别,年龄
SELECT name, job, gender, age
FROM student
WHERE job NOT IN ('大队长', '中队长', '小队长');

(6)BETWEEN AND 操作符

-- 查询工资在2000到5000之间的老师的名字工资职称和性别
SELECT name, salary, title, gender
FROM teacher
WHERE salary BETWEEN 2000 AND 5000;

-- 查看年龄在7到10岁的学生,名字,性别,年龄
SELECT name, gender, age
FROM student
WHERE age BETWEEN 7 AND 10;

-- 查询年龄在20到35岁之间的男老师,名字,性别,年龄,职称
SELECT name, gender, age, title
FROM teacher
WHERE age BETWEEN 20 AND 35
  AND gender = '男';

-- 查询所有在3-5层的班级,列出班级名称和所在楼
SELECT name, floor
FROM class
WHERE floor BETWEEN 3 AND 5;

(7)去除查询结果中重复的行

-- 查看老师都有哪些职位
SELECT DISTINCT title
FROM teacher;

-- 查看学生的职位有哪些
SELECT DISTINCT job
FROM student

-- 查看学生各个年龄段的职位都有哪些 两个加在一起不一样
SELECT DISTINCT age,job
FROM student

(8)LIKE模糊查询

-- 查询名字中含苍的老师都有谁
SELECT *
FROM teacher
WHERE name LIKE '%苍%';

-- 查询姓张的学生都有谁
SELECT name, age, job, gender
FROM student
WHERE name LIKE '张%';

-- 查看名字最后一个字是'晶'的老师
SELECT name, age, gender
FROM teacher
WHERE name LIKE '%晶';

-- 查询三个名字中,第二个字是"平"的学生都有谁
SELECT name
FROM student
WHERE name LIKE '_平_';

-- 查看哪些学生是课代表
SELECT name, job
FROM student
WHERE job LIKE '%课代表';

-- 查看所有2班都在几层
SELECT name, floor
FROM class
WHERE name LIKE '%2班';

(9)NULL值判断

-- 查询没有奖金的老师都有谁
SELECT name,comm
FROM teacher
WHERE comm IS NULL;

-- 查看有奖金的老师都有谁
SELECT name,comm
FROM teacher
WHERE comm IS NOT NULL;

3、对查询结果排序

(1)ORDER BY 子句

-- 查看老师的工资牌名,按最后工资降序排列
SELECT name, salary
FROM teacher
ORDER BY salary DESC;

-- 查看所有老师的奖金情况,从少到多排序
SELECT name, comm
FROM teacher
ORDER BY comm;

-- 查看学生的生日,并且生日由早到晚排序
SELECT name, birth
FROM student
ORDER BY birth;

-- 查看7-10岁的学生信息,学生排序按照从小到大排序
SELECT name, age, birth
FROM student
WHERE age BETWEEN 7 AND 10
ORDER BY birth DESC;

-- 查看老师的工资和奖金,首先按照奖金的升序,再按照工资的降序
SELECT name, salary, comm
FROM teacher
ORDER BY comm, salary DESC;

(2)LIMIT和分页查询

  • offset = (页号-1) * 页面行数
  • row_count = 页面行数
-- 查看老师奖金信息,按照降序排序后,每页显示3条,显示第五页
SELECT name,comm
FROM teacher
ORDER BY comm DESC
LIMIT 12,3;

二、函数和表达式

1、表达式和空值函数

(1)表达式生成结果集

-- 函数和表达式
-- 查看老师的工资和年薪
SELECT name, salary, comm, (IFNULL(comm, 0) + salary) * 12 as YEARS
FROM teacher;

(2)在WHERE子句中使用表达式

-- 在WHERE子句中使用表达式
-- 查看年薪小于60000的讲师都有谁
SELECT name, salary, salary * 12
FROM teacher
WHERE salary * 12 < 60000;

-- 查询奖金小于3000的讲师
SELECT name, comm
FROM teacher
WHERE IFNULL(comm, 0) < 3000;

(3)别名

-- 为查询的字段起别名
SELECT name, salary, salary * 12 AS annual_salary
FROM teacher;

(4)练习:函数和表达式练习

-- 查询所有10岁学生的生日,按生日对应的年纪从大到小
SELECT name, age, birth
FROM student
WHERE age = 10
ORDER BY birth;

-- 查询8岁同学中名字含有"苗"的学生信息
SELECT name, age, gender
FROM student
WHERE age = 8
  AND name LIKE '%苗%';

-- 查询负责课程编号1和2号且工资高于6000的老师信息
SELECT *
FROM teacher
WHERE (subject_id = 1 OR subject_id = 2)
  AND salary > 6000;

-- 查询10岁以上的语文课代表和数学课代表
SELECT *
FROM student
WHERE age > 10
  AND (job = '语文课代表'
    OR job = '数学课代表');

-- 查询不教课程编号1的老师信息,按照工资降序排序
SELECT *
FROM teacher
WHERE subject_id NOT IN (1)
ORDER BY salary DESC;

-- 查询没有奖金的老师信息
SELECT *
FROM teacher
WHERE IFNULL(comm, 0) = 0;

-- 查询所有老师的奖金,并按照奖金降序排序
SELECT name,comm
FROM teacher
ORDER BY comm DESC ;

-- 查看工资高于8000的老师负责的课程编号
SELECT name,subject_id
FROM teacher
WHERE salary >8000;

-- 查看全校年龄最小学生的第6-10名
SELECT *
FROM student
ORDER BY age
LIMIT 5,5

2、聚合函数

(1)常用的聚合函数

  • AVG(): 用于计算指定列的平均值
  • SUM(): 用于计算指定列的总和
  • MIN(): 用于返回指定列的最小值
  • MAX(): 用于返回指定列的最大值
  • COUNT(): 用于返回指定列中的行数
-- 查看所有老师的平均工资
SELECT AVG(salary)
FROM teacher;

-- 查看老师的最高工资,最低工资,平均工资和工资总和
SELECT MAX(salary) AS `最高工资`,MIN(salary) `最低工资`,AVG(salary) `平均工资`,SUM(salary) `工资总和`
FROM teacher;

-- 查看课程编号是1的老师的平均工资是多少
SELECT AVG(salary) `平均工资`
FROM teacher
WHERE subject_id=1;

(2)聚合函数忽略NULL值

-- 计算老师的平均奖金
SELECT AVG(IFNULL(comm, 0)) `平均工资`
FROM teacher;

-- 查看负责课程编号2的老师共多少人
SELECT COUNT(*)
FROM teacher
WHERE subject_id=2;

-- 查看全校学生生日最大的是哪一天
SELECT MAX(birth)
FROM student;

-- 查看11岁的课代表共有多少人
SELECT COUNT(*)
FROM student
WHERE age = 11
  AND job LIKE '%课代表';

三、分组查询

1、分组聚合

GROUP BY子句是仅用于配合聚合函数的

  • 如果SELECT 中没有聚合函数,就不会使用GROUP BY
  • 在SELECT中出现了聚合函数,那么不在聚合函数的中的其他字段都应当出现在GROUP BY子句中

(1)GROUP BY子句

-- 按照课程编号进行分组,查看教师的平均工资
SELECT AVG(salary),subject_id
FROM teacher
GROUP BY subject_id;

-- 查看每个班各多少人
SELECT COUNT(*), class_id
FROM student
GROUP BY class_id;

-- 查看学校每种职位的学生各多少人,以及最大生日和最小生日
SELECT COUNT(*), job, MAX(birth), MIN(birth)
FROM student
GROUP BY job;

(2)按照多字段分组

-- 查看每个班每种职务多少人
SELECT COUNT(*), class_id, job
FROM student
GROUP BY class_id, job;

(3)按照聚合函数排序

-- 查看每个科目老师的平均工资,并由少到多展示
SELECT AVG(salary), subject_id
FROM teacher
GROUP BY subject_id
ORDER BY AVG(salary);

2、过滤分组结果

(1)HAVING子句

-- 查看各科目老师的平均工资,但是仅查看高于6000的那些科目老师的平均工资
-- WHERE子句不能使用聚合
SELECT AVG(salary) `avg` ,subject_id
from teacher
GROUP BY subject_id
HAVING avg>6000;

-- 查看科目老师的工资总和(前提是该科老师平均奖金高于4000)
SELECT SUM(salary), avg(ifnull(comm, 0)), subject_id
FROM teacher
GROUP BY subject_id
HAVING AVG(IFNULL(comm, 0)) > 4000;

(2)HAVING子句与WHERE子句

聚合结果过滤是不能使用 WHERE子句

将聚合函数放在WHERE中进行过滤会出现上述错误:WHERE子句中不能使用聚合函数。究其原因,WHERE与HAVING的过滤时机不同:

  • WHERE 关键字用于过滤从表中检索出来的记录:它可以根据一个或多个条件从表中选择出符合条件的记录,然后返回这些记录
  • HAVING 关键字用于过滤分组后的数据:它通常与 GROUP BY 关键字一起使用,用于对分组后的数据进行筛选,仅返回符合特定条件的分组

可以简单理解为:WHERE先进行过滤查询结果,用于确定结果集;HAVING后过滤,用于确定GOURP BY分组聚合以后的数据。

四、子查询

1、DQL使用子查询

(1)子查询概述

查询中嵌套查询

(2)在DQL中使用标量子查询

标量子查询,子查询的结果只返回一行一列的数据。

-- 查看哪个老师的工资高于王克晶的工资?查询思路如下:
-- 查看王克晶的工资是多少?
SELECT salary
FROM teacher
WHERE name = '王克晶';

-- 上一个查询结果是8000,查询工资大于8000的老师
SELECT name, salary
FROM teacher
WHERE salary > 8000;

-- 整合
SELECT name,salary
FROM teacher
WHERE salary>(SELECT salary FROM teacher WHERE name = '王克晶');

-- 查看高于平均工资的那些老师的工资都是多少?
SELECT salary
FROM teacher
WHERE salary>(SELECT AVG(salary) FROM teacher);

-- 查询和李费水同一班的学生
SELECT name, age, gender, class_id
FROM student
WHERE class_id = (SELECT class_id FROM student WHERE name = '李费水');

(3)使用多行单列子查询

  • \>ANY :大于子查询列表中的其中之一,大于最小的即可
  • <ANY :小于子查询列表中其中之一,小于最大的即可
  • \>ALL:大于子查询列表中所有的,大于最大的
  • <ALL:小于子查询列表中所有的,小于最小的
-- 查看与"祝雷"和"李费水"在同一个班的学生都有谁?
SELECT name,class_id
from student
where class_id in (select class_id from student where name in ('祝雷','李费水'));

-- 查看比教科目2和科目4老师工资都高的老师都有谁?
SELECT name
FROM teacher
WHERE salary > ALL (SELECT salary FROM teacher WHERE subject_id IN (2, 4));

2、DDL使用子查询

使用子查询创建表

子查询可以得到多行多列的值,这样的子查询结果可以用于建立新的表。

有需求如下:

  • 创建一张表用于记录老师工资的统计情况(按照科目)
  • 要记录每门课老师的最高工资,最低工资,平均工资和工资总和以及科目编号
  • 表名为teacher_salary_info
CREATE TABLE teacher_salary_info
AS
SELECT MAX(salary) `max`,
       MIN(salary) `min`,
       AVG(salary) `avg`,
       SUM(salary) `sum`,
       subject_id
FROM teacher
GROUP BY subject_id;

五、练习

1 数据库基础查询练习

针对业务案例库,进行如下查询:

-- 查看负责课程编号(subject_id)3和4的女老师都有谁?
SELECT name, gender, subject_id
FROM teacher
WHERE gender = '女'
  AND (subject_id = 3
    OR subject_id = 4);

-- 查看工资高于5600的老女师都有谁?
SELECT name, gender, salary
FROM teacher
WHERE gender = '女'
  AND salary > 5600;

-- 查看奖金高于3000的男老师或女老师的工资?
desc teacher;
SELECT name, gender, salary
FROM teacher
WHERE comm > 3000;

-- 查看所有10岁以下学生中的小队长和语文课代表都是谁?
SELECT name, age, job
FROM student
WHERE age < 10
  AND job IN ('小队长', '语文课代表');

-- 查看奖金在1000到4000之间的老师以及具体工资?
SELECT name, salary, comm
FROM teacher
WHERE comm BETWEEN 1000 AND 4000;

-- 查看工资在4000到8000之间的老师及具体工资?
SELECT name, salary, comm
FROM teacher
WHERE salary BETWEEN 4000 AND 8000;

-- 查看男老师负责的课程编号都有什么?
SELECT DISTINCT gender, subject_id
FROM teacher
WHERE gender = '男';

-- 查看所有男老师的职称和课程编号都是什么?
SELECT DISTINCT gender, title, subject_id
FROM teacher
WHERE gender = '男';

-- 查看10-20岁的女同学的职位都有哪些?
SELECT DISTINCT age, gender, job
FROM student
WHERE age BETWEEN 10 AND 20
  AND gender = '女';

-- 查看二级讲师和三级讲师的奖金(comm)和薪酬是多少?
SELECT DISTINCT title, comm, salary
FROM teacher
WHERE title IN ('二级讲师', '三级讲师');

-- 查看除了老板、总监、一级讲师的其他老师的工资是多少?
SELECT name, title, comm, salary
FROM teacher
WHERE title NOT IN ('老板', '总监', '一级讲师');

-- 查看没有奖金的老师都有谁和薪资是多少?
SELECT name, salary, comm
FROM teacher
WHERE comm = 0 OR comm IS NULL;

2 LIKE查询练习

针对业务案例库,进行如下查询:

-- 查询名字姓"李" 和姓"张"的学生姓名
SELECT name
FROM student
WHERE name LIKE '李%'
   OR name LIKE '张%';

-- 查询名字中包含"华"的学生姓名
SELECT name
FROM student
WHERE name LIKE '%华%';

-- 查询名字以"乐"结尾的学生姓名
SELECT name
FROM student
WHERE name LIKE '%乐';

-- 查询7岁里是"课代表"的学生信息
SELECT *
FROM student
WHERE age = 7
  AND job LIKE '%课代表';

-- 查询名字第二个字是"熊"的学生信息
SELECT *
FROM student
WHERE name LIKE '_熊_';

-- 查询姓"常"的队长都是谁?
SELECT name, job
FROM student
WHERE name LIKE '常%'
  AND job LIKE '%队长'

3 排序、分组和聚合查询练习

针对业务案例库,进行如下查询:

-- 查询所有老师薪资和奖金总和大于8000的,并且按照升序输出全部信息
SELECT *
FROM teacher
where salary + comm > 8000
ORDER BY salary + comm;

-- 查询8岁同学中名字含有"苗"的学生数量
SELECT COUNT(*) `学生数量`
FROM student
WHERE age = 8
  AND name LIKE '%苗%';

-- 查询负责课程编号1和2号且年龄大于35的老师信息
SELECT *
FROM teacher
WHERE (subject_id = 1 OR subject_id = 2)
  AND age > 35;

-- 查询10岁以上的课代表总数
SELECT COUNT(*) `总数`
FROM student
WHERE age > 10
  AND job LIKE '%课代表';

-- 查询不教课程编号1的老师信息,按照年龄降序排序
SELECT *
FROM teacher
WHERE subject_id NOT IN (1)
ORDER BY age DESC;

-- 查询没有奖金的老师数量
SELECT COUNT(*) `数量`
FROM teacher
WHERE IFNULL(comm, 0) = 0;

-- 查询所有课代表年龄,并按年龄降序排序
SELECT name, age, job
FROM student
WHERE job LIKE '%课代表'
ORDER BY age DESC;

-- 查看姓李的学生每个年龄段有多少人?
SELECT COUNT(*),name,age
FROM student
WHERE name LIKE '李%'
GROUP BY age;

4 排序、分组和聚合、子查询练习

针对业务案例库,进行如下查询:

-- 统计每个城市的学生数量
SELECT COUNT(*) `学生数量`, location_id
FROM student
GROUP BY location_id;

-- 统计每个组长管理的学生平均年龄
SELECT AVG(age) `平均年龄`, team_leader
FROM student
GROUP BY team_leader;

-- 统计每个城市中年龄最小和最大的学生
SELECT MIN(age) `年龄最小`, MAX(age) `年龄最大`, name, location_id
FROM student
GROUP BY location_id;

-- 统计每个班级中,职位为"班长"的学生数
SELECT COUNT(*), class_id
FROM student
WHERE job = '班长'
GROUP BY class_id;

-- 统计每个科目的老师人数及平均年龄,按照科目编号升序排序
SELECT COUNT(*) `人数`, AVG(age) `平均年龄`, subject_id
FROM teacher
GROUP BY subject_id
ORDER BY subject_id;

-- 统计每个性别的老师人数及其平均工资和奖金总额
SELECT COUNT(*), gender, AVG(salary), SUM(salary)
FROM teacher
GROUP BY gender;

-- 统计每个上司的管理老师人数及其平均工资,按照管理老师人数降序排序
SELECT COUNT(*),subject_id,AVG(salary)
FROM teacher
WHERE title NOT IN ('总监','老板')
GROUP BY subject_id;

-- 查询乐明所在班级的所有学生信息
SELECT *
FROM student
WHERE class_id = (SELECT class_id FROM student WHERE name = '乐明');
最后修改:2023 年 09 月 02 日
如果觉得我的文章对你有用,请随意赞赏