CS145 Intro to databases 学习笔记3——关系型数据库设计、XML的查询、UML

前言

晚上床上玩手机有点上头,导致一整天下午之前都没怎么精神刷课,于是调整了下学这套课程的排期,多排了一天嘻嘻,这下轻松多了。

本文是学习standford CS145 Introduction to Databases系列视频的第三篇笔记,主要包括第七章到第九章的内容:

  1. 关系型数据库设计
  2. XML的查询
  3. 统一建模语言(Unified Modeling Language, or UML)

个人博客页观感更加喵,踩一踩留个脚印谢谢喵:CS145 Intro to databases 学习笔记3------关系型数据库设计、XML的查询、UML | Andrew的个人博客 (andreww1219.github.io)

相关参考资料:

视频链接:Introduction to Databases - Jennifer Widom - Stanford

函数依赖、部分依赖、传递依赖等准备知识:范式通俗理解:1NF、2NF、3NF和BNCF-CSDN博客

关系模式的分解原则:【数据库原理】(18)关系模式的分解 - 知乎 (zhihu.com)

三范式和BCNF的举例:数据库三范式和BCNF范式的理解:生动举例-CSDN博客

3NF和BCNF的区别:Difference Between 3NF and BCNF (with Comparison Chart) - Tech Differences

组合和聚合:UML一一 类图关系 (泛化、实现、依赖、关联、聚合、组合)_uml类图关系-CSDN博客

一、关系型数据库设计

1. 基本概念

现有关系表 R R R,关系表的所有属性的集合为 U U U

X X X、 Y Y Y和 Z Z Z皆为 R R R上的一组属性,即 X , Y , Z ⊆ U X, Y, Z \subseteq U X,Y,Z⊆U

1.1 函数依赖(Functional Dependencies)

(1) 定义

∀ t , u ∈ R \forall t, u \in R ∀t,u∈R,如果 t X = u X tX = uX tX=uX,则有 t Y = u Y tY = uY tY=uY,其中 t X tX tX代表取元组 t t t所有 X X X中的属性

则称, Y Y Y依赖于 X X X,记为 X → Y X \rightarrow Y X→Y

讲人话就是确定了 X X X就确定了 Y Y Y ,称 Y Y Y依赖于 X X X

(2) Trivial or Nontrivial

trivial意为平常的、琐碎的、不重要的,所以trivial的Functional Dependency(以下简称FD)就是在讲废话,不能传递更多信息。

Trivial FD:当 Y ⊆ X Y \subseteq X Y⊆X,我们称 X → Y X \rightarrow Y X→Y是 Trivial FD。因为确定了 X X X肯定就确定了它的子集 Y Y Y(讲废话

Nontivial FD:相对地,当 Y ⊈ X Y \nsubseteq X Y⊈X,我们称 X → Y X \rightarrow Y X→Y是 Nontrivial FD。

Complete nontrivial FD:当 X X X和 Y Y Y完全不重合时,即 Y ∩ X = ∅ Y \cap X = \varnothing Y∩X=∅,我们称 X → Y X \rightarrow Y X→Y是 Complete nontrivial FD

(3) 属性的闭包(Closure of Attributes)

给定许多依赖 S S S,和属性集 X X X

设集合 s e t = X set = X set=X

重复以下步骤直到 s e t set set不发生改变:

如果有 A → B A \rightarrow B A→B并且 A A A在 s e t set set当中,那么 s e t = s e t ∪ B set = set \cup B set=set∪B

最后得到的 s e t set set成为 X X X在 S S S上的闭包(Closure),记作 X + X^+ X+

讲人话,闭包就是已知许多依赖 S S S,确定了 X X X后,能够确定的所有属性

1.2 部分依赖

X → Y X \rightarrow Y X→Y,取 X X X的一子集 X ′ X' X′,若 X ′ → Y X' \rightarrow Y X′→Y,则称 Y Y Y部分依赖于 X X X

讲人话就是确定了 X X X中一部分值就能确定了 Y Y Y ,称 Y Y Y部分依赖于 X X X

1.3 传递依赖

X → Y X \rightarrow Y X→Y,并且 Y → Z Y \rightarrow Z Y→Z,并且 Y ↛ X Y \nrightarrow X Y↛X,则称 Z Z Z传递依赖于 X X X

讲人话就是确定了 X X X能确定 Y Y Y,确定了 Y Y Y又能确定 Z Z Z ,并且确定了 Y Y Y不能确定 X X X (在范式比较中会提到为什么这么定义),就说 Z Z Z传递依赖于 X X X

1.4 多值依赖(Multivalued Dependencies, or MVD)

Z = U − X − Y Z = U - X - Y Z=U−X−Y,即 Z Z Z为属性集 U U U中除了 X X X和 Y Y Y的剩余所有属性

(1) 定义

∀ t 1 , t 2 ∈ R \forall t_1, t_2 \in R ∀t1,t2∈R,如果 t 1 X = t 2 X t_1X = t_2X t1X=t2X,则 ∃ v ∈ R \exists v \in R ∃v∈R,使得 v X = t 1 X = t 2 X vX = t_1X = t_2X vX=t1X=t2X,并且 v Y = t 1 Y vY = t_1Y vY=t1Y,并且 v Z = t 2 Z vZ = t_2Z vZ=t2Z,则称 Y Y Y多值依赖 X X X

讲人话就是,如果有 ( x , y 1 , z 1 ) (x, y_1, z_1) (x,y1,z1)和 ( x , y 1 , z 2 ) (x, y_1, z_2) (x,y1,z2),则必有 ( x , y 1 , z 2 ) (x, y_1, z_2) (x,y1,z2)和 ( x , y 2 , z 1 ) (x, y_2, z_1) (x,y2,z1)(Y和Z是对称的),则称 Y Y Y多值依赖 X X X,记作 Y ↠ X Y \twoheadrightarrow X Y↠X

也就是说,确定了 X X X为 x x x时, Y Y Y和 Z Z Z会有很多种取值 y 1 , y 2 , . . . , y m y_1, y_2, ..., y_m y1,y2,...,ym和 z 1 , z 2 , . . . , z n z_1, z_2, ..., z_n z1,z2,...,zn, Y Y Y和 Z Z Z的取值的所有组合都会出现

从定义中,我们可以看出,判断 Y Y Y是否多值依赖 X X X,还需要考虑全属性集 U U U。也就是说,同样的属性集 Y Y Y和 X X X,在不同的全属性集 U U U中,它们可能多值依赖的关系不同。

(2) Trivial or Nontrivial

  1. Trivial MVD:当 X ∪ Y = U X \cup Y = U X∪Y=U或 Y ⊆ X Y \subseteq X Y⊆X时,称 X ↠ Y X \twoheadrightarrow Y X↠Y为 Trivial MVD。

如果有 ( x , y 1 , z 1 ) (x, y_1, z_1) (x,y1,z1)和 ( x , y 2 , z 2 ) (x, y_2, z_2) (x,y2,z2)

X ∪ Y = U X \cup Y = U X∪Y=U时, Z = ∅ Z = \varnothing Z=∅,得 z 1 = z 2 = N U L L z_1 = z_2 = NULL z1=z2=NULL。那么 ( x , y 1 , z 2 ) = ( x , y 1 , N U L L ) (x, y_1, z_2) = (x, y_1, NULL) (x,y1,z2)=(x,y1,NULL), ( x , y 2 , z 1 ) = ( x , y 2 , N U L L ) (x, y_2, z_1) = (x, y_2, NULL) (x,y2,z1)=(x,y2,NULL)已经在表中,自行满足了多值依赖的条件,

Y ⊆ X Y \subseteq X Y⊆X时,有 X → Y X \rightarrow Y X→Y,得 y 1 = y 2 y_1 = y_2 y1=y2。那么 ( x , y 1 , z 2 ) = ( x , y 2 , z 2 ) (x, y_1, z_2) = (x, y_2, z_2) (x,y1,z2)=(x,y2,z2), ( x , y 2 , z 1 ) = ( x , y 1 , z 1 ) (x, y_2, z_1) = (x, y_1, z_1) (x,y2,z1)=(x,y1,z1)已经在表中自行满足了多值依赖的条件

所以满足以上其中一种条件的多值依赖不能传递更多的信息,可称为Trivial MVD

  1. Nontrivial MVD:当 Y Y Y和 X X X不满足以上条件,则称 X ↠ Y X \twoheadrightarrow Y X↠Y为Nontrivial MVD

2. 分解关系模式(Decompostion of Relational Schema)

2.1 分解的原则

将关系 R ( U ) R(U) R(U)分解为 R 1 ( U 1 ) R_1(U_1) R1(U1)和 R 2 ( U 2 ) R_2(U_2) R2(U2)后,应当满足:

  1. U 1 ∪ U 2 = U U_1 \cup U_2 = U U1∪U2=U
  2. R 1 ⋈ R 2 = R R_1 \bowtie R_2 = R R1⋈R2=R (无损连接性)

实际上满足第二条就会满足第一条(小声

"Good" Decomposition,也就是一个好的分解,应当满足无损连接性 (能通过自然连接得到原始表)和依赖保留性(能在每个表中直接得到原来的所有依赖),详见前言中的参考资料

2.2 BCNF分解

(1) BCNF的定义

注意:在实际情况中,可能不止有一组元素能够作为主键,比如 X + = U X^+ = U X+=U, Y + = U Y^+ = U Y+=U,那么称 X X X和 Y Y Y都为超键 ,去掉超键中任意属性会使其不再为超键的,叫做候选键 ,我们可以在多个候选键中选一个叫主键

假设 X X X和 Y Y Y都是候选键, X ∪ Y X \cup Y X∪Y也就是 X X X和 Y Y Y中的所有元素都称作主属性。而不是只有我们选定的主键中的元素才叫做主属性

R R R中任一nontrivial FD X → Y X \rightarrow Y X→Y, X X X都是候选键的超集,那么就称 R R R满足 鲍依斯-科得范式(Boyce Codd Normal Form, or BCNF)

(2) BCNF分解算法

找到 R R R中的候选键

重复以下步骤直到所有的关系都满足BCNF:

  1. 关系 R ′ R' R′的依赖 A → B A \rightarrow B A→B不满足BCNF
  2. R ′ R' R′ 分解为 R 1 = ( A , B ) R_1 = (A, B) R1=(A,B)和 R 2 ( A , r e s t ) R_2(A, rest) R2(A,rest), r e s t rest rest为 A A A和 B B B之外的剩余部分
  3. 找到 R 1 R_1 R1和 R 2 R_2 R2中的FD和候选键

2.3 4NF分解

(1) 4NF的定义

R R R中任一nontrivial MVD X ↠ Y X \twoheadrightarrow Y X↠Y, X X X都是候选键的超集,那么就称 R R R满足4NF

(2) 4NF分解算法

找到 R R R中的候选键

重复以下步骤直到所有的关系都满足4NF:

  1. 关系 R ′ R' R′的依赖 A ↠ B A \twoheadrightarrow B A↠B不满足4NF
  2. R ′ R' R′ 分解为 R 1 = ( A , B ) R_1 = (A, B) R1=(A,B)和 R 2 ( A , r e s t ) R_2(A, rest) R2(A,rest), r e s t rest rest为 A A A和 B B B之外的剩余部分
  3. 找到 R 1 R_1 R1和 R 2 R_2 R2中的MVD和候选键

3. 范式之间的比较

3.1 每一层范式解决的问题

  • 1NF:每个元组的每个属性的值不能是集合,不可再分关系。1NF是 R R R作为关系模型的最基本的条件
  • 2NF:在1NF的基础上消除了非主属性对候选键的部分依赖,也就是非主属性不能只依赖于一部分主属性,应该完全依赖于所有主属性。
  • 3NF:在2NF的基础上消除了非主属性对候选键的传递依赖。也就是非主属性不能依赖于其他非主属性,应该直接完全依赖于所有主属性。

前面我们讲到了传递依赖的定义:

X → Y X \rightarrow Y X→Y,并且 Y → Z Y \rightarrow Z Y→Z,并且 Y ↛ X Y \nrightarrow X Y↛X,则称 Z Z Z传递依赖于 X X X

这里要求 Y ↛ X Y \nrightarrow X Y↛X是因为,如果 Y → X Y \rightarrow X Y→X,那么 Z Z Z部分依赖于 Y Y Y,而部分依赖已经在2NF中消除了。
3NF究竟还遗留了哪些问题?

我们现在只解决了主属性和非主属性之间的冗余,而BCNF希望解决多个候选键之间,也就是主属性之间的冗余。

当然,如果关系中只有一个候选键,那么3NF和BCNF其实没什么区别。要举出有多个后续键的例子比较困难,所以很难区分喵qwq

  • BCNF:在3NF的基础上消除了候选键之间的部分依赖和传递依赖

至此,我们已经解决的冗余都是针对依赖关系而言,而依赖是一对一的。

倘若我们有 X ↠ Y X \twoheadrightarrow Y X↠Y,剩余部分为 Z Z Z,其中 X X X对 Y Y Y是1对m, X X X对 Z Z Z是1对n,他们的组合就有 m × n m \times n m×n个元组,而实际上用两个表 R 1 R_1 R1和 R 2 R_2 R2共 m + n m + n m+n个元组就能表示这两个一对多的关系,而且 R 1 ⋈ R 2 = R R_1 \bowtie R_2 = R R1⋈R2=R也符合分解的原则。

  • 4NF:在BCNF的基础上消除了nontrivial MVD

3.2 BCNF和4NF的不足

BCNF和4NF会对所有FD和MVD做检查和分解,当分解出来的表的属性过少时,我们需要对多个表做自然连接才能验证我们原来的FD和MVD,对查询不是很友好,所以应该尽量先选择能保留更多属性的分解。然后具体问题具体分析,权衡好查询负载(Query Workload)和过分解(Over Decomposition)之间的关系。

二、XML的查询

1. XPath

视频中关于XPath的语法都能在这里找到:XPath 教程 | 菜鸟教程 (runoob.com)

主要列举一些示例方便快速复习:

xpath 复制代码
// 谓语(Predicates):将用于查找某些特定节点的条件嵌入到方括号[]中,将其称之为谓语
// 查询价格小于90且存在作者的姓是Ullman的一本书
// 注意:[]中的条件只针对存在
doc("BookstoreQ.xml")/Bookstore/Book[@Price < 90 and
    Authors/Author/Last_Name ="Ullman" ]/Title  
xpath 复制代码
// 内置函数(Built-in Functions)
// 查询Remark属性中包含"great"的书
doc("BookstoreQ.xml")//Book[contains(Remark, "great" )]/Title
xpath 复制代码
// self join
doc("BookstoreQ.xml")//Magazine[Title
    doc("BookstoreQ.xml")//Book/Title]
xpath 复制代码
// axes(轴)
// 查询所有父节点不为Bookstore和不为Book的节点
doc("BookstoreQ.xml")/Bookstore//*[name(parent::*)!="Bookstore"
    and name(parent::*)!="Book"]
// 查询所有跟同层级节点有相同Title的Book或Magzine
doc("BookstoreQ.xml")/Bookstore/(Book|Magazine)[Title = 
    following-sibling::*/Title or Title = preceding-sibling::*/Title]
xpath 复制代码
由于谓语只能表示"存在"(exists)关系,当我们想表示"任意"(forall)时,需要使用内置函数count
// 查询所有作者的First_Name都包含'J'的书
doc("BookstoreQ.xml")//Book[
    count(Authors/Author[contains(First_Name,"J")]) = 
    count(Authors/Author/First_Name)]

2. XQuery

视频中大多数的语法能在这里找到:XQuery 教程 | 菜鸟教程 (runoob.com)

内置函数需要在XPath中查询:XPath、XQuery 以及 XSLT 函数 | 菜鸟教程 (runoob.com)

限定表达式等在上述链接找不到,可以在这里看:限定表达式 (XQuery) - SQL Server | Microsoft Learn

2.1 FLWOR表达式

xquery 复制代码
For $var in expr
Let $var := expr
Where condition
Order by expr
Return expr

2.2 代码示例

xquery 复制代码
// 查询价格小于90且存在作者的姓是Ullman的一本书
for $b in doc("BookstoreQ.xml")/Bookstore/Book
where $b/@Price < 90 
 and $b/Authors/Author/Last_Name = "Ullman"
return $b/Title
xquery 复制代码
for $b in doc("BookstoreQ.xml")/Bookstore/Book

// 限定表达式 ( some | every ) <variable> in <Expression> (,...) satisfies <Expression>  
// some表示"存在"  every表示"任意"
// 查询Title中存在作者的First_Name的Book
where some $fn in $b/Authors/Author/First_Name satisfies
    contains($b/Title, $fn)
    
// 构造返回结果    
return <Book>
        { $b/Title }
        { $b/Authors/Author/First_Name }
    </Book>
xquery 复制代码
// 聚合函数
// 查询所有Book的Price的平均值
<Average>
{ let $plist := doc("BookstoreQ.xml")/Bookstore/Book/@Price
    return avg($plist)}
</Average>
xquery 复制代码
for $b in doc("BookstoreQ.xml")/Bookstore/Book
order by $b/@Price
return <Book>
         { $b/Title }
         <Price>{ $b/data(@Price))</Price>
       </Book>
xquery 复制代码
// 过滤重复值
// distinct-values返回 值的列表,而不是 节点的列表
for $n in distinct-values(doc("Bookstore0.xml" )//Last_Name)
return <Last_Name> {$n} </Last_Name>

3. XSLT(EXtensible Stylesheet Language)

XSLT支持将XML转换为其他文档,比如XHTML。对XML的转换也可以看作是查询和构造结果

示例如下:

xml 复制代码
<xsl:stylesheet version="2.0" xmins:xsl="http://mmr.w3.org/1999/XSl/Transform"
<xsl:output method="xml" indent="yes" onit-xml-declaration-"yes" />
//外层是基本格式

// template + match匹配特定节点
<xsl:template match="Book">
<BookTitle>
    // 选择特定节点中的子节点并构造返回结果
    <xsl:value-of select="Title"/></BookTitle>
</xsl:template>

<xsl:template match="Magazine">
    <MagazineTitle> <xsl:value-of select="Title" /> </MagazineTitle>
</xsl:template>

</xsl:stylesheet>
xml 复制代码
// 不等号需要使用转义 小于号:$lt;  大于号$gt;
// copy-of + select返回选择到的节点
<xsl:template match="Book[@Price &lt; 90]">
    <xsl:copy-of select="." />
<xsl:template>

// 不满足所有匹配的节点和属性会成串返回,因此得作以下处理
<xsl:template match="text()" />

// 更加具体的限定条件所构造的匹配,优先度更高
// 当节点同时满足两个优先度相同的匹配规则时(最好不要,会报错),以最后一个匹配规则为结果
xml 复制代码
// apply-templates + select 将 template + select 的结果嵌入其中
<xsl:template match="*|@*|text()"
    <xsl:copy>
        <xsl:apply-templates select="*|@*|text()/>
    </xsl:copy>
</xsl:template>
xml 复制代码
<xsl:template match="/"> 
<html> 
    <body> 
    <h2>My CD Collection</h2> 
    <table border="1"> 
        <tr bgcolor="#9acd32"> 
            <th>Title</th> 
            <th>Artist</th>
            <th>Price</th> 
        </tr> 
        // for-each + select 遍历选择到的所有节点
        <xsl:for-each select="catalog/cd"> 
            // if + test 选择满足条件的节点
            <xsl:if test="price &gt; 10"> 
                <tr>
                    <td><xsl:value-of select="title"/></td>
                    <td><xsl:value-of select="artist"/></td>
                    <td><xsl:value-of select="price"/></td> 
                </tr> 
            </xsl:if> 
        </xsl:for-each> 
    </table> 
    </body> 
</html> 
</xsl:template>

三、统一建模语言(UML)

UML用图形化的表示方法描述对数据模型作建模,可以直接翻译为关系模型

1. 类(Classes)

关系模型中的每一个表可以描述为一个了类,如

Student(sID, sName, GPA)

可以与下述模型互相转换:

plaintext 复制代码
+-----------+
|  Student  |
+-----------+
|   sID pk  |
|   sName   |
|    GPA    |
+-----------+
| <methods> |     
+-----------+

2. 关联 和 关联类(Associations and Association Classes)

一个类跟另一个类有联系,即有关联,可以有一条线将两个类相连来表示,而关联所产生的附加信息我们可以用一个关联类表示,如:

plaintext 复制代码
+-------+               +-------+  
|   C1  |  Association  |   C2  |
+-------+-------+-------+-------+
|   A1  |       |       |   A2  |
+-------+       |       +-------+
                |
             +--+----+ 
             |  C3   |
             +-------+
             |  A3   | 
             +-------+             

其中C1和C2关联到对方的数量可能不同,比如一个学生只能选一个专业,记为1..1,一个专业有至少一个学生修读,记为1..*,如下:

plaintext 复制代码
+-------+               +-------+  
|   C1  |  Association  |   C2  |
+-------+-------+-------+-------+
|   A1  |1..*   |   1..1|   A2  |
+-------+       |       +-------+
                |
             +--+----+ 
             |  C3   |
             +-------+
             |  A3   | 
             +-------+             

实际上,如果对应的数量是0..1或者1..1,那么关联表是多余的,可以将关联的属性归到C1中,如下:

plaintext 复制代码
+-------+               +-------+  
|   C1  |  Association  |   C2  |
+-------+-------+-------+-------+
|   A1  |1..*       1..1|   A2  |
|   A3  |               +-------+
+-------+                                      

3. 子类(Subclasses)

一个父类可以有很多个子类,子类拥有父类的主键和额外的属性或关联,如下:

plaintext 复制代码
            +------+
            |  C1  |
            +------+
            |  K pk|
            |  A1  |
            +--+---+
               |
 +-------------+------------+
 |             |            |
 |             |            |
+--+--+    +--+--+         +-------+               +-------+  
| C2  |    |  C3 |         |   C4  |  Association  |   C5  |
+-----+    +-----+         +-------+---------------+-------+
| A2  |    |  A3 |         |   A4  |               |   A5  |
+-----+    +-----+         +-------+               +-------+ 

不完整/完整(incomplete /complete):

当子类能够表示所有的情况时,我们说这些子类是complete的,否则则是incomplete的

重叠/不相交 (overlapping /disjoint):

当有对象能够同时属于多个子类时,我们说这些子类是overlapping的,否则则是disjoint的

将带子类的UML翻译为关系模型有多种办法:

  1. 父类建表,每一个子类就是一个表,只包含子类的属性和父类的主键,适用于disjoint + incomplete的情况
  2. 父类可不建表,每一个子类就是一个表,它不仅包含子类的属性和父类的主键,也包含父类的属性,适用于disjoint + complete的情况
  3. 用一个表包含父类和所有子类的属性:适用于heavily overlapping的情况
  1. Subclass relations contain superclass key+ specialized attrs
  2. Subclass relations contain all attributes
  3. One relation containing all superclass + subclass attrs.

4. 组合和聚合(Composition and Aggregation)

组合和聚合都是关联的特例,强调整体和部分的关系,在转换为关系模型时跟关联没有区别,但是在UML中的描述存在语义上的区别。

组合中的整体和部分具有强依赖,整体的对象负责部分的对象的生命周期,如鸟和翅膀

而聚合的整体和部分可以独立存在,如汽车和轮胎,部门和员工

详见前言中的参考资料。

相关推荐
憧憬成为web高手10 分钟前
皮卡丘靶场速通--sql 2
数据库·sql·mybatis
段一凡-华北理工大学23 分钟前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
oradh2 小时前
Oracle XTTS实现跨版本迁移和升级(Oracle 11g单库升级至19C RAC集群)
数据库·oracle·11g升级19c·xtts跨版本迁移和升级
z123456789863 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
程序猿DD3 小时前
一个 API Key,统一调用大模型、生图和联网搜索
数据库·网关
TlSfoward4 小时前
抓包代理链路下的 TLS 指纹变化分析 TLSFOWARD抓包工具
数据库·爬虫·网络协议·搜索引擎·php
数智化管理手记4 小时前
账龄分析手工统计易遗漏?自动账龄分析工具怎么搭建
大数据·网络·数据库·人工智能·数据挖掘
LabVIEW开发5 小时前
NI Package Manager安装LabVIEW时InternalServerError错误
网络·数据库·labview·labview知识·labview功能·labview程序
SelectDB5 小时前
PostgreSQL 实时同步到 Apache Doris:一站式 CDC 解决方案
数据库
欲速不达88205 小时前
Mysql并发DML锁等待的优化
数据库·mysql