作者写这篇博客的目的是为了记录一些心得体会,不会之处多担待

这里我不想赘述集合除法是什么,直接引述集合除法的实现和对实现集合除法过程的理解

我这里通过一个例子进行解释

现在我有一个存储学生信息的表格 如下图

mysql 数值除以_mysql 数值除以

# 创建学生的表格
create table Stu(
	SNO char(4) primary key not null, -- 学号 
	SNAME char(8) not null, -- 姓名 
	SEX tinyint, -- 性别 对这题实际上没用
	MNO char(2), -- 对应专业的编号 如软件工程的编号01 对这题实际上没用
	BIRDATE datetime, -- 出生日期 对这题实际上没用
	MEMO text -- 评论 对这题实际上没用
);

#学生信息的插入部分
insert into stu(sno,sname,sex,mno,birdate,memo,email) values
('S001','张三',1,'01','2001-10-01 00:00:00','二年级,荣获学院三好学生','1234@1234.com'),
('S002','李四',0,'02','2001-05-13 00:00:00',NULL,'1234@1234.com'),
('S003','李芳',0,'01','2000-05-11 00:00:00',NULL,'1234@1234.com'),
('S004','张明',1,'02','2002-05-31 00:00:00','一年级,荣获优秀学生干部','1234@1234.com'),
('S005','张强',1,'02','2001-06-01 00:00:00',NULL,'1234@1234.com'),
('S006','吴玲',0,'02','2000-06-11 00:00:00',NULL,'1234@1234.com'),
('S007','郑奇',1,'01','2000-06-11 00:00:00',NULL,'1234@1234.com'),
('S008','吴丽丽',0,'03','2002-06-17 00:00:00',NULL,'1234@1234.com'),
('S009','林森',1,'03','2003-01-10 00:00:00',NULL,'1234@1234.com'),
('S010','徐小宜',1,'04','2003-05-11 00:00:00',NULL,'1234@1234.com');

有一个记录课程的表

mysql 数值除以_数据库_02

创建cou表的sql语句

create table Cou(
	CNO char(4) primary key not null, -- 课程编号 如:C001
	CNAME varchar(20) not null, -- 课程的名称 如:软件工程
	CREDIT smallint, -- 学分 实际没有用
	PTIME char(5), -- 学时 实际没有用
	TEACHER char(10) -- 教师 这个很有用
);

insert into cou(cno,cname,credit,ptime,teacher) values
('C001','高等数学',8,'1','孙老师'),
('C002','C语言',5,'2','张老师'),
('C003','数据结构',4,'3','张老师'),
('C004','操作系统',3,'4','罗老师'),
('C005','组成原理',4,'3','陈老师'),
('C006','高等数学',3,'5','吴老师'),
('C007','JAVA程序设计',3,'3','李老师');
select *from cou;

有一个记录学生选课的表

mysql 数值除以_mysql_03

 

 

对应的SQL语句

create table Sc(
	SNO char(4) not null, -- 学生的学号
	CNO char(4) not null, -- 课程的编号
	GRADE decimal(4,1), -- 学生在该课程的得分 实际没有用
	primary key(SNO,CNO)
);

insert into sc(sno,cno,grade) values
('S001','C001',68.6),
('S001','C002',95.5),
('S001','C003',74.5),
('S002','C001',70),
('S002','C002',86.1),
('S003','C001',89.3),
('S003','C005',78.8),
('S003','C006',67.6),
('S004','C002',67.6),
('S004','C004',50.2),
('S005','C002',80.9);

至于我为什么要写那么多的没用的 因为懒 有现成的 哈哈哈哈哈哈哈哈哈 

现在我们题目的要求是这样的,从学生这张表中选出至少选修了张老师所有课程的学生

也就是说某个学生一旦选修了如下所有课程 那么我们认为这位学生满足我们的要求

mysql 数值除以_软件工程_04

1.取巧的集合除法实现:

题目的要求是选出所有至少选修了张老师所有课程的学生,那么我们先选出张老师的所有课程再说

select * from cou where teacher='张老师';

mysql 数值除以_sql_05

 

我们再看看有多少学生有选修张老师的课程(注意:我们这里只是有选修,而不是选修了全部)

select * from sc where sc.cno in
(select cno from cou where teacher='张老师');

  

mysql 数值除以_软件工程_06

 

 

 

那么直观的理解上看 如果我有选修了张老师的科目,并且我选修张老师的科目数与张老师所教授的课程数一致 那么我就是选修了张老师的所有科目。(当然 这是建立在数据正确的情况 即不存在我连续选修了张老师同一课程这一种情况)

select sno from  -- 选中学号

	(select * from sc where sc.cno in (select cno from cou where teacher='张老师')) a 
    -- 有选修张老师课程的表

group by sno -- 以学号为分组条件 分学号计算不同学号选修张老师的课程数

having count(a.cno)=(select count(cno) from cou where teacher='张老师'); 
-- 判断条件为选修张老师的科目数与张老师所教授的课程数一致

mysql 数值除以_sql_07

 

2.我所理解的集合除法:

上边的方法是先找选修了张老师科目的学生 然后统计个数找到答案

而下面的方法有点反着来

我们先找没有选修张老师科目的学生,然后从学生中剔除这些学生

(⊙﹏⊙) 这怎么做到“找出所有没有选修张老师科目的学生” 我是这么理解:

从特殊到一般:

先取一个具体的学生,如果这个学生有某个张老师的科目没有选修,那么这个学生满足我们的要求,抽出来保留在我们的剔除名里

如:我们取S001,S002这两名学生举例

select cno from cou where teacher='张老师'
-- 选出张老师的课程
and -- 并且
-- 选出S001这名学生缺的张老师课程
cno not in (select cno from sc where sc.sno='S001');

输出的结果

mysql 数值除以_数据库_08

这说明S001这名学生选修的课程中没有缺失张老师的任意一节课,即S001这名学生选修了张老师所有的课程 那么这么学生不保留在我们的剔除名单里

对于S002 来说

select cno from cou where teacher='张老师'
-- 选出张老师的课程
and -- 并且
-- 选出S002这名学生缺的张老师课程
cno not in (select cno from sc where sc.sno='S002');

输出的结果

mysql 数值除以_sql_09

S003这名学生并没有选修了张老师所有的课程 那么这么学生就应当保留在我们的剔除名单里

从一般的角度来看:

如果我们能让上面的SQL语句中的 sc.sno部分依次等于学生表中的sno 并将满足条件的sno保留在我们的剔除名单里,那么我们的剔除名单就完成了

mysql 数值除以_软件工程_10

 那么我们必须要有的几个模块

1.    select sno from stu  这个模块是依次引用学生表中的学号 

2.  where exists 这个是链接上下两个模块的

3. 这个模块是为了判断当前的stu.sno是否有少选修张老师的科目

select cno from cou where teacher='张老师'
and 
cno not in (select cno from sc where sc.sno=stu.sno);

 总的来看 (以下就是剔除名单)

select sno from stu 
where exists 
(select cno from cou where teacher='张老师'
and 
cno not in (select cno from sc where sc.sno=stu.sno));

mysql 数值除以_sql_11

 

解释一下过程:(我个人的理解)

假如从stu表中取出的sno为’S001‘ 此时

select cno from cou where teacher='张老师'
and 
cno not in (select cno from sc where sc.sno='S001')

由于上面的结果是空集

mysql 数值除以_mysql 数值除以_12

(也就是说上面的查询为空),那么此时的

查询可以理解为 

尝试取出 'S001' where exists '空'--------》

尝试取出 'S001' where false -----》

从stu取出的'S001不满足条件,所有最终的剔除名单里没有S001

假如从stu表中取出的sno为’S002‘ 此时

 select cno from cou where teacher='张老师'
and 
cno not in (select cno from sc where sc.sno='S002')

由于上面的结果不是空集

mysql 数值除以_mysql 数值除以_13

 那么此时可以理解为

尝试取出 'S002' where exists '集合非空'--------》

尝试取出 'S002' where true -----》

从stu取出的'S002满足条件,所有最终的剔除名单里就有S002

但此时我们得到的只是剔除名单 我们要的不是剔除名单啊!!!

简单的做法是

select sno from stu where
not exists  -- 这里加个not 就可以了
(select cno from cou where teacher='张老师'
and 
cno not in (select cno from sc where sc.sno=stu.sno));

复杂一点 但是跟我们的初始想法一致

select sno from stu -- 从学生表出发
where sno not in -- 查找学号不在剔除名单里的

-- 学生剔除名单
(select sno from stu where
    exists 
(select cno from cou where teacher='张老师'
and 
cno not in (select cno from sc where sc.sno=stu.sno)));

mysql 数值除以_mysql_14

 

 以上就是方某对于集合除法过程(以上例题)的理解 如有更好的解释方法 欢迎欢迎