今天学习到了如何通过NOT EXISTS来实现SQL中的关系除法,记录一下以备日后温习。
已经了解到,SQL现成的集合运算符有:UNION(并集)、EXCEPT(差集)、INTERSECT(交集)、CROSS JOIN(笛卡儿积),但关系除法是没有现成函数的。
由于下面会用到,所以首先熟悉一下 EXISTS 的作用和用法:
例如下面的代码实现的功能是找出在Table1、Table2中同时存在的全部id所对应的行
SELECT * FROM Table1 WHERE EXISTS( SELECT 1 FROM Table2 WHERE Table2.id=Table1.id) ;
/*内查询中select后面的内容可以任意设定,哪怕NULL都OK,不影响结果,
因为EXISTS函数的内查询中返回的是布尔值True或False,对应着查询结果存在与否,与结果的实际内容无关*/
结果等同于IN语句
SELECT * FROM Table1 WHERE id IN(SELECT id FROM Table2);
接下来正式进入关系除法的演示部分,我们使用两张表作为示例用表。
Skills表:
-----
skill
------
Oracle
UNIX
Java
EmpSkills表:
emp skill
--------------
相田 Oracle
相田 UNIX
相田 Java
相田 C#
神崎 Oracle
神崎 UNIX
神崎 Java
平井 UNIX
平井 Oracle
平井 PHP
平井 Perl
平井 C++
若田部 Perl
渡来 Oracle
以下这个问题就是除法的典型应用:
“从该表中选取出掌握了Skills表中所有3个领域的技术的员工”
方法一:
SELECT DISTINCT emp
FROM EmpSkills ES1
WHERE NOT EXISTS
(SELECT skill
FROM Skills
EXCEPT
SELECT skill
FROM EmpSkills ES2
WHERE ES1.emp = ES2.emp);--原书作者有笔误
这样我们就得到了包含相田和神崎2 人的结果。
emp
------
神崎
相田
通过另一种方法,可以实现同样的结果。
方法二:
SELECT emp
FROM EmpSkills
WHERE skill in (SELECT skill FROM Skills)
GROUP BY emp
HAVING COUNT(DISTINCT skill)=(SELECT COUNT(skill) FROM Skills);