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.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');