原文地址:http://mis.blogbus.com/logs/11754651.html
原来集合运算在删选条件为非唯一属性时才显的那么重要
-------------------------------------
-- SQL集合运算——查询的差集 --
-------------------------------------
--求没有选择课号为‘c01’的学生学号
/*以下语句不正确,原因是cid不是独立主键,并不能函数决定sid,
意味着选择了'c01'的某一sid,可能会同时选择非'c01'的其他cid,
因此,并不能通过仅排除'c01',而将所有的曾选择过'c01'的该sid排除在外。
该查询的目标范围将比实际的大。
*/
select sid from learning
where cid<>'c01'
/*正确语句*/
select sid from learning
except (
select sid from learning where cid='c01'
)
--求没有选择课号为‘c01’的学生的学号和课号
/*不正确。因为sid与cid的同时存在于子查询中,使得要减去的部分将比原来的小,
排除了该sid同时选择其他cid而被排除的可能性。其结果范围将比没有cid的大。
*/
select sid,cid from learning
except (
select sid,cid from learning where cid='c01'
)
--正确:
select sid,cid from learning
where sid in (
select sid from learning
except (
select sid from learning where cid='c01'
)
)
-------------------------------------
-- SQL集合运算——查询的交集 --
-------------------------------------
--求同时选了课号为'c01'和'c02'的学生学号
/*以下语句不正确。其结果将是空值,因为一个属性在一个元组中只能有一个值,不会有两个值。
select运行时只会一行一行地(逐个元组)进行,不会跨行进行比较。
*/
select sid from learning where cid='c01' and cid='c02'
/*以下语句正确:*/
select sid from learning where cid='c01'
intersect (
select sid from learning where cid='c02'
)
/*以下语句正确:通过自连接将cid的一个属性,变成两个名义属性,再逐行进行比较:*/
select l1.sid from learning l1,learning l2
where l1.sid=l2.sid and l1.cid='c01' and l2.cid='c02'
--问题:求同时选了课号为'c01'和‘c02’的学生学号和课号。
-------------------------------------
-- SQL集合运算——查询的并集 --
-------------------------------------
--求计算机系学生的学号和选了'c03'课程且成绩在分以上的学生学号
select sid from student where department='计算机系'
union (
select sid from learning
where cid='c03' and score>80
)
--分解分析,两个子查询自动将重复出现的记录合并
select sid from student where department='计算机系'
select sid from learning
where cid='c03' and score>70