关系还可以做除法!的确是这样。那么关系的除法运算是怎样的呢?在这一节,我们将会揭开关系除法运算的面纱!
为了便于讨论,我们示意性地给出以下两个关系:

说明一下:假定SC是学生的选课信息关系,sid是学生的学号,cid是该学生所选课程的课程号。C是我们给定的一个局部的课程关系,cid是课程号。
来看一下我们遇到的问题:在SC中检索选修了C中所有课程的学生的学号。
这个问题如何解决呢?答案就是关系的除法:SC ÷ C。
这是怎么回事?让我们来看一下SC÷ C的运算步骤:
第1步:从SC中取出sid列(即去除与C中相同的列)。sid就是我们需要判定的学生。

第2步:将第1步取出的sid列中的每一个元祖和C分别做笛卡儿积。如果其中任何一个元祖和C进行笛卡儿积运算的结果全部包含在SC中,那么该元祖即为除法运算的结果之一。
比如对于第1步取出的sid列,我们依次进行判定:
第1轮:取出第1个元祖1,将其和C做笛卡儿积,得到两个元祖{(1,4),(1,7)};判定{(1,4),(1,7)}是否全在SC中?根据SC中的数据,全部存在,所以1是除法运算的结果。
第2轮:取出第2个元祖2,将其和C做笛卡儿积,得到两个元祖{(2,4),(2,7)};判定{(2,4),(2,7)}是否全在SC中?根据SC中的数据,(2,4)并未出现在SC中,所以2不是除法运算的结果。
第3轮:取出第3个元祖3,将其和C做笛卡儿积,得到两个元祖{(3,4),(3,7)};判定{(3,4),(3,7)}是否全在SC中?根据SC中的数据,(3,7)并未出现在SC中,所以3不是除法运算的结果。
第4轮:取出第4个元祖4,将其和C做笛卡儿积,得到两个元祖{(4,4),(4,7)};判定{(4,4),(4,7)}是否全在SC中?根据SC中的数据,(4,4),(4,7)均未出现在SC中,所以4不是除法运算的结果。
结论:SC ÷ C的结果为1,即:

这就是关系的除法运算过程,我们给出除法运算的定义:
关系的除法 R ÷ S
设有关系R(X,Y)与关系S(Z),其中X,Y,Z 为属性集合。假设Y和Z具有相同的属性个数,且对应属性出自相同域。关系R(X,Y)除以 S(Z) 所得的商关系是关系R在属性X上投影的 一个子集,该子集和S(Z)的笛卡尔积必须包含在R(X,Y)中。
我们再次给出示范性的R和S供大家来理解一下这个定义:

根据上面的定义,可得出以下结论:
R中包含X,Y两个属性集合,其中X={A},Y={B,C};
S中包含Z,T两个属性集合,其中Z={B,C},T={D},T对于此处的除法运算没有意义,可忽略。
R中的Y和S中的Z具有相同的属性个数(都是2个:B、C),且出自相同域(字符串)。
所以R÷S的商是R在属性A上投影的一个子集,该子集和S(B,C)的笛卡尔积必须包含在R(A, B, C)中。
据此,对属性A中的每一个元祖(a1,a2,a3,a4)进行检视,看它们与S(B,C)的笛卡儿积是否全部包含在R中?
A=
S(B,C) = 
需要说明的是A中相同的元祖无需重复测试。
第一趟:取出A中的元祖a1,将其和S(B,C)做笛卡儿积,得到两个元祖{(a1,b1,c2),(a1,b2,c1)};判定{(a1,b1,c2),(a1,b2,c1)}是否全在R(A,B,C)中?根据R中的数据,全部存在,所以a1是除法运算的结果。
第二趟:取出A中的元祖a2,将其和S(B,C)做笛卡儿积,得到两个元祖{(a2,b1,c2),(a2,b2,c1)};判定{(a2,b1,c2),(a2,b2,c1)}是否全在R(A,B,C)中?根据R中的数据,全部存在,所以a2是除法运算的结果。
第三趟:取出A中的元祖a3,将其和S(B,C)做笛卡儿积,得到两个元祖{(a3,b1,c2),(a3,b2,c1)};判定{(a3,b1,c2),(a3,b2,c1)}是否全在R(A,B,C)中?根据R中的数据,(a3,b1,c2)并未出现在R中,所以a3不是除法运算的结果。
第四趟:取出A中的元祖a4,将其和S(B,C)做笛卡儿积,得到两个元祖{(a4,b1,c2),(a4,b2,c1)};判定{(a4,b1,c2),(a4,b2,c1)}是否全在R(A,B,C)中?根据R中的数据,(a4,b1,c2),(a4,b2,c1)均未出现在R中,所以a4不是除法运算的结果。
结论:R(A,B,C) ÷ S(B,C)的结果为(1,2),即:

我们再次详细地阐述了关系除法的运算过程,希望大家真正地理解了除法运算。接下来我们准备在关系代数表达式中运用除法运算来解决一个实际问题。
【例1】找出在位于Brooklyn的所有支行都有帐户的客户。


解析:这道题我们可以分作3步来完成:
第1步:找到位于Brooklyn的所有支行。
r1=πbranch-name(σcity=‘Brooklyn’(branch))
结果示意如下:

第2步:找到在支行有帐户的所有客户。
r2 =Πcustomer-name,branch-name(depositor⋈account)
结果示意如下:

第3步:找出在位于Brooklyn的所有支行都有帐户的客户。这是我们的最终目的,但这一步如何实现呢?没有账户的客户自然是不用管了,而所有有账户的客户均已被我们找出,存在了r2中。所以我们的办法当然是扫描r2中的每一个客户,将其与r1中的支行进行笛卡儿积,然后判断该客户与所有支行的组合是否都在r2中?如果有任何一个不在,则都说明该客户未在r1所表示的所有支行有账户;否则说明该客户在r1中的所有支行均有账户。回顾一下,这不就是除法运算的定义吗?所以这一步只需要利用除法运算即可解决问题。
r2 ÷ r1 = πcustomer-name,branch-name(depositor⋈account)
÷ πbranch-name(σcity=‘Brroklyn’ (branch))
因此最终的关系代数表达式是:
πcustomer-name,branch-name(depositor⋈account)
÷ πbranch-name(σcity=‘Brroklyn’ (branch))
小结:除法运算的运用时机和方法其实并不好掌握。我们尝试着为大家小结一下,以便于大家能够更加准确和灵活地使用除法运算来解决问题。
此处以上例的题目来说明:
“找出在位于Brooklyn的所有支行都有帐户的客户。”
1. 运用时机
一般在题目中出现“所有”或“全部”字样的时候,就应该考虑使用除法运算。
2. 除数和被除数的确定
除数(除关系):一般在题目中出现“所有XX”或“全部XX”的时候,那么这个“所有XX”或“全部XX”就是除法运算中的除数,比如例1中的“所有支行”就是除法运算中的除数。除数也许是一个现存的关系,也许是一个需要通过选择或投影运算来构造的新关系。一般来讲,除关系中出现的列就是“所有XX”中“XX”所对应的列。比如例1中的“所有支行”中的“支行”就是我们确定除数应该包含哪些列的依据。但是“支行”本身并不是一个具体的列,在例1的branch关系中,有branch-name,city,assets列,哪些列是我们构造除数关系所需要的呢?这里可以从两个方面来考虑:能够代表支行、区分支行的只有branch-name;观察depositor和account关系,它们都含有branch-name,而没有city、assets列;其实大家都清楚branch-name在此处是一个外键。一个客户在支行有没有账户,只是看该客户与branch-name的组合是否存在?与该支行的city和assets信息并无关系,所以除数关系中应该包含的列只有branch-name。因此在例1中我们采用了选择和投影运算构造出了一个新关系来充当除数。
被除数(被除关系):和除数的构造相同,被除数也许是一个现存的关系,也许是一个需要通过选择或投影运算来构造的新关系。不管如何构造,必须保证被除数中应该包含两个部分:(1)除数所包含的列;(2)希望查询的列。在例1中,我们最后构造出的被除数就包含有除数所包含的列branch-name,以及希望查询的列customer-name。被除数中的数据不需要进行筛选,它是我们判定一个元组是否是商的重要依据。
以上小结仅是一种经验的总结,希望对大家掌握关系的除法运算有所帮助。