数据库练习-多表联查

在这里插入图片描述

数据库练习-多表联查

1多表联查

查询所有学生的 name,以及该学生在 score 表中对应的 cnodegree

SELECT no, name FROM student;
+-----+-----------+
| no  | name      |
+-----+-----------+
| 101 | 曾华      |
| 102 | 匡明      |
| 103 | 王丽      |
| 104 | 李军      |
| 105 | 王芳      |
| 106 | 陆军      |
| 107 | 王尼玛    |
| 108 | 张全蛋    |
| 109 | 赵铁柱    |
+-----+-----------+

SELECT sno, cno, degree FROM score;
+------+-------+--------+
| s_no | c_no  | degree |
+------+-------+--------+
| 103  | 3-105 |     92 |
| 103  | 3-245 |     86 |
| 103  | 6-166 |     85 |
| 105  | 3-105 |     88 |
| 105  | 3-245 |     75 |
| 105  | 6-166 |     79 |
| 109  | 3-105 |     76 |
| 109  | 3-245 |     68 |
| 109  | 6-166 |     81 |
+------+-------+--------+

通过分析可以发现,只要把 score 表中的 sno 字段值替换成 student 表中对应的 name 字段值就可以了,如何做呢?

#	 select 要查询的字段1,要查询的字段2,要查询的字段3 from 这些字段从那个表查,这些字段从那个表查 where 根据那个表的字段进行筛选=根据那个表的字段进行筛选;
mysql> select sname,cno,degree from student,score where student.sno=score.sno;
+--------+-------+--------+
| sname  | cno   | degree |
+--------+-------+--------+
| 王丽   | 3-105 | 92     |
| 王丽   | 3-245 | 86     |
| 王丽   | 6-166 | 85     |
| 王芳   | 3-105 | 88     |
| 王芳   | 3-245 | 75     |
| 王芳   | 6-166 | 79     |
| 赵铁柱 | 3-105 | 76     |
| 赵铁柱 | 3-245 | 68     |
| 赵铁柱 | 6-166 | 81     |
+--------+-------+--------+
9 rows in set (0.08 sec)

查询所有学生的 sno 、课程名称 ( course 表中的 name ) 和成绩 ( score 表中的 degree ) 列。

mysql> select sname,cname,degree from student,score,course where student.sno=score.sno and score.cno=course.cno;
+--------+------------+--------+
| sname  | cname      | degree |
+--------+------------+--------+
| 王丽   | 计算机导论 | 92     |
| 王丽   | 操作系统   | 86     |
| 王丽   | 数字电路   | 85     |
| 王芳   | 计算机导论 | 88     |
| 王芳   | 操作系统   | 75     |
| 王芳   | 数字电路   | 79     |
| 赵铁柱 | 计算机导论 | 76     |
| 赵铁柱 | 操作系统   | 68     |
| 赵铁柱 | 数字电路   | 81     |
+--------+------------+--------+
9 rows in set (0.10 sec)
2子查询加分组求平均分

查询 95031 班学生每门课程的平均成绩。

score 表中根据 student 表的学生编号筛选出学生的课堂号和成绩:

-- IN (..): 将筛选出的学生号当做 sno 的条件查询
SELECT sno, c_no, degree FROM score
WHERE sno IN (SELECT no FROM student WHERE class = '95031');
+------+-------+--------+
| sno | cno  | degree |
+------+-------+--------+
| 105  | 3-105 |     88 |
| 105  | 3-245 |     75 |
| 105  | 6-166 |     79 |
| 109  | 3-105 |     76 |
| 109  | 3-245 |     68 |
| 109  | 6-166 |     81 |
+------+-------+--------+

这时只要将 cno 分组一下就能得出 95031 班学生每门课的平均成绩:

SELECT c_no, AVG(degree) FROM score
WHERE s_no IN (SELECT no FROM student WHERE class = '95031')
GROUP BY c_no;
+-------+-------------+
| c_no  | AVG(degree) |
+-------+-------------+
| 3-105 |     82.0000 |
| 3-245 |     71.5000 |
| 6-166 |     80.0000 |
+-------+-------------+

3查询在 3-105 课程中,所有成绩高于 109 号同学的记录。

思路:先查询出3-105中109号同学的成绩,然后在根据查出来的结果去查询大于当前同学成绩的学生

#先查询出3-105中109号同学的成绩
mysql> select degree from score where sno='109' and cno='3-105';
+--------+
| degree |
+--------+
| 76     |
+--------+
1 row in set (0.06 sec)
#根据查出来的结果去查询大于当前同学成绩的学生
#注意:在嵌套查询时,整个sql语句只能有一个结束符-->分号
mysql>  select * from score where  degree>(select degree from score where sno='109' and cno='3-105') and cno='3-105';
+-----+-------+--------+
| sno | cno   | degree |
+-----+-------+--------+
| 103 | 3-105 | 92     |
| 105 | 3-105 | 88     |
+-----+-------+--------+
2 rows in set (0.06 sec)

4YEAR 函数与带 IN 关键字查询

查询所有和 101108 号学生同年出生的 nonamebirthday 列。

# 先查询出这两位同学的生日所在年份
#  使用year()函数可以直接选取年份
mysql> select year(sbirthday) from student where sno in('108','109');
+-----------------+
| year(sbirthday) |
+-----------------+
|            1975 |
|            1974 |
+-----------------+
2 rows in set (0.06 sec)
#根据查出来的年份作为条件去筛选 ,因为查出来的年份有两个,所以使用in关键字
mysql> select * from student where year(sbirthday) in ( select year(sbirthday) from student where sno in('108','109'));
+-----+--------+------+---------------------+--------+
| sno | sname  | ssex | sbirthday           | sclass |
+-----+--------+------+---------------------+--------+
| 102 | 匡明   | 男   | 1975-10-02 00:00:00 | 95031  |
| 105 | 王芳   | 女   | 1975-02-10 00:00:00 | 95031  |
| 106 | 陆军   | 男   | 1974-06-03 00:00:00 | 95031  |
| 108 | 张全蛋 | 男   | 1975-02-10 00:00:00 | 95031  |
| 109 | 赵铁柱 | 男   | 1974-06-03 00:00:00 | 95031  |
+-----+--------+------+---------------------+--------+
5 rows in set (0.10 sec)

5UNION 和 NOTIN 的使用

查询 计算机系电子工程系 中的不同职称的教师。

-- NOT: 代表逻辑非
SELECT * FROM teacher WHERE department = '计算机系' AND profession NOT IN (
    SELECT profession FROM teacher WHERE department = '电子工程系'
)
-- 合并两个集UNION
UNION
SELECT * FROM teacher WHERE department = '电子工程系' AND profession NOT IN (
    SELECT profession FROM teacher WHERE department = '计算机系'
);

6表示所有的 ALL

查询课程 3-105 且成绩高于 3-245score 表。

-- ALL: 符合SQL语句中的所有条件。
-- 也就是说,在 3-105 每一行成绩中,都要大于从 3-245 筛选出来全部行才算符合条件。
SELECT * FROM score WHERE cno = '3-105' AND degree > ALL(
    SELECT degree FROM score WHERE cno = '3-245'
);
+-----+-------+--------+
| sno | cno   | degree |
+-----+-------+--------+
| 103 | 3-105 | 92     |
| 105 | 3-105 | 88     |
+-----+-------+--------+
2 rows in set (0.09 sec)

7ANY 表示至少一个 - DESC ( 降序 )

查询课程 3-105 且成绩 至少 高于 3-245score 表。

SELECT * FROM score WHERE c_no = '3-105';
+------+-------+--------+    
| sno | cno  | degree |
+------+-------+--------+
| 101  | 3-105 |     90 |
| 102  | 3-105 |     91 |
| 103  | 3-105 |     92 |
| 104  | 3-105 |     89 |
| 105  | 3-105 |     88 |
| 109  | 3-105 |     76 |
+------+-------+--------+

SELECT * FROM score WHERE cno = '3-245';
+------+-------+--------+
| s_no | c_no  | degree |
+------+-------+--------+
| 103  | 3-245 |     86 |
| 105  | 3-245 |     75 |
| 109  | 3-245 |     68 |
+------+-------+--------+

-- ANY: 符合SQL语句中的任意条件。
-- 也就是说,在 3-105 成绩中,只要有一个大于从 3-245 筛选出来的任意行就符合条件,
-- 最后根据降序查询结果。
SELECT * FROM score WHERE cno = '3-105' AND degree > ANY(
    SELECT degree FROM score WHERE cno = '3-245'
) ORDER BY degree DESC;
+------+-------+--------+
| sno | cno  | degree |
+------+-------+--------+
| 103  | 3-105 |     92 |
| 102  | 3-105 |     91 |
| 101  | 3-105 |     90 |
| 104  | 3-105 |     89 |
| 105  | 3-105 |     88 |
| 109  | 3-105 |     76 |
+------+-------+--------+

8按等级查询

建立一个 grade 表代表学生的成绩等级,并插入数据:

CREATE TABLE grade (
    low INT(3),
    upp INT(3),
    grade char(1)
);

INSERT INTO grade VALUES (90, 100, 'A');
INSERT INTO grade VALUES (80, 89, 'B');
INSERT INTO grade VALUES (70, 79, 'C');
INSERT INTO grade VALUES (60, 69, 'D');
INSERT INTO grade VALUES (0, 59, 'E');

查询所有学生的 snocnograde 列。

思路是,使用区间 ( BETWEEN ) 查询,判断学生的成绩 ( degree ) 在 grade 表的 lowupp 之间。

#语句解释:两表联查,以成绩进行区间查询,当成绩在对应的区间的时候显示;
# select 查询的字段1,查询的字段2,查询的字段3 from 字段来自表1,字段来自表2 where 以成绩划分 between 区间条件1 and 区间条件2;
mysql> select sno,cno,grade from score,grade where degree between low and upp;
+-----+-------+-------+
| sno | cno   | grade |
+-----+-------+-------+
| 103 | 3-105 | A     |
| 103 | 3-245 | B     |
| 103 | 6-166 | B     |
| 105 | 3-105 | B     |
| 105 | 3-245 | C     |
| 105 | 6-166 | C     |
| 109 | 3-105 | C     |
| 109 | 3-245 | D     |
| 109 | 6-166 | B     |
+-----+-------+-------+
9 rows in set (0.06 sec)

9连接查询

sql的四种连接查询;

内连接 inner join 或者join 内联查询就是两张表中的的数据,通过某个字段有对应关系,查出相关记录数据

外连接

​ —>左连接 left join 或者 left outer join 完整显示左边的表,右边的表如果符合条件就显示,不符合则补 NULL

​ —>右连接 right join 或者 right outer join 完整显示右边的表 ,左边的表如果符合条件就显示,不符合则补 NULL

​ —>全外连接 full join 或者 full outer join 完全显示两张表的数据(mysql不支持)

连接查询数据准备

CREATE DATABASE testJoin;

CREATE TABLE person (
    id INT,
    name VARCHAR(20),
    cardId INT
);

CREATE TABLE card (
    id INT,
    name VARCHAR(20)
);

INSERT INTO card VALUES (1, '饭卡'), (2, '建行卡'), (3, '农行卡'), (4, '工商卡'), (5, '邮政卡');
SELECT * FROM card;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | 饭卡      |
|    2 | 建行卡    |
|    3 | 农行卡    |
|    4 | 工商卡    |
|    5 | 邮政卡    |
+------+-----------+

INSERT INTO person VALUES (1, '张三', 1), (2, '李四', 3), (3, '王五', 6);
SELECT * FROM person;
+------+--------+--------+
| id   | name   | cardId |
+------+--------+--------+
|    1 | 张三   |      1 |
|    2 | 李四   |      3 |
|    3 | 王五   |      6 |
+------+--------+--------+

分析两张表发现,person 表并没有为 cardId 字段设置一个在 card 表中对应的 id 外键。如果设置了的话,personcardId 字段值为 6 的行就插不进去,因为该 cardId 值在 card 表中并没有。

内连接

要查询这两张表中有关系的数据,可以使用 INNER JOIN ( 内连接 ) 将它们连接在一起。

-- INNER JOIN: 表示为内连接,将两张表拼接在一起。
-- on: 表示要执行某个条件。
-- 语句解释:SELECT * FROM 查询的表名1 INNER JOIN 查询的表名2 on 筛选条件;
SELECT * FROM person INNER JOIN card on person.cardId = card.id;
+------+--------+--------+------+-----------+
| id   | name   | cardId | id   | name      |
+------+--------+--------+------+-----------+
|    1 | 张三   |      1 |    1 | 饭卡      |
|    2 | 李四   |      3 |    3 | 农行卡    |
+------+--------+--------+------+-----------+

-- 将 INNER 关键字省略掉,结果也是一样的。
-- SELECT * FROM person JOIN card on person.cardId = card.id;

-- ------注意:card 的整张表被连接到了右边。

左外连接

完整显示左边的表 ( person ) ,右边的表如果符合条件就显示,不符合则补 NULL

-- LEFT JOIN 也叫做 LEFT OUTER JOIN,用这两种方式的查询结果是一样的。
mysql> select * from person left join card on person.cardid=card.id;
+----+------+--------+------+--------+
| id | name | cardId | id   | name   |
+----+------+--------+------+--------+
|  1 | 张三 |      1 |    1 | 饭卡   |
|  2 | 李四 |      3 |    3 | 农行卡 |
|  3 | 王五 |      6 | NULL | NULL   |
+----+------+--------+------+--------+
3 rows in set (0.07 sec)

右外链接

完整显示右边的表 ( card ) ,左边的表如果符合条件就显示,不符合则补 NULL

#-- right join 也叫做right outer join,用这两种方式的查询结果是一样的。

SELECT * FROM person RIGHT JOIN card on person.cardId = card.id;
+------+--------+--------+------+-----------+
| id   | name   | cardId | id   | name      |
+------+--------+--------+------+-----------+
|    1 | 张三   |      1 |    1 | 饭卡      |
|    2 | 李四   |      3 |    3 | 农行卡    |
| NULL | NULL   |   NULL |    2 | 建行卡    |
| NULL | NULL   |   NULL |    4 | 工商卡    |
| NULL | NULL   |   NULL |    5 | 邮政卡    |
+------+--------+--------+------+-----------+

全外连接

完全显示两张表的数据

-- MySQL 不支持这种语法的全外连接
-- SELECT * FROM person FULL JOIN card on person.cardId = card.id;
-- 出现错误:
-- ERROR 1054 (42S22): Unknown column 'person.cardId' in 'on clause'

-- MySQL全连接语法,使用 UNION 将两张表合并在一起。
SELECT * FROM person LEFT JOIN card on person.cardId = card.id
UNION
SELECT * FROM person RIGHT JOIN card on person.cardId = card.id;
+------+--------+--------+------+-----------+
| id   | name   | cardId | id   | name      |
+------+--------+--------+------+-----------+
|    1 | 张三   |      1 |    1 | 饭卡      |
|    2 | 李四   |      3 |    3 | 农行卡    |
|    3 | 王五   |      6 | NULL | NULL      |
| NULL | NULL   |   NULL |    2 | 建行卡    |
| NULL | NULL   |   NULL |    4 | 工商卡    |
| NULL | NULL   |   NULL |    5 | 邮政卡    |
+------+--------+--------+------+-----------+
发布了80 篇原创文章 · 获赞 12 · 访问量 3917

猜你喜欢

转载自blog.csdn.net/weixin_44036436/article/details/102637201
今日推荐