Mysql-SQL基础应用02 DQL-Select 多表连接

DQL-Select 多表连接

1.1连接方式

a.笛卡尔乘积

mysql> select * from a,b;

b.内连接

mysql> select * from a join b on a.id=b.aid;

c.外连接

mysql> select * from a left join b on a.id=b.aid;
mysql> select * from a right  join b on a.id=b.aid;
mysql> select * from a left join b on a.id=b.aid and  b.aid is null;

1.2 列子

1.2.1 前提条件

student :学生表
sno: 学号
sname:学生姓名
sage: 学生年龄
ssex: 学生性别
teacher :教师表
tno: 教师编号
tname:教师名字
course :课程表
cno: 课程编号
cname:课程名字
tno: 教师编号
score :成绩表
sno: 学号
cno: 课程编号
score:成绩
项目构建
mysql> create database school charset utf8mb4;

mysql> use school


mysql> source /root/school.sql
Database changed
Query OK, 0 rows affected (0.02 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 10 rows affected (0.03 sec)
Records: 10  Duplicates: 0  Warnings: 0

Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

Query OK, 17 rows affected (0.01 sec)
Records: 17  Duplicates: 0  Warnings: 0
############################/root/school.sql#############################
[root@oldboy ~]# cat school.sql 
CREATE DATABASE school CHARSET utf8;
USE school
CREATE TABLE student(
sno INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '学号',
sname VARCHAR(20) NOT NULL COMMENT '姓名',
sage TINYINT UNSIGNED  NOT NULL COMMENT '年龄',
ssex  ENUM('f','m') NOT NULL DEFAULT 'm' COMMENT '性别'
)ENGINE=INNODB CHARSET=utf8;

CREATE TABLE course(
cno INT NOT NULL PRIMARY KEY COMMENT '课程编号',
cname VARCHAR(20) NOT NULL COMMENT '课程名字',
tno INT NOT NULL  COMMENT '教师编号'
)ENGINE=INNODB CHARSET utf8;

CREATE TABLE sc (
sno INT NOT NULL COMMENT '学号',
cno INT NOT NULL COMMENT '课程编号',
score INT  NOT NULL DEFAULT 0 COMMENT '成绩'
)ENGINE=INNODB CHARSET=utf8;

CREATE TABLE teacher(
tno INT NOT NULL PRIMARY KEY COMMENT '教师编号',
tname VARCHAR(20) NOT NULL COMMENT '教师名字'
)ENGINE=INNODB CHARSET utf8;

INSERT INTO student(sno,sname,sage,ssex)
VALUES 
(1,'zhang3',18,'m'),
(2,'zhang4',18,'m'),
(3,'li4',18,'m'),
(4,'wang5',19,'f'),
(5,'zh4',18,'m'),
(6,'zhao4',18,'m'),
(7,'ma6',19,'f'),
(8,'oldboy',20,'m'),
(9,'oldgirl',20,'f'),
(10,'oldp',25,'m');

INSERT INTO teacher(tno,tname) VALUES
(101,'oldboy'),
(102,'hesw'),
(103,'oldguo'),
(104,'alex');

INSERT INTO course(cno,cname,tno)
VALUES
(1001,'linux',101),
(1002,'python',102),
(1003,'mysql',103),
(1004,'go',105);

INSERT INTO sc(sno,cno,score)
VALUES
(1,1001,80),
(1,1002,59),
(2,1002,90),
(2,1003,100),
(3,1001,99),
(3,1003,40),
(4,1001,79),
(4,1002,61),
(4,1003,99),
(5,1003,40),
(6,1001,89),
(6,1003,77),
(7,1001,67),
(7,1003,82),
(8,1001,70),
(9,1003,80),
(10,1003,96);

1.2.2 大显身手

#############################################################
 核心思路: 
	 1.找到所有相关表 
	 2.找到所有表之间的关联关系
	 3.罗列其他的查询条件
#############################################################

-- 统计下每个学生平均成绩 

-- a.分析题意,找出所有相关表 
student
sc

-- b. 找到以上表的直接或间接关联条件
student.sno
sc.sno

-- c. 列举你要查询的列条件 
student.sname  
sc.score 

-- d. 组合 

mysql> select student.sname,avg(sc.score) 
from student join sc on student.sno = sc.sno 
group by student.sno;


-- 练习 : 
-- 1.  每位学生学习的课程门数

SELECT student.sname,COUNT(sc.score)
FROM student JOIN sc  ON student.sno=sc.sno 
GROUP BY student.sno;


-- 2.  每位老师所教的课程门数

SELECT teacher.tname ,COUNT(course.cname)
FROM teacher JOIN course
ON teacher.tno=course.tno
GROUP BY teacher.tno;

-- 3.  每位老师所教的课程门数和名称

SELECT teacher.tname ,COUNT(course.cname),GROUP_CONCAT(course.cname)
FROM teacher JOIN course
ON teacher.tno=course.tno
GROUP BY teacher.tno;

-- 4.  每位学生学习的课程门数和名称
SELECT student.sname,COUNT(sc.score),GROUP_CONCAT(course.cname)
FROM student
JOIN sc 
ON student.sno=sc.sno
JOIN course
ON sc.cno=course.cno
GROUP BY student.sno;




-- 多表SQL练习题
-- 1. 统计zhang3,学习了几门课

SELECT student.sname ,COUNT(*) 
FROM student 
JOIN sc 
ON student.sno=sc.sno
WHERE student.sname='zhang3';

-- 2. 查询zhang3,学习的课程名称有哪些?

SELECT student.sname ,GROUP_CONCAT(course.cname)
FROM student 
JOIN sc 
ON student.sno=sc.sno
JOIN course
ON sc.cno=course.cno
WHERE student.sname='zhang3'
GROUP BY student.sname

-- 3. 查询oldguo老师教的学生名.
SELECT teacher.tname,GROUP_CONCAT(student.sname)
FROM teacher
JOIN course
ON teacher.tno=course.tno
JOIN sc 
ON course.cno=sc.cno
JOIN student
ON sc.sno=student.sno
WHERE teacher.tname='oldguo'
GROUP BY teacher.tno

-- 4. 查询oldguo所教课程的平均分数

SELECT teacher.tname,AVG(sc.score) 
FROM teacher 
JOIN course
ON teacher.tno=course.tno
JOIN sc 
ON course.cno=sc.cno
WHERE teacher.tname='oldguo'
GROUP BY teacher.tno;

-- 5. 每位老师所教课程的平均分,并按平均分排序

SELECT teacher.tname,course.cname,AVG(sc.score) 
FROM teacher 
JOIN course
ON teacher.tno=course.tno
JOIN sc 
ON course.cno=sc.cno
GROUP BY teacher.tno , course.cno
ORDER BY AVG(sc.score) DESC;


-- 6. 查询oldguo所教的不及格的学生姓名
SELECT teacher.tname,GROUP_CONCAT(student.sname)
FROM teacher
JOIN course
ON teacher.tno=course.tno
JOIN sc 
ON course.cno=sc.cno
JOIN student
ON sc.sno=student.sno
WHERE teacher.tname='oldguo' AND sc.score<60
GROUP BY teacher.tno


-- 7. 查询所有老师所教学生不及格的信息
SELECT teacher.tname,GROUP_CONCAT(student.sname)
FROM teacher
JOIN course
ON teacher.tno=course.tno
JOIN sc 
ON course.cno=sc.cno
JOIN student
ON sc.sno=student.sno
WHERE  sc.score<60
GROUP BY teacher.tno

-- 8. 查询平均成绩大于60分的同学的学号和平均成绩;
SELECT student.sno,student.sname,AVG(sc.score)
FROM student
JOIN sc 
ON student.sno=sc.sno
GROUP BY student.sno
HAVING AVG(sc.score)>60

-- 9. 查询所有同学的学号、姓名、选课数、总成绩;
SELECT student.sno ,student.sname,COUNT(*),SUM(sc.score)
FROM student 
JOIN sc 
ON student.sno=sc.sno
JOIN course
ON sc.cno=course.cno
GROUP BY student.sno

-- 10.查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分 

SELECT course.cno,MAX(sc.score),MIN(sc.score)
FROM course
JOIN sc
ON course.cno=sc.cno
GROUP BY course.cno;

-- 11.查询每门课程被选修的学生数
SELECT course.cname,COUNT(sc.sno)
FROM course
JOIN sc 
ON course.cno=sc.cno
GROUP BY course.cno 

-- 12.查询出只选修了一门课程的全部学生的学号和姓名
SELECT course.cname,GROUP_CONCAT(CONCAT(student.sno,":",student.sname))
FROM course 
JOIN sc
ON course.cno=sc.cno 
JOIN student
ON sc.sno=student.sno
GROUP BY course.cno

-- 13.查询选修课程门数超过1门的学生信息
SELECT student.sname,COUNT(*)
FROM student
JOIN sc
ON student.sno=sc.sno
GROUP BY student.sno
HAVING COUNT(*)>1

-- 14.查询平均成绩大于85的所有学生的学号、姓名和平均成绩 
SELECT student.sno,student.sname,AVG(sc.score)
FROM student
JOIN sc 
ON student.sno=sc.sno
GROUP BY student.sno
HAVING AVG(sc.score)>85
-- 15.统计各位老师,所教课程的及格率

SELECT teacher.tname,COUNT(CASE  WHEN sc.score>=60 THEN 1 END)/COUNT(*)
FROM teacher
JOIN course
ON teacher.tno=course.tno
JOIN sc
ON course.cno=sc.cno
GROUP BY teacher.tno

-- 16.统计每门课程:优秀(85分以上),良好(70-85),一般(60-70),不及格(小于60)的学生列表

SELECT 
course.cname,
GROUP_CONCAT(CASE WHEN sc.score>=85  THEN student.sname END) AS 优秀,
GROUP_CONCAT(CASE WHEN sc.score>=70 AND sc.score<85  THEN student.sname END) AS 良好,
GROUP_CONCAT(CASE WHEN sc.score>=60 AND sc.score<70  THEN student.sname END) AS 一般,
GROUP_CONCAT(CASE WHEN sc.score<60  THEN student.sname END) AS 差
FROM course
JOIN sc 
ON course.cno=sc.cno
JOIN student
ON sc.sno=student.sno
GROUP BY course.cno

2.元数据获取

2.1 show

mysql> show databases;
mysql> show tables;
mysql> show privileges;
mysql> show grants for root@'localhost';
mysql> show create database  school;
mysql> show charset ;
mysql> show collation;
mysql> show variables like '%char%';
mysql> show status like '%binglog%'
mysql> show processlist;
mysql> show index from school.student;
mysql> show engines;
mysql> show binlog events ;
mysql> show master status ;
mysql> show slave status ;
mysql> show slave hosts;
mysql> show plugins;
mysql> show engine innodb status ;
mysql> show relaylog events;
mysql> show open tables;

3 information_schema

3.1.1介绍

视图. 查询元数据的方法

3.2.1 tables视图介绍

TABLE_SCHEMA 表所在库
TABLE_NAME 表名
ENGINE 存储引擎
TABLE_ROWS 表的行数(粗略统计)
AVG_ROW_LENGTH 平均行长度(粗略统计)
INDEX_LENGTH 索引长度(粗略统计)
DATA_FREE 碎片数
TABLE_COMMENT 表注释

3.2.2 tables视图应用例子:

1. 统计所有库,对应的表个数和名字列表
mysql> select table_schema,count(*),group_concat(table_name)
    -> from information_schema.tables
    -> group by table_schema;
| world              |        3 | countrylanguage,country,city 
2. 统计每个库的数据量大小
mysql> select table_schema,sum(table_rows*avg_row_length+index_length)/1024
    -> from information_schema.tables
    -> group by table_schema;
+--------------------+--------------------------------------------------+
| table_schema       | sum(table_rows*avg_row_length+index_length)/1024 |
+--------------------+--------------------------------------------------+
| information_schema |                                             NULL |
| mysql              |                                        2338.7188 |
| performance_schema |                                           0.0000 |
| school             |                                          63.9834 |
| sys                |                                          15.9961 |
| test               |                                          16.0000 |
| world              |                                         781.9990 |
+--------------------+--------------------------------------------------+

3. 拼接语句 
a. 查询一下业务数据库中,非InnoDB的表
mysql> SELECT  table_schema , table_name ,engine FROM information_schema.tables 
    -> WHERE 
    -> table_schema NOT IN ('mysql','sys','information_schema','performance_schema') 
    -> AND ENGINE <>'innodb';   
b.将非InnoDB表批量替换为InnoDB
SELECT  concat("alter table ",table_schema,".",table_name," engine=innodb;") FROM information_schema.tables 
WHERE 
table_schema NOT IN ('mysql','sys','information_schema','performance_schema','world') 
AND ENGINE <>'innodb' into outfile '/tmp/alter.sql' ;
mysqldump -uroot -p123 world city >/databak/world_city.sql

SELECT  concat("mysqldump -uroot -p123 ",table_schema," ",table_name," >/databak/",table_schema,"_",table_name,".sql") FROM information_schema.tables 
WHERE 
table_schema NOT IN ('mysql','sys','information_schema','performance_schema') into outfile '/tmp/bak.sh' ;

3.2.3 columns

TABLE_SCHEMA
TABLE_NAME
COLUMN_NAME
DATA_TYPE
COLUMN_KEY
COLUMN_COMMENT
select table_schema,table_name ,column_name from information_schema.columns
where table_schema NOT IN ('mysql','sys','information_schema','performance_schema');
posted @ 2021-05-14 12:20  断尽的记忆  阅读(124)  评论(0编辑  收藏  举报