当前位置:   article > 正文

关于集合除法的理解(MySQL实现)_集合的除法

集合的除法

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

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

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

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

  1. # 创建学生的表格
  2. create table Stu(
  3. SNO char(4) primary key not null, -- 学号
  4. SNAME char(8) not null, -- 姓名
  5. SEX tinyint, -- 性别 对这题实际上没用
  6. MNO char(2), -- 对应专业的编号 如软件工程的编号01 对这题实际上没用
  7. BIRDATE datetime, -- 出生日期 对这题实际上没用
  8. MEMO text -- 评论 对这题实际上没用
  9. );
  10. #学生信息的插入部分
  11. insert into stu(sno,sname,sex,mno,birdate,memo,email) values
  12. ('S001','张三',1,'01','2001-10-01 00:00:00','二年级,荣获学院三好学生','1234@1234.com'),
  13. ('S002','李四',0,'02','2001-05-13 00:00:00',NULL,'1234@1234.com'),
  14. ('S003','李芳',0,'01','2000-05-11 00:00:00',NULL,'1234@1234.com'),
  15. ('S004','张明',1,'02','2002-05-31 00:00:00','一年级,荣获优秀学生干部','1234@1234.com'),
  16. ('S005','张强',1,'02','2001-06-01 00:00:00',NULL,'1234@1234.com'),
  17. ('S006','吴玲',0,'02','2000-06-11 00:00:00',NULL,'1234@1234.com'),
  18. ('S007','郑奇',1,'01','2000-06-11 00:00:00',NULL,'1234@1234.com'),
  19. ('S008','吴丽丽',0,'03','2002-06-17 00:00:00',NULL,'1234@1234.com'),
  20. ('S009','林森',1,'03','2003-01-10 00:00:00',NULL,'1234@1234.com'),
  21. ('S010','徐小宜',1,'04','2003-05-11 00:00:00',NULL,'1234@1234.com');

有一个记录课程的表

创建cou表的sql语句

  1. create table Cou(
  2. CNO char(4) primary key not null, -- 课程编号 如:C001
  3. CNAME varchar(20) not null, -- 课程的名称 如:软件工程
  4. CREDIT smallint, -- 学分 实际没有用
  5. PTIME char(5), -- 学时 实际没有用
  6. TEACHER char(10) -- 教师 这个很有用
  7. );
  8. insert into cou(cno,cname,credit,ptime,teacher) values
  9. ('C001','高等数学',8,'1','孙老师'),
  10. ('C002','C语言',5,'2','张老师'),
  11. ('C003','数据结构',4,'3','张老师'),
  12. ('C004','操作系统',3,'4','罗老师'),
  13. ('C005','组成原理',4,'3','陈老师'),
  14. ('C006','高等数学',3,'5','吴老师'),
  15. ('C007','JAVA程序设计',3,'3','李老师');
  16. select *from cou;

有一个记录学生选课的表

 

 

对应的SQL语句

  1. create table Sc(
  2. SNO char(4) not null, -- 学生的学号
  3. CNO char(4) not null, -- 课程的编号
  4. GRADE decimal(4,1), -- 学生在该课程的得分 实际没有用
  5. primary key(SNO,CNO)
  6. );
  7. insert into sc(sno,cno,grade) values
  8. ('S001','C001',68.6),
  9. ('S001','C002',95.5),
  10. ('S001','C003',74.5),
  11. ('S002','C001',70),
  12. ('S002','C002',86.1),
  13. ('S003','C001',89.3),
  14. ('S003','C005',78.8),
  15. ('S003','C006',67.6),
  16. ('S004','C002',67.6),
  17. ('S004','C004',50.2),
  18. ('S005','C002',80.9);

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

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

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

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

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

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

 

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

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

   

 

 

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

  1. select sno from -- 选中学号
  2. (select * from sc where sc.cno in (select cno from cou where teacher='张老师')) a
  3. -- 有选修张老师课程的表
  4. group by sno -- 以学号为分组条件 分学号计算不同学号选修张老师的课程数
  5. having count(a.cno)=(select count(cno) from cou where teacher='张老师');
  6. -- 判断条件为选修张老师的科目数与张老师所教授的课程数一致

 

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

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

而下面的方法有点反着来

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

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

从特殊到一般:

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

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

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

输出的结果

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

对于S002 来说

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

输出的结果

 这说明S002这名学生选修的课程中缺失张老师的一节课 并且课程号为"C003",即S003这名学生并没有选修了张老师所有的课程 那么这么学生就应当保留在我们的剔除名单里

从一般的角度来看:

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

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

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

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

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

 

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

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

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

由于上面的结果是空集(也就是说上面的查询为空),那么此时的

查询可以理解为 

尝试取出 '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')

由于上面的结果不是空集 那么此时可以理解为

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

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

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

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

简单的做法是

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

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

  1. select sno from stu -- 从学生表出发
  2. where sno not in -- 查找学号不在剔除名单里的
  3. -- 学生剔除名单
  4. (select sno from stu where
  5. exists
  6. (select cno from cou where teacher='张老师'
  7. and
  8. cno not in (select cno from sc where sc.sno=stu.sno)));

 

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

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号