一、数据准备
# 创建数据库
create database sql50;
use sql50;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for Teacher
-- ----------------------------
DROP TABLE IF EXISTS `Teacher`;
CREATE TABLE `Teacher` (
`TId` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`Tname` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of Teacher
-- ----------------------------
INSERT INTO `Teacher` VALUES ('01', '张三');
INSERT INTO `Teacher` VALUES ('02', '李四');
INSERT INTO `Teacher` VALUES ('03', '王五');
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for Course
-- ----------------------------
DROP TABLE IF EXISTS `Course`;
CREATE TABLE `Course` (
`CId` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`Cname` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`TId` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of Course
-- ----------------------------
INSERT INTO `Course` VALUES ('01', '语文', '02');
INSERT INTO `Course` VALUES ('02', '数学', '01');
INSERT INTO `Course` VALUES ('03', '英语', '03');
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for Student
-- ----------------------------
DROP TABLE IF EXISTS `Student`;
CREATE TABLE `Student` (
`SId` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`Sname` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`Sage` datetime(0) NULL DEFAULT NULL,
`Ssex` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of Student
-- ----------------------------
INSERT INTO `Student` VALUES ('01', '赵雷', '1990-01-01 00:00:00', '男');
INSERT INTO `Student` VALUES ('02', '钱电', '1990-12-21 00:00:00', '男');
INSERT INTO `Student` VALUES ('03', '孙风', '1990-12-20 00:00:00', '男');
INSERT INTO `Student` VALUES ('04', '李云', '1990-12-06 00:00:00', '男');
INSERT INTO `Student` VALUES ('05', '周梅', '1991-12-01 00:00:00', '女');
INSERT INTO `Student` VALUES ('06', '吴兰', '1992-01-01 00:00:00', '女');
INSERT INTO `Student` VALUES ('07', '郑竹', '1989-01-01 00:00:00', '女');
INSERT INTO `Student` VALUES ('09', '张三', '2017-12-20 00:00:00', '女');
INSERT INTO `Student` VALUES ('10', '李四', '2017-12-25 00:00:00', '女');
INSERT INTO `Student` VALUES ('11', '李四', '2012-06-06 00:00:00', '女');
INSERT INTO `Student` VALUES ('12', '赵六', '2013-06-13 00:00:00', '女');
INSERT INTO `Student` VALUES ('13', '孙七', '2014-06-01 00:00:00', '女');
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for SC
-- ----------------------------
DROP TABLE IF EXISTS `SC`;
CREATE TABLE `SC` (
`SId` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`CId` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`score` decimal(18, 1) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of SC
-- ----------------------------
INSERT INTO `SC` VALUES ('01', '01', 80.0);
INSERT INTO `SC` VALUES ('01', '02', 90.0);
INSERT INTO `SC` VALUES ('01', '03', 99.0);
INSERT INTO `SC` VALUES ('02', '01', 70.0);
INSERT INTO `SC` VALUES ('02', '02', 60.0);
INSERT INTO `SC` VALUES ('02', '03', 80.0);
INSERT INTO `SC` VALUES ('03', '01', 80.0);
INSERT INTO `SC` VALUES ('03', '02', 80.0);
INSERT INTO `SC` VALUES ('03', '03', 80.0);
INSERT INTO `SC` VALUES ('04', '01', 50.0);
INSERT INTO `SC` VALUES ('04', '02', 30.0);
INSERT INTO `SC` VALUES ('04', '03', 20.0);
INSERT INTO `SC` VALUES ('05', '01', 76.0);
INSERT INTO `SC` VALUES ('05', '02', 87.0);
INSERT INTO `SC` VALUES ('06', '01', 31.0);
INSERT INTO `SC` VALUES ('06', '03', 34.0);
INSERT INTO `SC` VALUES ('07', '02', 89.0);
INSERT INTO `SC` VALUES ('07', '03', 98.0);
SET FOREIGN_KEY_CHECKS = 1;
二、SQL各种连接查询详解
2.1、交叉连接
-- 交叉连接(不带on子句,返回的是两表的乘积,也叫笛卡尔积)
# 隐式交叉连接 没有cross join
SELECT * from Student , Course WHERE CId = '03';
# 显式交叉连接 有cross join
SELECT * from Student CROSS JOIN Course WHERE CId = '03';
2.2、内连接
# 隐式的内连接,没有inner join,形成的中间表为两个表的笛卡尔积。
SELECT * FROM Student, SC WHERE Student.SId = SC.SId;
# 显示的内连接,一般称为内连接,有inner join,形成的中间表为两个表经过on条件过滤后的笛卡尔积。
SELECT * FROM Student INNER JOIN SC on Student.SId = SC.SId;
2.3、外连接
# 1、左外连接(left outer join) 左表全部数据+右表符合要求数据
SELECT Student.Sname , SC.score from Student LEFT JOIN SC on Student.SId = SC.SId;
# 2、右外连接(left outer join) 左表符合要求数据+右表全部数据
SELECT Student.Sname , SC.score from Student RIGHT JOIN SC on Student.SId = SC.SId;
# 3、全外连接(不重复全集)
# mysql是不支持全外的连接的,这里给出的写法适合oracle和db2。
SELECT Student.Sname , SC.score from Student RIGHT JOIN SC on Student.SId = SC.SId;
# 推荐在写连接查询的时候,on后面只跟连接条件,而对中间表限制的条件都写到where子句中。
SELECT Student.Sname , SC.score from Student LEFT JOIN SC on Student.SId = SC.SId WHERE SC.score>88.0;
两表连接查询选择方式的依据:
1、 查两表关联列相等的数据用内连接。
2、 col_l是col_r的子集时用右外连接。
3、 col_r是col_l的子集时用左外连接。
4、 col_r和col_l彼此有交集但彼此互不为子集时候用全外。
5、 求差操作的时候用联合查询。
三、备
四、sql 50 题
4.1. 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
# 左连接自交
select *
from Student as s
right join
(
select t1.SId, score_for_c01, score_for_c02
from (select SId, score as score_for_c01 from SC as sc where sc.CId = 01) as t1,
(select SId, score as score_for_c02 from SC as sc where sc.CId = 02) as t2
where t1.SId = t2.SId
and t1.score_for_c01 > t2.score_for_c02
) as r
on s.SId = r.SId;
# +---+-----+-------------------+----+---+-------------+-------------+
# |SId|Sname|Sage |Ssex|SId|score_for_c01|score_for_c02|
# +---+-----+-------------------+----+---+-------------+-------------+
# |02 |钱电 |1990-12-21 00:00:00|男 |02 |70.0 |60.0 |
# |04 |李云 |1990-12-06 00:00:00|男 |04 |50.0 |30.0 |
# +---+-----+-------------------+----+---+-------------+-------------+
4.2.查询同时存在"01"课程和"02"课程的情况
# 注意查找效率,每次生成的关系表越小越好
select t1.*, t2.CId, t2.score
from (select * from SC as sc where sc.CId = '01') as t1,
(select * from SC as sc where sc.CId = '02') as t2
where t1.SId = t2.SId;
# +---+---+-----+---+-----+
# |SId|CId|score|CId|score|
# +---+---+-----+---+-----+
# |01 |01 |80.0 |02 |90.0 |
# |02 |01 |70.0 |02 |60.0 |
# |03 |01 |80.0 |02 |80.0 |
# |04 |01 |50.0 |02 |30.0 |
# |05 |01 |76.0 |02 |87.0 |
# +---+---+-----+---+-----+
4.3.查询存在"01"课程但可能不存在"02"课程的情况(不存在时显示为null)
# 典型的外联结
select t1.*, t2.CId, t2.score
from (select * from SC as sc where sc.CId = '01') as t1
left join
(select * from SC as sc where sc.CId = '02') as t2
on t1.SId = t2.SId;
# +---+---+-----+----+-----+
# |SId|CId|score|CId |score|
# +---+---+-----+----+-----+
# |01 |01 |80.0 |02 |90.0 |
# |02 |01 |70.0 |02 |60.0 |
# |03 |01 |80.0 |02 |80.0 |
# |04 |01 |50.0 |02 |30.0 |
# |05 |01 |76.0 |02 |87.0 |
# |06 |01 |31.0 |NULL|NULL |
# +---+---+-----+----+-----+
4.4. 查询不存在"01"课程但存在"02"课程的情况
# 采用子查询(联结也可以,但本题子查询简单)
select *
from SC as sc
where sc.SId not in (
select SId
from SC as sc
where sc.CId = '01'
)
AND sc.CId = '02';
# +---+---+-----+
# |SId|CId|score|
# +---+---+-----+
# |07 |02 |89.0 |
# +---+---+-----+
4.5.查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
# 聚合函数分组和HAVING条件过滤,获得sid,最后与学生表联结
select s.SId, s.Sname, t.avg_score
from Student as s
inner join (select SId, avg(score) as avg_score
from SC
group by SId
having avg_score >= 60) as t
on s.SId = t.SId;
# +---+-----+---------+
# |SId|Sname|avg_score|
# +---+-----+---------+
# |01 |赵雷 |89.66667 |
# |02 |钱电 |70.00000 |
# |03 |孙风 |80.00000 |
# |05 |周梅 |81.50000 |
# |07 |郑竹 |93.50000 |
# +---+-----+---------+