《锋利的SQL(第2版)》——1.2 SQL的理论基础

简介:

本节书摘来自异步社区出版社《锋利的SQL(第2版)》一书中的第1章,第1.节,作者:张洪举 王晓文,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.2 SQL的理论基础

锋利的SQL(第2版)
E. F. Codd博士提出的关系数据库管理系统模型基于两个数学分支:集合理论和谓词逻辑。理解集合理论,对于构建数据库结构,减少数据冗余,保证数据一致性方面具有重要意义。所以,即使你是一个资深的DBA,也建议你重温本节内容。

1.2.1 集合理论

集合理论(集合论)是由数学家Georg Cantor创建的,这是一个基于关系模型的数学分支。Cantor的集合定义如下:

任意集合体M是我们感知或想到的,能够确定的互异对象m(称之为M的元素)的整体。

——Joseph W. Dauben 和Georg Cantor(普林斯顿大学出版社,1990)
看似简短的一句话,但是定义中的每个字都有着深刻和重要的意义。一个“集合”应将其视为单个实体,你的焦点应该放在对象的集合上,而不是组成集合的单个对象上。例如,当你对数据库中的雇员表编写查询时,应该将雇员的集合看作一个整体,而不是单个的雇员。这听起来可能并不重要并且很简单,但是很多程序员没有这种思维方式。

“互异”的含义是指集合中的每个元素必须是唯一的。对于数据库中的表,我们可以通过定义键约束来强制表中行的唯一性。没有键的话,就不能唯一地标识行,这样的表也就不能称之为“集合”,只能将其看作一个多重集合或一个无序的单位组。

“对象”可以是汽车或雇员这样的物理对象,也可以是抽象对象,如质数或线条。

“我们感知或想到的”这句话意味着集合的定义是主观的。例如,在教室中,“人”可以被认定为是“学生”的集合,也可以是“教师”的集合。因此,在定义集合方面你具有很大的自由度。在为数据库设计数据模型时,设计过程应仔细考虑应用程序的主观需求,从而为相关实体确定恰当的定义。

需要注意的是,Cantor的集合定义省略掉的内容同样重要。定义中没有提到集合元素间的任何顺序,集合元素的列出顺序并不重要。因为与顺序无关,{b, a, c}与{b, c, a}表示的是同一集合。对于属性(SQL中称之为列)集合,它们组成了关系(SQL中称之为表)的表头,元素应该是按名称标识,而不是按顺序位置标识。

同样,对于元组(SQL中称之为行)而言,它们构成了关系的主体,元素由其键值进行标识,而不是按位置标识。许多程序员很难适应这种观念,对于查询表而言,行之间没有顺序。换句话说,对表的查询可以按任意顺序返回表中的行,除非你基于特定展现目的,明确要求数据以特定的方式进行排序。

1.2.2 谓词逻辑

谓词逻辑的渊源可追溯到古希腊,是基于关系模型的另一个数学分支。谓词是一个属性或是一个表示“持有”或“不持有”的表达式,换句话说,也就是“真”或“假”。关系模型就是依靠谓词来维护数据的逻辑完整性并定义其结构的。例如,在一个名为Employees的表中定义了约束,仅允许工资(Salary)大于0的雇员存储在表中。谓词是“工资大于0”(T-SQL表达式:salary > 0)。

当通过筛选数据来界定子集等操作时,也可以使用谓词。例如,如果需要查询Employees表并要求只返回销售部门的雇员行时,可以在查询筛选器中使用谓词“部门(Department)等于销售(Sales)”(SQL表达式:department = 'sales')。

在集合理论中,可以使用谓词定义集合,这是非常有用的,因为不能总是通过列出所有元素来定义集合(例如,无限集合),通过特征定义集合往往更加方便简洁。例如,这是使用谓词定义无限集合的例子:所有质数集合的谓词定义是——x是一个仅能被1和自身整除的大于1的正整数。对于任意指定值,谓词可能为“真”,也可能为“假”,而全部质数的集合是谓词为“真”的所有元素的集合。例如,这是一个使用谓词定义有限集合的例子,集合{0,1,2,3,4,5,6,7,8,9}可以被定义为下面谓词为“真”的所有元素的集合——x是一个大于或等于0且小于或等于9的整数。

1.2.3 关系模型

前面提过,关系模型是基于集合理论和谓词逻辑进行数据管理和操作的语义模型,它涉及命题、谓词、关系、元组和属性等概念。关系模型的目标是确保数据的一致性表示,最小化或是没有冗余且不牺牲完整性,并将定义数据的完整性(强制数据一致性)作为模型的一部分。RDBMS应实施关系模型并提供方法来存储、管理、实施完整性和查询数据。

1.命题、谓词和关系
很多人认为“关系”是指表之间的关系,这是不正确的。在数学的集合理论中,关系是集合的表现形式。在关系模型中,关系是相关信息的集合,与SQL中相对应的就是一个表——尽管不能完全对应。关系模型中的一个关键点是,单个的关系应代表一个单个集合(如客户)。需要注意的是,对多个关系操作(例如,两个关系之间的联接)的结果也是一个关系。

关系是由表头和主体组成的。表头包含一组属性(SQL中称之为列),其中每个元素由一个属性名称和类型名称标识。主体包含一个元组(SQL中称之为行)集合,其中每个元素都由键标识。为了简单起见,将表称之为行集。

当为数据库设计数据模型时,要使用关系(表)来表示所有数据。首先要确定需要在数据库中表示的命题。命题应当是一个断定或必须为“真”或“假”的语句。例如,语句“雇员 A出生于1971年2月12日,在IT部门工作”是一个命题,如果这是一个真命题,它将表现为Employees(雇员)表中的一个行,如果是假命题,则根本不会出现。这个假设被称为“封闭世界假设”(close world assumption,CWA)。

下一步是将命题形式化,即取出实际数据(关系的主体)并定义结构(关系的表头)。可以以参数化命题方式思考谓词,关系的表头包含一个属性集合。属性由属性名称和类型名称进行标识,例如,一个Employees(雇员)关系的表头可能包含下列属性(属性名称和类型名称以成对方式出现):employeeid 整型、firstname 字符串型、lastname字符串型、birthdate 日期型、departmentid整型。

类型是关系最基本的构造块,它约束了属性是一个可能或有效值的确定集合。例如,INT类型是范围自–2 147 483 648至2 147 483 647所有整数的集合。类型是数据库中谓词的最简单形式之一,因为它限制了该属性的允许值。例如,数据库不会接受一个雇员的出生日期为1971年2月31日的命题(更不用提像“abc”这样的生日)。注意,类型不受像整型或字符串型等基本类型的限制,它也可以是可能值的枚举,例如枚举可能的工作岗位。

2.缺失值
关系模型的一个方面是对于“是否谓词应限制于二值逻辑”的激情辩论。也就是说,在二值谓词逻辑中谓词是“真”或“假”。 如果谓词不是“真”,那肯定是“假”。不过,也有人说具有三值(甚至四值)谓词逻辑空间,例如,像账号缺失这种情况。对于谓词,涉及缺失值就会出现既不是“真”也不是“假”的问题——因为它是未知的。例如,一个Employees(雇员)关系的手机属性,假设某些雇员的手机号码丢失了,怎么把这一事实表示在数据库中?这要使用三值逻辑实现,手机属性应当允许有一个代表缺失值的特定标记。然后,在这种缺失值情况下,将该手机属性与一些指定数字比较,谓词也将产生未知。三值谓词逻辑是指来自谓词结果的3种可能逻辑值——“真” “假”和“未知”(true、false和unknown)。

SQL通过支持NULL标记实现了三值谓词逻辑,以表示缺失值的通用概念。SQL中对NULL和三值谓词逻辑的支持是造成极大混乱和复杂性的根源,一些资深的DBA在对故障查询语句进行分析时,费尽周折却发现是数据中存在NULL值导致的。当然,最好的方法是使用二值谓词逻辑,这是不会造成问题的,但是在实际工作中,你会发现这很难。尤其是对一些现有数据系统改造时,数据质量很差,你只能是尽可能地规范这些数据,而无法将其完全规范到二值逻辑中。

3.约束
关系模型的最大好处是能够把定义数据的完整性作为模型的一部分。数据完整性通过在数据模型中定义的约束规则实现,并由RDBMS实施。实施完整性的最简单方式是指定属性类型的nullability(是否支持或不支持NULL标记)标志。约束也可以通过模型自身实施,例如,限定关系Orders(orderid, orderdate, duedate, shipdate) 中每笔订单有3个互异日期,关系Employees(empid) 与EmployeeChildren(empid, childname)允许每个雇员有0或多个子集。

约束的其他例子还包括提供实体完整性的候选键和提供引用完整性的外键。候选键是定义了一个或多个属性的键,防止关系中出现多个相同的元组(SQL中的行),基于候选键的谓词可以唯一地标识行(如雇员)。你可以在关系中定义多个候选键,例如,在Employees关系中,可以在employeeid、SSN(社会安全号码)等属性上定义候选键。通常,可以任意选择一个候选键作为主键(例如,Employees关系中的employeeid),并作为标识行的首选方式。其他的所有候选键称为备用键。

外键用于强制引用完整性。外键定义了关系的一个或多个属性(称为引用关系)引用另一个关系(或同一关系)的候选键,此约束限定了引用关系的外键属性中的值,应是出现在被引用关系(父表)的候选键属性中的值。例如,假设Employees关系具有一个定义在departmentid属性上的外键,它引用Departments关系中的主键属性departmentid,这意味着Employees.departmentid中的值会出现在Departments.departmentid中的值。

4.规范化
关系模型还定义了规范化规则(也称为范式),用于确保每个实体都由单一关系表示。在规范化的数据库中,要在数据修改过程中避免异常,并在不牺牲完整性的情况下保持最低限度冗余。下面简要介绍一下由Codd提出的前3个范式(1NF、2NF和3NF)。

(1)1NF

第一范式是说关系(表)中的元组(行)必须是唯一的,并且属性是原子化的。也就是说,如果表正确地表示了关系,它已经符合了第一范式。

通过为表定义一个唯一键就可以实现唯一行。

你只能执行属性类型所定义的操作,我们知道,属性的原子性是主观的,这与集合的定义是主观的一样。例如,Employees关系中雇员姓名应当使用1个(fullname)、2个(firstname和lastname)还是3个(firstname、middlename和lastname)属性表示呢?答案取决于应用程序。如果应用程序需要分别处理雇员的姓名部分(如处于搜索目的),则有必要把它们分开,否则,则不需要。

同样,基于应用程序的需求,属性可能不被完全原子化,也有可能被亚原子化。例如,如果地址属性被作为一个特定应用程序的原子,不将“城市”作为地址的一部分会违反第一范式。

(2)2NF

第二范式涉及两个规则。一个规则是数据必须满足第一范式,另一个规则提及非键属性和候选键属性之间的关系。对于每个候选键,每个非键属性必须是对整个候选键的完全函数依赖。也就是说,如果要获取任何非键属性值,需要提供相同元组中候选键的所有属性的值;如果知道候选键的所有属性的值,就可以检索到任何元组的任何属性的任何值。

下面是一个违反第二范式的例子,假设定义了一个名为Orders的关系,表示订单和订单行的信息,如图1-1所示。Orders关系包含下列属性:orderid、productid、 orderdate、qty、customerid和companyname。主键定义为orderid和productid。

image

图1-1中违反了第二范式,因为有非键属性仅依赖于候选键(即该示例的主键)的一部分。例如,你可以仅通过orderid找到订单的orderdate,以及customerid和companyname。要符合第二范式,需要将原来的关系拆分为两个关系,即Orders和OrderDetails,如图1-2所示。Orders关系将包括orderid、orderdate、customerid和companyname属性,主键定义为orderid。OrderDetails关系将包括orderid、productid和qty,主键定义为orderid和productid。

image

(3)3NF

第三范式也有两个规则。数据必须满足第二范式,同时,所有非键属性必须依赖于非传递的候选键。通俗地讲,该规则的意思是所有非键属性必须相互独立。换句话说,一个非键属性不能依赖于另一个非键属性。

先前所述的Orders和OrderDetails关系现在已经符合第二范式。请记住,此时的Orders关系包含orderid、orderdate、customerid和companyname属性,主键定义为orderid。customerid和companyname均依赖于主键——orderid。例如,你需要通过orderid主键来查找代表订单中客户的customerid,同样,你需要通过orderid主键查找订单中客户的公司名称(companyname)。然而,customerid和companyname也是互相依靠的。为满足第三范式,需要添加包含customerid(作为主键)和companyname的Customers关系,如图1-3所示,然后就可以从Orders关系中删除companyname属性。

image

通俗地讲,2NF和3NF通常以这句话概括:“每个非键属性依赖于键,依赖于整个键,并且除了键别无他物”。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关文章
|
4月前
|
SQL Oracle 关系型数据库
每天一道大厂SQL题【Day07】教育领域SQL实战
每天一道大厂SQL题【Day07】教育领域SQL实战
25 0
|
SQL Oracle 关系型数据库
SQLServer SQL连接查询深度探险(摘录 )
SQLServer SQL连接查询深度探险(摘录)
84 0
|
SQL Oracle Java
【SQL开发实战技巧】系列(三):SQL排序的那些事
如何以指定的单列或多列顺序返回查询结果、通过translate函数替换字符串、如何根据数字和字母混合字符串中的字母排序以及空值排序。【SQL开发实战技巧】这一系列博主当作复习旧知识来进行写作,毕竟SQL开发在数据分析场景非常重要且基础,面试也会经常问SQL开发和调优经验,相信当我写完这一系列文章,也能再有所收获,未来面对SQL面试也能游刃有余~。不早了,零点十分了,又是一篇SQL基础文章,继续加油!温故而知新~
【SQL开发实战技巧】系列(三):SQL排序的那些事
|
SQL 存储 数据库
一个反直觉的sql
一个反直觉的sql
一个反直觉的sql
|
SQL 关系型数据库 MySQL
SQL练习一(Datawhale系列)
datawhale mysql练习系列
1609 0
|
SQL 数据库 索引