元组关系演算(从集合的角度深入浅出)- 例题(不严谨,无蕴含式)
由于之前的排版很chishi,所以就改了一下,把前面一部分移动到了新的文章《元组关系演算(从集合的角度深入浅出)》
例题(不严谨,更严谨的看这里:蕴含式) ===》
注:这里有如下说明 > 关于全称量词需要用到“蕴含式”,所以就不严谨(但并不是说有错误)。我们知道我们提出这样一个理论的目的是为了更好的运用于实际,在实际中我们是用的SQL语句来实现的,这样写是很难转换为SQL语句的,所以就不提倡大家用这样的方法写,上面就贴出来一个全新的、能够很容易就转换为SQL语句的元组关系演算(顺便介绍了“蕴含式”——百度百科)。
用户提供的5张表 ===》
描述的实体 | 表的中文名 | 表的数据结构 |
Teacher | 教师关系表 | T(TNo, TN, Dept) |
Student | 学生关系表 | S(SNo, SN, Dept) |
Class | 课程关系表 | C(CNo, CN, CT) |
Student_Class | 学生-选课关系表 | SC(SNo, CNo, Score) |
Teacher_Class | 教师-授课关系表 | TC(TNo, CNo) |
(Ⅰ)"全部都有" VS "至少没一"(即:A ∪ B =?= A,或者表述为A ?⊇ B)
(1). 查询选修了'李力'老师所教授的全部课程的学生的学号、姓名
粗略关系代数表达式为:
Π(SNo, SN)(S) ⋈ Π(SNo, CNo)(SC) ÷ ΠCNo{ΠTNo[σTN='李力'(T)] ⋈ TC};
元组演算表达式为: {
new_s(2) | 【(∃t)(∃sc)(∃s)】
【T(t) Λ TC(tc) Λ SC(sc) Λ S(s)】 Λ
【
t[2] = '李力' Λ # 在T表中选取TN字段为'李力'的元组;
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行自然连接,这时得到了李力老师教授的所有课程的课程号的集合:Lili_C;
s[1] = sc[1] Λ # 通过SNo字段将SC表与S表进行自然连接;
(∀tc) tc[2] = sc[2] Λ # 对于任意的(∀)tc ∈ TC,总是存在(∃)sc ∈ SC,满足tc[2] = sc[2],即Lili_C ⊆ SNocno(所在关系为Π(SNo, CNo)(SC));
new_s[1] = s[1] Λ # 将S表投影到SNo字段,新表的第一个属性为SNo;
new_s[2] = s[2] Λ # 将S表投影到SN字段,新表的第二个属性为SN;
】
}
(2). 查询至少有一门'李力'老师所教授的课程没有选过的学生的学号、姓名(这名学生没有选择李力老师教授的一门或以上的课程)
粗略关系代数表达式为:
Π(SNo, SN)(S) - Π(SNo, SN)(S) ⋈ Π(SNo, CNo)(SC) ÷ ΠCNo{ΠTNo[σTN='李力'(T)] ⋈ TC};
在上一个题目中,我们求的是"选修了'李力'老师所教授的全部课程的学生",所以选择"全称量词∀"来表述命题p:∀tc∈TC,∃sc∈SC使得tc[2] = sc[2]成立。而现在我们是"没有选择李力老师教授的一门或以上的课程的学生",即求¬p:∃tc∈TC,∀sc∈SC使得tc[2] ≠ sc[2]成立。
元组演算表达式为: {
new_s(2) | 【(∃t)(∃tc)(∀sc)(∃s)】
【T(t) Λ TC(tc) Λ SC(sc) Λ S(s)】 Λ
【
t[2] = '李力' Λ # 在T表中选取TN字段为'李力'的元组;
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行自然连接,这时得到了李力老师教授的所有课程的课程号的集合:Lili_C;
s[1] = sc[1] Λ # 通过SNo字段将SC表与S表进行自然连接;
tc[2] ≠ sc[2] Λ # 存在tc ∈ TC,对于任意的sc ∈ SC,都满足tc[2] ≠ sc[2],即TC ∩ SC ≠ TC;
new_s[1] = s[1] Λ # 将S表投影到SNo字段,新表的第一个属性为SNo;
new_s[2] = s[2] Λ # 将S表投影到SN字段,新表的第二个属性为SN;
】
}
--(3). 查询(至少)教授'数据库'和'计算机基础'这两门课程的老师的姓名(在老师教授的课程的课程编号集合中包含{'数据库'的编号, '计算机基础'的编号}) ===》
答:粗略关系代数表达式为: ===》
Π(TNo, CNo)[Π(TNo, TN)(T) ⋈ Π(TNo, CNo)(TC)] ÷ ΠCNo[σcn='数据库' ∨ cn='计算机基础'(C)];
元组演算表达式为: {
new_t(1) | (∃t)(∃tc)
【T(t) Λ TC(tc) Λ C(c)】 Λ
【
(∃c) (c[2] = '数据库' ∨ c[2] = '计算机基础') Λ # 在C表中选取CN字段为'数据库'的元组,其实是得到了'数据库'课程的编号sjk_C;
(∀c) (tc[2] = c[1]) Λ # ∀c∈C,∃tc∈TC,满足tc[2] = c[1],即TC ⊇ C;
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行连接;
new_t[1] = t[2] Λ # 将T表投影到TN字段,新表的第一个属性为TN;
】
}
--(4). 查找至少没有教授"数据库"和"计算机基础"这俩门课程中的一门的老师的姓名 ===》
答:关系代数: ===》
ΠTN(T) - Π(TNo, CNo)[Π(TNo, TN)(T) ⋈ Π(TNo, CNo)(TC)] ÷ ΠCNo[σcn='数据库' ∨ cn='计算机基础'(C)];
这个问题乍一看"WTF",那我们"正难则反",考虑其反面:"全部都选"。所以¬p: ∀tc∈TC和sc∈SC,都满足tc[2] ≠ sc[2] ===> p:∃tc∈TC和sc∈SC,满足tc[2] = sc[2],即A ∩ B ≠ ∅。
元组演算表达式为: {
new_t(1) | (∃t)(∃c)(∀tc)
【T(t) Λ TC(tc) Λ C(c)】 Λ
【
c[2] = '数据库' ∨ c[2] = '计算机基础' Λ # 在C表中选取CN字段为'数据库'的元组,其实是得到了'数据库'课程的编号sjk_C;
tc[2] ≠ c[1] Λ # ∃c∈C,∀tc∈TC都满足tc[2] ≠ c[1],即A ∪ B ≠ A;
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行连接;
new_t[1] = t[2] Λ # 将T表投影到TN字段,新表的第一个属性为TN;
】
}
(Ⅱ)"全部都没" VS "至少有一"(即:A ∩ B =?= ∅)
--(1). 查询没有选修'李力'老师的课程的(全部)学生的学号、姓名(一门李力老师教授的课程都没有选的学生) ===》
答:粗略关系代数表达式为(这个用关系代数比较难表达,所以我们可以看反面:"至少选了一门"。然后再用总的减去它):
Π(SNo, SN)(S) - Π(SNo, SN)(ΠCNo{ΠTNo[σcn='李力'(T)] ⋈ TC} ⋈ [Π(CNo, SNo)(SC) ⋈ Π(SNo, SN)(S)]);
这个问题可以表述为A ∩ B = ∅(对于A、B中的所有元素,都满足a ≠ b),这里的A即为{某个学生选课的编号集合},B即为{李力老师教授课程的课程编号集合}
元组演算表达式为: {
new_s(2) | 【(∃t)(∀tc)(∀sc)(∃s)】
【T(t) Λ TC(tc) Λ SC(sc) Λ S(s)】 Λ
【
t[2] = '李力' Λ # 在T表中选取TN字段为'李力'的元组;
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行连接,得到李力老师教授的全部课程的课程编号集合;
tc[2] ≠ sc[2] Λ # ∀tc∈TC和sc∈SC,都满足tc[2] ≠ sc[2];
s[1] = sc[1] Λ # 通过SNo字段将SC表与S表进行自然连接;
new_s[1] = s[1] Λ # 将S表投影到SNo字段,新表的第一个属性为SNo;
new_s[2] = s[2] Λ # 将S表投影到SN字段,新表的第二个属性为SN;
】
}
--(2). 查询选修了'李力'老师的课程的(全部)学生的学号、姓名(至少选修了一门李力老师教授的课程的学生) ===》
答:粗略关系代数表达式为: ===》
Π(SNo, SN)(ΠCNo{ΠTNo[σcn='李力'(T)] ⋈ TC} ⋈ [Π(CNo, SNo)(SC) ⋈ Π(SNo, SN)(S)]);
很懵逼,那老规矩"正难则反",考虑其反面:"全部都没选",发现正好是(1)中解决的(真巧吭,难道是故意安排的,谁知道呢?),所以¬p: ∀tc∈TC和sc∈SC,都满足tc[2] ≠ sc[2] ===> p:∃tc∈TC和sc∈SC,满足tc[2] = sc[2],即A ∩ B ≠ ∅。
元组演算表达式为: {
new_s(2) | 【(∃t)(∃tc)(∃sc)(∃s)】
【T(t) Λ TC(tc) Λ SC(sc) Λ S(s)】 Λ
【
t[2] = '李力' Λ # 在T表中选取TN字段为'李力'的元组;
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行连接,得到李力老师教授的全部课程的课程编号集合;
tc[2] = sc[2] Λ # ∃tc∈TC和sc∈SC,满足tc[2] = sc[2],即在TC表中存在某个元组tc,总能在SC表中找到某个元组sc,满足tc[2] = sc[2];
s[1] = sc[1] Λ # 通过SNo字段将SC表与S表进行自然连接;
new_s[1] = s[1] Λ # 将S表投影到SNo字段,新表的第一个属性为SNo;
new_s[2] = s[2] Λ # 将S表投影到SN字段,新表的第二个属性为SN;
】
}
--(3). 查询教授'数据库'这门课程的(全部)老师的编号、姓名(在老师教授的课程的课程编号集合中至少存在数据库这门课程的编号) ===》
答:粗略关系代数表达式为: ===》
Π(TNo, TN){ΠCNo[σcn='数据库'(C)] ⋈ TC ⋈ Π(TNo, TN)(T)};
元组演算表达式为: {
new_t(2) | 【(∃c)(∃t)(∃tc)】
【T(t) Λ C(c) Λ TC(tc)】 Λ
【
c[2] = '数据库' Λ # 在C表中选取CN字段为'数据库'的元组;
tc[2] = c[1] Λ # ∃tc∈TC和c∈C,满足tc[2] = c[1],即'数据库'课程的编号sjk_C存在于这位老师教授课程的课程编号集合中;
tc[1] = t[1] Λ # 通过TNo字段将T表与TC表进行连接;
new_t[1] = t[1] Λ # 将T表投影到TNo字段,新表的第一个属性为TNo;
new_t[2] = t[2] Λ # 将T表投影到TN字段,新表的第二个属性为TN;
】
}
--(4). 查找没有教授"数据库"这门课程的老师的姓名('数据库'这门课程全都不存在于老师的教授课程编号集合中) ===》
答:粗略关系代数表达式为(考虑反面:"至少有一个'数据库'的课程存在于老师的教授课程编号集合中"):
ΠTN(T) - ΠTN{ΠCNo[σcn='数据库'(C)] ⋈ TC ⋈ Π(TNo, TN)(T)};
元组演算表达式为: {
new_t(1) | (∃t)(∀tc)(∀c)
【T(t) Λ TC(tc) Λ C(c)】 Λ
【
c[2] = '数据库' Λ # 在C表中选取CN字段为'数据库'的元组,其实是得到了'数据库'课程的编号sjk_C;
tc[2] ≠ c[1] Λ # ∀tc∈TC和c∈sjk_C,都满足tc[2] ≠ c[1];
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行连接;
new_t[1] = t[2] Λ # 将T表投影到TN字段,新表的第一个属性为TN;
】
}
3. "全部都有" VS "全部都没" (注意:这俩并不是对立事件!!!)
--(1). 查询选修了所有课程的学生的学号、姓名(在C表中任取一个课程都能在这个学生的SC表中找到对应的CNo ===> ∀c∈C,c∈在集合π(SNo, CNo)(SC)中SNo的像集CNosno) ===》
答:粗略关系代数表达式为: ===》
Π(SNo, SN)(S) ⋈ Π(SNo, CNo)(SC) ÷ ΠCNo(C)
元组演算表达式为: {
new_s(2) | 【(∀c)(∃sc)(∃s)】
【C(c) Λ S(s) Λ SC(sc)】 Λ
【
s[1] = sc[1] Λ # 通过SNo字段将SC表与S表进行连接,这时其实可以得到所有选课学生的课程编号;
sc[2] = c[1] Λ # 对于任意的c ∈ C,总是存在(∃)sc ∈ SC,满足sc[2] = c[1],即πCNo(C) ⊆ SNocno(所在关系为π(SNo, CNo)(SC));
new_s[1] = s[1] Λ # 将S表投影到SNo字段,新表的第一个属性为SNo;
new_s[2] = s[2] Λ # 将S表投影到SN字段,新表的第二个属性为SN;
】
}
--(2). 查询没有选修一门课程的学生的学号、姓名(比如:1805xxxxx04, SimbaWang) ===》
答:粗略关系代数表达式为(老规矩"正难则反":"选修了课程的学生"): ===》
ΠSN(S) - ΠSN[Π(SNo)(SC) ⋈ Π(SNo, SN)(S)]
元组演算表达式为: {
new_s(2) | 【(∀c)(∀sc)(∃s)】
【C(c) Λ S(s) Λ SC(sc)】 Λ
【
s[1] = sc[1] Λ # 通过SNo字段将SC表与S表进行连接,这时其实可以得到所有选课学生的课程编号;
sc[2] ≠ c[1] Λ # 对于任意的c ∈ C和sc ∈ SC,都满足sc[2] ≠ c[1],即这两者的交集为∅;
new_s[1] = s[1] Λ # 将S表投影到SNo字段,新表的第一个属性为SNo;
new_s[2] = s[2] Λ # 将S表投影到SN字段,新表的第二个属性为SN;
】
}
--(1). 查询选修了'李力'老师所教授的全部课程的学生的学号、姓名 ===》
答:粗略关系代数表达式为: ===》
Π(SNo, SN)(S) ⋈ Π(SNo, CNo)(SC) ÷ ΠCNo{ΠTNo[σTN='李力'(T)] ⋈ TC};
元组演算表达式为: {
new_s(2) | 【(∃t)(∃sc)(∃s)】
【T(t) Λ TC(tc) Λ SC(sc) Λ S(s)】 Λ
【
t[2] = '李力' Λ # 在T表中选取TN字段为'李力'的元组;
t[1] = tc[1] Λ # 通过TNo字段将T表与TC表进行自然连接,这时得到了李力老师教授的所有课程的课程号的集合:Lili_C;
s[1] = sc[1] Λ # 通过SNo字段将SC表与S表进行自然连接;
(∀tc) tc[2] = sc[2] Λ # 对于任意的(∀)tc ∈ TC,总是存在(∃)sc ∈ SC,满足tc[2] = sc[2],即Lili_C ⊆ SNocno(所在关系为Π(SNo, CNo)(SC));
new_s[1] = s[1] Λ # 将S表投影到SNo字段,新表的第一个属性为SNo;
new_s[2] = s[2] Λ # 将S表投影到SN字段,新表的第二个属性为SN;
】
}