第2章_004_关系数据库_关系演算_001_元组关系演算

一. 定义 ===》
元组关系演算中,以元组为单位,通过公式约束所要查找元组的条件,可以表示为: {t | φ(t)} ===> 使φ(t)为真的元组t的集合。其中: t为元组变量,即查询目的,φ为元组演算的谓词公式,即查询的条件。
按照集合的思想来理解即为:个体词t具有谓词φ(t)的性质。



二. 元组关系演算的谓词公式 ===》
φ(t)可以通过原子公式、约束公式、自由变量、运算符构成。
1. 原子公式分为3类 ===》
--(1). R(t): R为关系名,表示t是R中的元组;

--(2). t[i] θ u[j]: 表示"元组t的第i个分量与元组u的第j个分量进行比较运算: θ",如t[2] < u[3]。

--(3). t[i] θ C: 表示"元组的第i个分量与常量C进行比较运算: θ",如t[3] > 5。

2. 约束元组变量 && 自由元组变量 ===》
若元组演算公式中的一个元组变量前有"全称量词"和"存在量词",则称该变量为约束元组变量; 否则称为自由元组变量。
即: 在公式(∃t)φ(t)和(∀t)φ(t)中,φ称为量词的辖域。t出现在(∃t)或(∀t)的辖域内,t为约束元组变量,被量词所绑定。任何没有以这种方法显示绑定的变量都称为自由变量。

3. 为此公式φ(t)的递归定义 ===》
--(1). 原子公式是公式;

--(2). 通过吸取连接词、合取连接词所构成的复合公式也是公式 ===> 设φ1(t1)和φ2(t2)是公式,则¬φ1(t1),φ1(t1) Λ φ2(t2)和φ1(t1) ∨ φ2(t2)也是公式;

--(3). 利用全称量词和存在量词构成的公式也是φ(t)的一种表现形式 ===> (∃t)φ(t)和(∀t)φ(t)也是公式;

--(4). 有限次利用上述规则得到的式子都是公式;


三. 公式运算符及其优先级 ===》
1. 算术比较符: <, >, ≥, ≤, ≠, =;
2. 全称量词∀和存在量词∃;
3. 逻辑运算符: Λ, ∨, ¬, →;
4. 优先级: 算术比较符 > 全称量词∀和存在量词∃ > 逻辑运算符;


四. 元组关系演算与关系代数 ===》
在元组关系演算中,可以不用考虑为解决表的自然连接中产生数据冗余而进行投影属性列(最好还是考虑,但是为了简化步骤就没有考虑)
1. 传统关系代数 ---> 元组关系演算 ===》
--(1). 交操作: {t | R(t) Λ S(t)};

--(2). 并操作: {t | R(t) ∨ S(t)};

--(3). 差操作: {t | R(t) Λ ¬S(t)};

--(4). 广义笛卡尔积操作: {t(m+n) | (∃u)(∃v) (R(u) Λ S(v)) Λ (t[i]=u[j] (i=1, 2, ..., m) Λ t[i]=v[k]) (i=m+1, m+2, ..., m+n) (j=1, 2, ...,m) (k=1, 2, ..., n)};

2. 专门关系代数 ---> 元组关系演算 ===》
--(1). 选择操作: {t | R(t) Λ F},其中F ☞ 查询的条件。选取操作只是在原有的表上,将满足特定性质的元组提取出来,并没有形成新的表。

--(2). 投影操作: {t(n) | (∃u) (R(u) Λ t[i]=u[j]) (i=1, 2, ..., n, j∈[1, count_A(R)])}。===> ∃u ∈ R,满足t[1] = u[1]。投影是建立了一个新的表,这个表中的列来自于原表中的属性列(感兴趣的、被选取出来的列)。

补充:为什么投影是要对所有的关系中元组进行操作(将所有的元组投影到属性列上),但却用"存在量词∃"而不是"全称量词∀"?===》
因为如果用了"全称量词∀",那么这句话将会被解释为:"对于任意的u∈R,都满足t[i] = u[j]" ===> "新关系中某一个元组上的第i个分量t[i]等于原关系的第j列上所有的分量",这显然是不正确的,这是因为一个t[i]有且仅有一个u[j]与之对应相等。所以说,我们只能表述为:"在关系R中,总是存在某一个u元组,满足t[i] = u[j]"。
还有一种解释(更确切地说是理解)将会在下面提到。
补充:投影用存在量词∃的原因


五. 什么时候用"全称量词∀和存在量词∃"("浅"理解) ===》
1. "存在量词∃": 当需求中含有"存在一个"、"至少一个"、"有一个"等词的时候。就像上述的投影操作一样:有且仅有一个R中的u元组,满足t[i] = u[j]。

2. "全称量词∀": 当需求中含有"全部"、"所有"等词,并且将"全部"一词去掉有后改变原句句意的时候。eg:
--(1). 在进行操作的过程中选择某一集合中全部元素的元素集合时,即此时的"全部"并不是默认值,默认值为"至少一个 / 存在": "查询选修了全部课程的学生",将"全部"一词去掉后变为"查询选修了课程的学生",前一个是"选修了全部课程",后一个是"只要是选修了课程,即至少选修了一门课程",将两者比较我们发现,两句话的句意完全不同。

--(2). 在经过一系列操作后所得到的集合中选择全部元组时,即此时的"全部"为默认值: 对于"查询选修了'刘伟'老师的课程的全部学生",将"全部"一词去掉后变为"查询选修了'刘伟'老师的课程的学生",这并没有len何差别,所以自然就"不配"使用"全称量词∀"了。

--(3). 关于"投影中使用'存在量词∃'的另一角度的理解": "将所有的元组投影到属性列上",把"所有的"一词去掉变为"将元组投影到属性列上",显然这两句话其实是一样的意思。

六. 命题的否定 VS 否命题 ===》
存在一个命题为:若p,则q。
1. 命题的否定: 若p,则¬q。也就是说,命题的否定只会否定命题的结论,并不会否定命题的条件。简单来说就是与原命题唱反调,所以他与原命题是完全对立的。所以我们研究问题的时候用的"正难则反"就是研究问题的否定形式¬q。

2. 否命题: 若¬p,则¬q。也就是说,否命题会把命题的条件和结论一起否定掉。他与原命题的真假无关,与逆命题同真同假。

3. 全称量词∀和存在量词∃的否定形式 ===》
--(1). 全称量词∀的否定形式 ===》
  1st. 更换量词: 将全称量词∀换成存在量词∃;
  2nd. 将结论否定;
也就是说: 全称量词∀的否定是一个存在命题;

--(2). 存在量词∃的否定形式 ===》
  1st. 更换量词: 将存在量词∃换成全称量词∀;
  2nd. 将结论否定;
也就是说: 存在量词∃的否定是一个全称命题;

七. 例题(不严谨,更严谨的看这里:蕴含式) ===》

注:这里有如下说明 > 关于全称量词需要用到“蕴含式”,所以就不严谨(但并不是说有错误)。我们知道我们提出这样一个理论的目的是为了更好的运用于实际,在实际中我们是用的SQL语句来实现的,这样写是很难转换为SQL语句的,所以就不提倡大家用这样的方法写,上面就贴出来一个全新的、能够很容易就转换为SQL语句的元组关系演算(顺便介绍了“蕴含式”——百度百科)。

用户提供的5张表 ===》
  1st. Teacher      (教师关系表)     as    T  (TNo, TN, Dept)
  2nd. Student      (学生关系表)     as    S  (SNo, SN, Dept)
  3rd. Class       (课程关系表)     as    C  (CNo, CN, CT)
  4th. Student-Class   (学生-选课关系表)  as    SC (SNo, CNo, Score)
  5th. Teacher-Class   (教师-授课关系表)  as    TC (TNo, CNo)


1. "全部都有" VS "至少没一"(即:A ∪ B =?= A,或者表述为A ?⊇ B)
--(1). 查询选修了'李力'老师所教授的全部课程的学生的学号、姓名 ===》
答:粗略关系代数表达式为: ===》
Π(SNo, SN)(S) ⋈ Π(SNo, CNo)(SC) ÷ ΠCNoTNoTN='李力'(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) ÷ ΠCNoTNoTN='李力'(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)] ÷ ΠCNocn='数据库' ∨ 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)] ÷ ΠCNocn='数据库' ∨ 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;
  】
}



2. "全部都没" VS "至少有一"(即:A ∩ B =?= ∅)
--(1). 查询没有选修'李力'老师的课程的(全部)学生的学号、姓名(一门李力老师教授的课程都没有选的学生) ===》
答:粗略关系代数表达式为(这个用关系代数比较难表达,所以我们可以看反面:"至少选了一门"。然后再用总的减去它): 
Π(SNo, SN)(S) - Π(SNo, SN)CNoTNocn='李力'(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)CNoTNocn='李力'(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)CNocn='数据库'(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) - ΠTNCNocn='数据库'(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;
  】
}



八. 总结 (什么时候用"全称量词∀和存在量词∃"("深"理解)) ===》
研究"全称量词∀和存在量词∃"本质上就是研究"集合"的有关问题,所以要先把握住集合与集合之间的关系。任何两个集合的关系有且仅可能有3种:相交、包含、相离,并且这三种关系又有如下的关系 ===》
  1. "相离" 与 "相交"∪"包含": 互为对立事件,即"全部都没" VS "至少有一";
  2. "包含" 与 "相交"∪"相离": 互为对立事件,即"全部都有" VS "至少没一";

了解了这个后,我们就可进一步的归纳出使用"全称量词∀和存在量词∃"的情景 ===》
  1. 当某个事件被表述为两个集合"相离"或者"包含"的时候 ===> 使用"全称量词∀"来表示"全部都没"或者"全部都有";
  2. 当某个事件被表述为两个集合"相交"的时候 ===> 使用"存在量词∃"来表达"至少有一"或者"至少没一"

举个栗子 ===》
  1. "相离": "没有选修过'李力'老师教授的课程的同学"这个问题就可以被表述为:"Ai ∩ B = ∅",其中Ai = {第i个学生的"学生-选课信息"的课程编号集合},B = {'李力'老师教授的课程的课程编号集合};
  2. "相交": "选修过'李力'老师教授的课程的同学"这个问题就可以被表述为:"Ai ∩ B ≠ ∅",其中Ai = {第i个学生的"学生-选课信息"的课程编号集合},B = {'李力'老师教授的课程的课程编号集合};
  3. "包含": "选修了'李力'老师教授的全部课程的同学"这个问题就可以被表述为:"Ai ⊇ B",其中Ai = {第i个学生的"学生-选课信息"的课程编号集合},B = {'李力'老师教授的课程的课程编号集合};

 

从"正"、"反"两个方面考虑问题的角度来说 ===》

1. 当考虑的问题是"全部都有"时则可以从面入手,在关系代数中利用除法,在元组演算中利用"全称量词∀";

2. 当考虑的问题是"至少没有一个"时则可以从面入手,在关系代数中利用除法 + 减法,在元组演算中利用"存在量词∃";

3. 当考虑的问题是"至少存在一个"时则可以从面入手,在关系代数中利用自然连接,在元组演算中利用"存在量词∃";

4. 当考虑的问题是"全部都无"时则可以从面入手,在关系代数中利用自然连接 + 减法,在元组演算中利用"全称量词∀";

(头发嗐挺多)

猜你喜欢

转载自www.cnblogs.com/SimbaWang/p/12502855.html