1.如何理解关系中的除法

定义:设关系 R除以关系S的结果为关系T,则T包含所有在R中但不在S中的属性及其值,且T的元组与S的元组的所有组合都在R 中(摘自百度百科)。


文字上过于抽象,若用图来表示,以下表示为关系R、S、T之间的运算:

Python SQL 除法 sql里面除法_mysql

图中阴影部分为关系R与关系S重叠的部分,即某些属性的值发生了重合,这些属性是某些元组的子属性,将R÷S,得到的结果是,元组中除了这些重叠的属性外剩下的属性。


需要注意的是,R和S中的每一行都代表一个元组(这里没有给出元组之间的分界线)。同时,要求T中每一个分量都包含公有的部分!


下面给出具体的实例,考虑关系R和关系S:

X

Y

p1

q1

p1

q2

p1

q3

p2

q1

p2

q2

p3

q1

关系R



Y

Z

q1

m1

q2

m1

关系S



可以发现,R与S中发生重叠的属性是Y,除数S中S.Y的取值有{q1, q2},再考虑被除数R中,R.Y中包含S.Y即{q1, q2}的元素有{p1, p1},其中p1对应的R.Y真包含{p1, p2},p2对应的R.Y直接等于{p1, p2}。

因此,R÷Y的值就是

X

p1

p2

关系T

2.使用SQL来实现关系的除法运算
由以上论述可以发现,关系的除法实际上是一个关系的某些元素真包含另一个关系的某些元素的问题,因此可以用来解“关系包含”类的问题。

首先给出其一般表达语句:

select distinct R.X from R as R1
where not exists
(
  select S.Y from S
   where not exists
     (
      select select* from R as R2
      where R2.X = R1.X and R2.Y = S.Y
      )
)

逐句进行分析:




Python SQL 除法 sql里面除法_Python SQL 除法_02

这句话指明在R中查找X元组,我们把R命名为R1,方便后续的操作;


Python SQL 除法 sql里面除法_sql_03

此处的子查询表明,要在R中查找元组,这些元组的X属性是我们要找的目标属性(即最外层的R1.X),同时这些元组的Y列等于S.Y(即R与S发生重叠的部分)。也就是说,这两句话指明了要查找文章开头那张图中的R与S发生重叠的部分。



Python SQL 除法 sql里面除法_nosql_04

由上述可知,红框中第二行开始后的语义为:不存在②中这样的元组,即不存在“R与S发生重叠的部分”。再从红框中的第一行开始分析,我们要在S中找S.Y,并且S.Y与R.Y不发生任何重叠。


但是,由第一张图可知,只要R与Y能做除法,那么一定有R.Y与S.Y发生了重叠,怎么可能发生这样的情况呢?

因此就有了最外层的not exists:



Python SQL 除法 sql里面除法_数据库_05

结合上述分析,此处的语义为:不存在S.Y与R.Y不发生重叠的部分。此处的两个“不存在”分别对应与SQL语句中的两个"not exists"。这样,就能轻松处理集合之间的"包含"问题和"全部"问题了

当然,实际应用时,除了要理解原理,更要把SQL这种通用的语法形式熟悉掌握,在草稿纸上多默写几遍,才能用起来得心应手。