集合论是SQL语言的根基——这是贯穿全书主题之一。因为他的这个特性,SQL也被称为面向集合语言。只有从集合的角度思考,才能明白SQL的强大。 但是,实际上这一点长期以来都被很多人忽略了。造成这种状况,SQL本身也是要负一定责任的。其实,在很长一段时间内,SQL连我们在高中学习过的基础的集合运算符都没有。UNION是SQL-86标准开始加入的,还算比较早,而INTERSECT和EXCEPT都是SQL-92标准才加入的。至于关系除法,更是至今还没有被标准化。
这里说的“相等”指的是行数和列数以及内容都相同,即是“同一个集合”的意思
select count(1) row_cnt from ( select * from tbl_A union select * from tbl_b ) tmp ;在本节开头说过,SQL里还没有能直接进行关系除法运算的运算符。因此,为了进行除法运算,必须自己实现。方法比较多,其中具有代表性的是下面三个
嵌套使用NOT EXISTS使用HAVING子句转化成一对一关系把除法变成减法 Skills skill(技术)OracleUNIXJava EmpSkills emp(员工)skill(技术)相田Oracle相田UNIX相田Java相田C#神崎Oracle神崎UNIX神崎Java平井UNIX平井Oracle平井PHP平井Perl平井C++若田部Perl渡来Oracle 从表EmpSkills中找出精通表Skills中所有技术的员工 --用求差的方法进行关系除法运算 select distinct emp from empskills es1 where not exists (select skill from skills expect select skill from empskills es2 where es1.emp = es2.emp); /**理解这段代码的要点在于EXCEPT运算符和关联子查询。 关联子查询建立在表Empskills上,这是因为,我们要针对每个员工进行集合运算。 即从集合的技术的集合中减去每个员工自己的技术的集合,结果集合为空集 则说明该员工具备所有的需求的技术,否则说明该员工不具备某些需求的技术**/注意:
关联子查询是为了使SQL能够实现类似面向过程语言中循环的功能而引入的这个问题看起来简单,但是SQL并没有提供任何用于检查集合的包含关系或相等性的谓词,并且比较的双方都不固定,这次我们需要比较所有子集的全部组合,所以这个问题更具有普遍性
--找出经营的零件在种类数和种类上都完全相同的供应商组合 select a.sup s1, b.sup s2 from supparts a, supparts b where a.sup < b.sup -- 生成供应商的全部组合 and a.part = b.part -- 条件1:经营同种类型的零件 group by a.sup, b.sup having count(*) = (select count(1) -- 条件2:经营的零件的数量种类相同 a = 中间数 from supparts c where c.sup = a.sup) and count(*) = (select count(1) -- 条件2:经营的零件的数量种类相同 b = 中间数 from supparts d where d.sup = b.sup) /**如果我们把HAVING子句里的两个条件当初精准关系除法运算,机会很好理解 加上这两个条件,我们就能保证集合A和集合B的元素个数一致,不会出现不足或者过剩(即存在一一映射) 而且条件一又保证了经营的零件类型也都是完全相同的**/ ;本节要点:
在集合运算方面,SQL的标准化进行的比较缓慢,直到现在也是实现状况因数据库不同而参差不齐,因此使用的时候需要注意如果集合运算符不指定ALL可选项,重复行会被排除掉,而且这种情况还会发生排序,所以性能方面不够好UNION和INTERSECT都具有幂等性这一重要性质,而EXCEPT不具有幂等性标准SQL没有关系除法的运算符,需要自己实现判断两个集合是否相等时,可以通过幂等性或一一映射两种方法使用EXCEPT可以很简单的求得补集