数据库-表查询进阶

查询进阶


同结构不同表查询插入

  • 给定两个相同结构表,内容可以由查询功能插入
  • insert into student2 select * from student1;
-- 创建表1
mysql> create table student1(id int,name varchar(10));
Query OK, 0 rows affected (0.05 sec)

-- 创建表2
mysql>  create table student2(id int,name varchar(10));
Query OK, 0 rows affected (0.04 sec)

-- 在表1中插入数据
mysql>  insert into student1 values(1,"zhangsan"),(2,"lisi"),(3,"wangwu");
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

-- 查看表1数据
mysql> select * from student1;
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangsan |
|    2 | lisi     |
|    3 | wangwu   |
+------+----------+
3 rows in set (0.00 sec)

-- 写法->:直接以查询结果插入表2
mysql> insert into student2 select * from student1;
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

-- 查看表2数据
mysql> select * from student2;
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangsan |
|    2 | lisi     |
|    3 | wangwu   |
+------+----------+
3 rows in set (0.00 sec)

聚合查询

聚合函数

  • 行与行之间需要运算,可以使用sql提供的函数;
函数说明
count([distinct] expr)返回查询到的数据的数量(DISTINCT 表示去重统计)
sum([distinct] expr)返回查询到的数据的 总和,不是数字没有意义
avg([distinct] expr)返回查询到的数据的 平均值,不是数字没有意义
max([distinct] expr)返回查询到的数据的 最大值,不是数字没有意义
min([distinct] expr)返回查询到的数据的 最小值,不是数字没有意义
  • DISTINCT 为可选参数,表示对数据进行去重后再执行聚合操作。
  1. 给出成绩表举例
mysql>  select * from exam_result;
+---------+---------+------+---------+
| name    | chinese | math | english |
+---------+---------+------+---------+
| 学生1   |    67.0 | 98.0 |    56.0 |
| 学生2   |    87.5 | 78.0 |    77.0 |
| 学生3   |    88.5 | 98.0 |    90.0 |
| 学生4   |    55.5 | 85.0 |    45.0 |
| NULL    |    NULL | NULL |    NULL |
+---------+---------+------+---------+
5 rows in set (0.00 sec)
  2.select count(*)...
  • 先执行select*再进行count统计

  • select count(name)…先查询name再统计name有多少行

  • (distinct name)会进行名字去重

  • *号会统计null值 而 单列不计算null值

  • count() 括号要紧紧挨着count 不能有空格

-- 写法->count(*)计算null值
mysql>  select count(*) from exam_result;
+----------+
| count(*) |
+----------+
|        5 |
+----------+
1 row in set (0.00 sec)

-- 写法->count(name)不计算null值
mysql> select count(name) from exam_result;
+-------------+
| count(name) |
+-------------+
|           4 |
+-------------+
1 row in set (0.01 sec)
3 select sum(*)...
  • null 不会去参与计算
  • sql会将数据转换成double类型计算,数字字符串也可以被转换,非数字字符串将转换失败
-- 写法->:语文列成绩相加
mysql> select sum(chinese) from exam_result;
+--------------+
| sum(chinese) |
+--------------+
|        298.5 |
+--------------+
1 row in set (0.00 sec)


-- 写法->:先将列数据相加,再去将行相加
mysql> select sum(chinese + math + english) from exam_result;
+-------------------------------+
| sum(chinese + math + english) |
+-------------------------------+
|                         925.5 |
+-------------------------------+
1 row in set (0.00 sec)
4 select avg(chinese)... -- 和sum同理
-- 写法-> 平均值:
mysql> select avg(chinese) from exam_result;
+--------------+
| avg(chinese) |
+--------------+
|     74.62500 |
+--------------+
5 select max(chinese)...  -- 和sum同理
-- 写法-> 最大值:
mysql>  select max(chinese) from exam_result;
+--------------+
| max(chinese) |
+--------------+
|         88.5 |
+--------------+
1 row in set (0.00 sec)
6 select min(chinese)... -- 和sum同理
-- 写法-> 最小值:
mysql>  select min(chinese) from exam_result;
+--------------+
| min(chinese) |
+--------------+
|         55.5 |
+--------------+
1 row in set (0.00 sec)

group by

  • 假设给出一张员工薪资表
-- 创建表
mysql> create table company(id int primary key auto_increment, 
name varchar(20),role varchar(20),salary int);

-- 插入后查看表
mysql> select * from company;
+----+--------+-----------+--------+
| id | name   | role      | salary |
+----+--------+-----------+--------+
|  1 | 张三   | 程序员    |  10000 |
|  2 | 李四   | 程序员    |  12000 |
|  3 | 王五   | 设计师    |   8000 |
|  4 | 赵六   | 设计师    |   8500 |
|  5 | 田七   | 设计师    |   9000 |
|  6 | 老八   | 老板      | 100000 |
+----+--------+-----------+--------+
6 rows in set (0.00 sec)

1.平均值的分组计算

-- 写法-> 所有人的平均值:
mysql>  select avg(salary) from company;
+-------------+
| avg(salary) |
+-------------+
|  24583.3333 |
+-------------+
1 row in set (0.00 sec)
  • 如果直接进行平均值计算,乍一看平均薪资竟然有两万多,显然这不合理;所以平均值需要进行分组计算
    select role, avg(salary) from company group by role;
  • group by role 根据role来分组
-- 写法->分组平均值:
mysql> select role, avg(salary) from company group by role;
+-----------+-------------+
| role      | avg(salary) |
+-----------+-------------+
| 程序员    |  11000.0000 |
| 老板      | 100000.0000 |
| 设计师    |   8500.0000 |
+-----------+-------------+
3 rows in set (0.00 sec)
  • 可以在分组之增加条件
-- 写法->:先排除张三,再分组查询
mysql> select role ,avg(salary) from company where name != "张三" group by role;
+-----------+-------------+
| role      | avg(salary) |
+-----------+-------------+
| 程序员    |  12000.0000 |
| 老板      | 100000.0000 |
| 设计师    |   8500.0000 |
+-----------+-------------+
3 rows in set (0.01 sec)
  • 可以在分组之增加条件
  • having
-- 写法->:先分组,再筛选平均小于20000
mysql> select role,avg(salary) from company group  by role having avg(salary) < 20000;
+-----------+-------------+
| role      | avg(salary) |
+-----------+-------------+
| 程序员    |  11000.0000 |
| 设计师    |   8500.0000 |
+-----------+-------------+
2 rows in set (0.01 sec)

-- 写法->:having count(role) 就可以得到各职位的人数;
  • 当然,前后一起用也可以的

联合查询

笛卡尔积 “排列组合”

-- 给定班级表内容
mysql> select * from class;
+----+-----------------+
| id | name            |
+----+-----------------+
|  1 | 一年级一班      |
|  2 | 一年级二班      |
+----+-----------------+
3 rows in set (0.00 sec)

-- 给定学生表内容
mysql> select * from student;
+----+--------+---------+
| id | name   | classid |
+----+--------+---------+
|  1 | 张三   |       1 |
|  2 | 李四   |       2 |
|  3 | 王五   |       2 |
+----+--------+---------+
3 rows in set (0.00 sec)

-- 如果直接两表拼在一起,两表就会排列组合,把所有数据都组合一遍,
甚至生成一些无用的数据;因此我们应当过滤一些无意义数据;
mysql>  select * from class,student;
+----+-----------------+----+--------+---------+
| id | name            | id | name   | classid |
+----+-----------------+----+--------+---------+
|  1 | 一年级一班      |  1 | 张三   |       1 |
|  2 | 一年级二班      |  1 | 张三   |       1 |
|  1 | 一年级一班      |  2 | 李四   |       2 |
|  2 | 一年级二班      |  2 | 李四   |       2 |
|  1 | 一年级一班      |  3 | 王五   |       2 |
|  2 | 一年级二班      |  3 | 王五   |       2 |
+----+-----------------+----+--------+---------+
9 rows in set (0.00 sec)

-- 筛选两表合法内容

内部关联

  • where 表 . 列名 = 表 . 列名
-- 写法->:给定内部条件进行筛选
mysql> select * from class,student where 
class.id = student.classid;
+----+-----------------+----+--------+---------+
| id | name            | id | name   | classid |
+----+-----------------+----+--------+---------+
|  1 | 一年级一班      |  1 | 张三   |       1 |
|  2 | 一年级二班      |  2 | 李四   |       2 |
|  2 | 一年级二班      |  3 | 王五   |       2 |
+----+-----------------+----+--------+---------+
3 rows in set (0.00 sec)

-- 写法->:可以对列再进行精简
mysql> select class.name, student.id ,student.name 
from class,student where class.id = student.classid;
+-----------------+----+--------+
| name            | id | name   |
+-----------------+----+--------+
| 一年级一班      |  1 | 张三   |
| 一年级二班      |  2 | 李四   |
| 一年级二班      |  3 | 王五   |
+-----------------+----+--------+
3 rows in set (0.00 sec)
  • 内部关联还有一种写法,只是把连接两表的 , 换成了join / inner join,把where换成了on
    select class.name, student.id ,student.name from class join student on class.id = student.classid;

外部关联

  • 创建两个有一定关联的表,但是其中有特殊情况导致一些数据不存在关联
-- 学生表
mysql> select * from student;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 张三   |
|    2 | 李四   |
|    3 | 王五   |
+------+--------+
3 rows in set (0.00 sec)

-- 分数表
mysql> select * from score;
+------+-------+
| id   | score |
+------+-------+
|    1 |  90.0 |
|    2 |  78.0 |
|    4 |  64.0 |
+------+-------+
3 rows in set (0.00 sec)
  • 如果直接以内部关联的方式查询,查询不到无关联的数据
-- 以内部关联方式查询
mysql> select * from student inner join 
score on student.id = score.id;
+------+--------+------+-------+
| id   | name   | id   | score |
+------+--------+------+-------+
|    1 | 张三   |    1 |  90.0 |
|    2 | 李四   |    2 |  78.0 |
+------+--------+------+-------+
2 rows in set (0.00 sec)
  • 左外连接
    • 确保左表student能够被完全表示,外部关联的score表数据用null填充。
-- 写法->:left join
mysql> select * from student left join 
score on student.id = score.id;
+------+--------+------+-------+
| id   | name   | id   | score |
+------+--------+------+-------+
|    1 | 张三   |    1 |  90.0 |
|    2 | 李四   |    2 |  78.0 |
|    3 | 王五   | NULL |  NULL |
+------+--------+------+-------+
3 rows in set (0.00 sec)
  • 右外连接
    • 确保右表score能够被完全表示,外部关联的student表数据用null填充。
-- 写法->:right join
mysql>  select * from student right join 
score on student.id = score.id;
+------+--------+------+-------+
| id   | name   | id   | score |
+------+--------+------+-------+
|    1 | 张三   |    1 |  90.0 |
|    2 | 李四   |    2 |  78.0 |
| NULL | NULL   |    4 |  64.0 |
+------+--------+------+-------+
3 rows in set (0.00 sec)

自连接

  • 行与行之间的比较
  • 给出学生表和分数表
-- 学生表
mysql> select * from student;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 张三   |
|    2 | 李四   |
|    3 | 王五   |
+------+--------+
3 rows in set (0.00 sec)

-- 分数表
mysql> select * from score;
+------------+-------+--------+
| student_id | score | course |
+------------+-------+--------+
|          1 |  88.0 | 语文   |
|          1 |  97.0 | 数学   |
|          1 |  65.5 | 英语   |
|          2 |  77.0 | 语文   |
|          2 |  55.0 | 数学   |
|          2 |  67.5 | 英语   |
|          3 |  49.0 | 语文   |
|          3 |  80.0 | 数学   |
|          3 |  40.0 | 英语   |
+------------+-------+--------+
9 rows in set (0.00 sec)
  • 如果想要在行与行之间比较分数,需要自连接,将行转换成列的形式进行比较。
  • 自连接由于表名重复,需要使用别名
    select * from score as s1,score as s2;
mysql>  写法->:select * from score as s1,score as s2;
+------------+-------+--------+------------+-------+--------+
| student_id | score | course | student_id | score | course |
+------------+-------+--------+------------+-------+--------+
|          1 |  88.0 | 语文   |          1 |  88.0 | 语文   |
|          1 |  97.0 | 数学   |          1 |  88.0 | 语文   |
|          1 |  65.5 | 英语   |          1 |  88.0 | 语文   |
|          2 |  77.0 | 语文   |          1 |  88.0 | 语文   |
|          2 |  55.0 | 数学   |          1 |  88.0 | 语文   |
|          2 |  67.5 | 英语   |          1 |  88.0 | 语文   |
|          3 |  49.0 | 语文   |          1 |  88.0 | 语文   |
|          3 |  80.0 | 数学   |          1 |  88.0 | 语文   |
|          3 |  40.0 | 英语   |          1 |  88.0 | 语文   |
|          1 |  88.0 | 语文   |          1 |  97.0 | 数学   |
|          1 |  97.0 | 数学   |          1 |  97.0 | 数学   |
|          1 |  65.5 | 英语   |          1 |  97.0 | 数学   |
|          2 |  77.0 | 语文   |          1 |  97.0 | 数学   |
|          2 |  55.0 | 数学   |          1 |  97.0 | 数学   |
|          2 |  67.5 | 英语   |          1 |  97.0 | 数学   |
|          3 |  49.0 | 语文   |          1 |  97.0 | 数学   |
表太大简略了,共81
+------------+-------+--------+------------+-------+--------+
81 rows in set (0.01 sec)
  • 明显可见,在排列组合的过程中,就会存在可进行比较的不同学科出现在了同一行当中,进而转化成了列的比较。
  • 为了简化,不妨将同一个人的语文成绩和数学成绩进行比较
-- 查看同一个人的语文成绩和数学成绩
mysql> select * from score as s1,score as s2 where 
s1.student_id = s2.student_id 
and s1.course = '语文' 
and s2.course = '数学';
+------------+-------+--------+------------+-------+--------+
| student_id | score | course | student_id | score | course |
+------------+-------+--------+------------+-------+--------+
|          1 |  88.0 | 语文   |          1 |  97.0 | 数学   |
|          2 |  77.0 | 语文   |          2 |  55.0 | 数学   |
|          3 |  49.0 | 语文   |          3 |  80.0 | 数学   |
+------------+-------+--------+------------+-------+--------+
3 rows in set (0.00 sec)


-- 写法->:只看同一个人的语文和数学成绩,其中语文成绩比数学大的
mysql> select * from score as s1,score as s2 where 
s1.student_id = s2.student_id 
and s1.course = '语文' 
and s2.course = '数学' 
and s1.score >s2.score;
+------------+-------+--------+------------+-------+--------+
| student_id | score | course | student_id | score | course |
+------------+-------+--------+------------+-------+--------+
|          2 |  77.0 | 语文   |          2 |  55.0 | 数学   |
+------------+-------+--------+------------+-------+--------+
1 row in set (0.00 sec)


-- 写法->:进行列化简
mysql> select s1.student_id,s1.course,s1.score,
s2.course,s2.score 
from score as s1,score as s2 where 
s1.student_id = s2.student_id 
and s1.course = '语文' 
and s2.course = '数学' 
and s1.score >s2.score;
+------------+--------+-------+--------+-------+
| student_id | course | score | course | score |
+------------+--------+-------+--------+-------+
|          2 | 语文   |  77.0 | 数学   |  55.0 |
+------------+--------+-------+--------+-------+
1 row in set (0.00 sec)

子查询

  • 单行子查询:返回一行记录的子查询
-- 一个学生表
mysql> select * from student;
+------+--------+---------+
| id   | name   | classid |
+------+--------+---------+
|    1 | 张三   |       1 |
|    2 | 李四   |       1 |
|    3 | 王五   |       1 |
|    4 | 赵四   |       1 |
|    5 | 田七   |       2 |
|    6 | 周八   |       2 |
+------+--------+---------+
6 rows in set (0.00 sec)
  • 要想查询某一学生的同班学生有谁
-- 写法->:找出张三所在的班级
mysql> select classid from student where name = '张三';
+---------+
| classid |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)
-- 写法->:根据班级查询成员
mysql>  select * from student where classid = 1 and name != '张三';
+------+--------+---------+
| id   | name   | classid |
+------+--------+---------+
|    2 | 李四   |       1 |
|    3 | 王五   |       1 |
|    4 | 赵四   |       1 |
+------+--------+---------+
3 rows in set (0.00 sec)

3.合并1和2;将得到1的语句替换2中的1

-- 写法->: 替换1
mysql> select * from student where classid = 
( select classid from student where name = '张三') 
and name != '张三';
+------+--------+---------+
| id   | name   | classid |
+------+--------+---------+
|    2 | 李四   |       1 |
|    3 | 王五   |       1 |
|    4 | 赵四   |       1 |
+------+--------+---------+
3 rows in set (0.01 sec)
  • 多行子查询:
-- 给出3张表,分别记录学生,课程,分数;
mysql> select * from student;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 张三   |
|    2 | 李四   |
|    3 | 王五   |
|    4 | 赵四   |
|    5 | 田七   |
|    6 | 周八   |
+------+--------+
6 rows in set (0.00 sec)

mysql> select * from course;
+------+--------------------------+
| id   | courseName               |
+------+--------------------------+
|    1 | 计算机科学与技术         |
|    2 | 大学英语                 |
|    3 | 大学物理                 |
|    4 | 软件工程                 |
|    5 | 线性代数                 |
|    6 | 军事理论                 |
+------+--------------------------+
6 rows in set (0.00 sec)

mysql> select * from score;
+-----------+----------+-------+
| studentid | courseid | score |
+-----------+----------+-------+
|         1 |        1 |  88.0 |
|         1 |        2 |  70.0 |
|         1 |        5 |  78.0 |
|         2 |        1 |  68.0 |
|         2 |        2 |  54.0 |
|         2 |        5 |  90.0 |
|         3 |        2 |  68.0 |
|         3 |        3 |  54.0 |
|         3 |        4 |  90.0 |
|         4 |        4 |  68.0 |
|         4 |        5 |  54.0 |
|         4 |        6 |  90.0 |
|         5 |        3 |  49.0 |
|         5 |        5 |  54.0 |
|         5 |        2 |  60.0 |
|         6 |        1 |  49.0 |
|         6 |        6 |  74.0 |
|         6 |        2 |  88.0 |
+-----------+----------+-------+
18 rows in set (0.00 sec)
  • 现需要找出指定课程所有学生分数

做法一,联合查询
先找到对应课程id,再通过课程id找学生和分数

-- 找出大学英语和大学物理对应的id
mysql>  select id from course where courseName = '大学英语' 
or courseName = '大学物理';
+------+
| id   |
+------+
|    2 |
|    3 |
+------+
2 rows in set (0.00 sec)

-- 筛选得到对应学生 使用 -in()进行筛选
mysql>  select  studentid,courseid ,score from score where courseid in(2 , 3);
+-----------+----------+-------+
| studentid | courseid | score |
+-----------+----------+-------+
|         1 |        2 |  70.0 |
|         2 |        2 |  54.0 |
|         3 |        2 |  68.0 |
|         3 |        3 |  54.0 |
|         5 |        3 |  49.0 |
|         5 |        2 |  60.0 |
|         6 |        2 |  88.0 |
+-----------+----------+-------+
7 rows in set (0.01 sec)

做法二:将上方法进行套娃,替换 (2,3)

mysql> select  studentid,courseid ,score from score 
where courseid in
(select id from course where courseName = '大学英语' or courseName = '大学物理');
+-----------+----------+-------+
| studentid | courseid | score |
+-----------+----------+-------+
|         1 |        2 |  70.0 |
|         2 |        2 |  54.0 |
|         3 |        2 |  68.0 |
|         3 |        3 |  54.0 |
|         5 |        3 |  49.0 |
|         5 |        2 |  60.0 |
|         6 |        2 |  88.0 |
+-----------+----------+-------+
7 rows in set (0.00 sec)

合并查询

  • 为了合并多个select的执行结果,可以使用集合操作符 union,union all。
-- or的同一表下查询使用
mysql> select * from course where id < 3 or coursename = "军事理论";
+------+--------------------------+
| id   | courseName               |
+------+--------------------------+
|    1 | 计算机科学与技术         |
|    2 | 大学英语                 |
|    6 | 军事理论                 |
+------+--------------------------+
3 rows in set (0.00 sec)

-- ->写法:使用union表达式
mysql> select * from course where id < 3 union select * from course where coursename = "军事理论";
+------+--------------------------+
| id   | courseName               |
+------+--------------------------+
|    1 | 计算机科学与技术         |
|    2 | 大学英语                 |
|    6 | 军事理论                 |
+------+--------------------------+
3 rows in set (0.01 sec)
  • union允许多个表合并
  • 如果类型是相同的,可以合并,但列名取其一
  • 成功合并如果有相同行,则会进行去重!! union all不会去重
-- 相同类型合并
mysql> select * from course where id < 3 union select * from student where id < 4;
+------+--------------------------+
| id   | courseName               |
+------+--------------------------+
|    1 | 计算机科学与技术         |
|    2 | 大学英语                 |
|    1 | 张三                     |
|    2 | 李四                     |
|    3 | 王五                     |
+------+--------------------------+
5 rows in set (0.00 sec)
  • 如果类型不同,会报错
-- 不同类型合并
mysql>  select * from course where id < 3 union select * from score where studentid < 4;

ERROR 1222 (21000): The used SELECT statements have a different number of columns
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值