设计得当的数据库可以让您访问最新、准确的信息。 由于正确的设计对于实现使用数据库的目标至关重要,因此投入学习良好设计原则所需的时间是有意义的。 最后,您更有可能最终获得一个满足您的需求并且可以轻松适应变化的数据库。
本文提供桌面数据库规划指南。 您将学习如何决定您需要哪些信息,如何将这些信息划分为适当的表和列,以及这些表如何相互关联。 在创建第一个桌面数据库之前,应阅读本文。
本文内容
一些需要了解的数据库术语
Access 会将你的信息整理到 表中:行和列列表,让人联想到会计的笔记本或电子表格。 在简单的数据库中,可能只有一个表。 对于大多数数据库,您将需要多个数据库。 例如,您可能有一个表存储有关产品的信息,另一个表存储有关订单的信息,另一个表包含有关客户的信息。
更正确地说,每一行都称为 记录,每列都称为 字段。 记录是组合有关某事的信息的一种有意义且一致的方式。 字段是单个信息项,即出现在每条记录中的项类型。 例如,“产品”表中的每行(即每条记录)包含有关某种产品的信息。 每列(即每个字段)包含该有关产品的某类信息,例如其名称或价格。
什么是优秀数据库设计?
某些原则指导数据库设计过程。 第一个原则是重复信息 (也称为冗余数据) 是不好的,因为它会浪费空间并增加错误和不一致的可能性。 第二个原则是信息的正确性和完整性很重要。 如果数据库包含不正确的信息,则从数据库拉取信息的任何报表也将包含不正确的信息。 因此,您基于这些报告做出的任何决定都将被误导。
因此,一个好的数据库设计是这样的:
- 将您的信息划分为基于主题的表以减少冗余数据。
- 根据需要向 Access 提供将表中的信息联接在一起所需的信息。
- 帮助支持并确保信息的准确性和完整性。
- 满足数据处理和报告需求。
设计过程
设计过程包括以下步骤:
-
确定数据库的用途
这有助于为剩余步骤做好准备。 -
查找和组织所需的信息
收集您可能想要在数据库中记录的所有类型的信息,例如产品名称和订单号。 -
将信息划分为表格
将信息项划分为主要实体或主题,例如产品或订单。 然后每个主题都变成一个表。 -
将信息项转换为列
确定要在每个表中存储的信息。 每个项都成为一个字段,并在表中显示为一列。 例如,“员工”表可能包含“姓氏”和“雇用日期”等字段。 -
指定主键
选择每个表的主键。 主键是用于唯一标识每行的列。 示例可以是产品 ID 或订单 ID。 -
设置表关系
查看每个表,并确定一个表中的数据与其他表中的数据的关系。 根据需要向表添加字段或创建新表以阐明关系。 -
优化设计
分析设计中的错误。 创建表并添加一些示例数据记录。 查看是否可以从表中获取所需的结果。 根据需要对设计进行调整。 -
应用规范化规则
应用数据规范化规则以查看表的结构是否正确。 根据需要对表格进行调整。
确定数据库的用途
最好在纸上写下数据库的用途——它的目的、你期望如何使用它以及谁将使用它。 例如,对于一家家庭企业的小型数据库,您可以编写一些简单的内容,例如“客户数据库保留客户信息列表,用于生成邮件和报告”。如果数据库更复杂或由许多人使用(在公司环境中经常发生),则目的很容易是一个段落或更多段落,并且应包括每个人何时以及如何使用数据库。 这个想法是有一个完善的使命宣言,可以在整个设计过程中参考。 拥有这样的陈述可以帮助您在做出决定时专注于您的目标。
查找和组织所需信息
要查找和组织所需的信息,请从现有信息开始。 例如,您可以在分类帐中记录采购订单,或将纸质表单上的客户信息保存在文件柜中。 收集这些文档并列出显示的每种类型的信息 (例如,在表单) 上填写的每个框。 如果您没有任何现有表单,请想象您必须设计一个表单来记录客户信息。 你会在表单上填写哪些信息? 会创建哪些填充框? 标识并列出每个项目。 例如,假设您当前将客户列表保存在索引卡上。 检查这些卡可能会显示每张卡都包含客户姓名、地址、城市、州、邮政编码和电话号码。 其中每个项都代表表中的一个潜在列。
当您准备此列表时,不要担心一开始会让它变得完美。 相反,请列出每个想到的项目。 如果其他人将使用该数据库,也请征求他们的想法。 您可以稍后微调列表。
接下来,考虑您可能希望从数据库生成的报告或邮件的类型。 例如,您可能希望产品销售报表按区域显示销售额,或希望显示产品库存水平的库存汇总报表。 您可能还想生成表格信函以发送给宣布促销活动或提供溢价的客户。 在脑海中设计报告,并想象它会是什么样子。 你会在报表中包含哪些信息? 列出每个项目。 对表单和您预计创建的任何其他报告执行相同的操作。
考虑您可能想要创建的报告和邮件有助于您确定数据库中需要的项目。 例如,假设您让客户有机会选择加入或退出 () 定期电子邮件更新,并且您希望打印已选择加入的客户的列表。 要记录该信息,请在客户表中添加“发送电子邮件”列。 对于每个客户,您可以将字段设置为 是 或 否。
向客户发送电子邮件的要求建议了要记录的另一个项目。 一旦您知道客户想要接收电子邮件,您还需要知道要将其发送到的电子邮件地址。 因此,您需要为每个客户记录一个电子邮件地址。
构建每个报告或输出列表的原型并考虑生成报告需要哪些项目是很有意义的。 例如,当您检查一封表格信时,可能会想到一些事情。 如果要包含正确的称呼 - 例如,开始问候语的“先生”、“夫人”或“女士”字符串,则必须创建一个称呼项。 此外,您通常可能会以“亲爱的史密斯先生”开头,而不是“亲爱的。 西尔维斯特·史密斯先生“。 这表明您通常希望将姓氏与名字分开存储。
要记住的一个关键点是,您应该将每条信息分解为最小的有用部分。 对于姓名,为了使姓氏易于获得,您可以将名称分成两部分——名字和姓氏。 例如,要按姓氏对报表进行排序,单独存储客户的姓氏会很有帮助。 通常,如果要根据某项信息进行排序、搜索、计算或报告,则应将该项放在其自己的字段中。
想想你可能希望数据库回答的问题。 例如,您上个月完成了多少特色产品的销售? 您的 最佳客户 住在哪里? 谁是你们最畅销产品的供应商? 预测这些问题有助于你将其他记录项目归零。
收集此信息后,您就可以执行下一步了。
将信息划分为表
要将信息划分为表格,请选择主要实体或主题。 例如,在查找并组织产品销售数据库的信息之后,初步列表可能如下所示:
此处显示的主要实体是产品、供应商、客户和订单。 因此,从这四个表开始是有意义的:一个用于有关产品的事实,一个用于关于供应商的事实,一个用于关于客户的事实,一个用于关于订单的事实。 虽然这还不能完成列表,但这是一个很好的起点。 可以继续优化此列表,直到获得效果良好的设计。
首次查看初步项目列表时,你可能会想要将它们全部放在一个表中,而不是上图所示的四个表中。 您将在这里了解为什么这是一个坏主意。 请考虑一下此处显示的表格:
在这种情况下,每一行都包含有关产品及其供应商的信息。 由于您可以拥有来自同一供应商的许多产品,因此必须多次重复供应商名称和地址信息。 这很浪费磁盘空间。 在单独的供应商表中仅记录一次供应商信息,然后将该表链接到“产品”表,是一个更好的解决方案。
当您需要修改有关供应商的信息时,就会出现这种设计的第二个问题。 例如,假设您需要更改供应商的地址。 由于它在多处出现,因此可能出现在某处更改了地址却忘记在其他位置进行更改的意外情况。 仅在一个地方记录供应商的地址可以解决问题。
设计数据库时,请始终尝试只记录每个事实一次。 如果您发现自己在多个地方重复相同的信息,例如特定供应商的地址,请将该信息放在单独的表中。
最后,假设 Coho Winery 只供应一种产品,并且您想删除该产品,但保留供应商名称和地址信息。 如何在不丢失供应商信息的情况下删除产品记录? 不可能。 因为每条记录都包含有关产品的事实以及关于供应商的事实,所以你不能删除一个记录而不删除另一个记录。 若要将这些事实分开,必须将一个表拆分为两个:一个表用于产品信息,另一个表用于供应商信息。 删除产品记录应仅删除有关产品的事实,而不删除有关供应商的事实。
选择表格表示的主题后,该表中的列应仅存储有关该主题的事实。 例如,产品表应仅存储有关产品的事实。 因为供应商地址是关于供应商的事实,而不是关于产品的事实,所以它属于供应商表中。
将信息项转换为列
要确定表中的列,请确定您需要跟踪有关表中记录的主题的信息。 例如,对于“客户”表,“名称”、“地址”、“城邦邮政编码”、“发送电子邮件”、“称呼”和“电子邮件地址”构成了一个很好的起始列列表。 表中的每条记录都包含相同的列集,因此您可以存储每条记录的姓名、地址、城市-州-邮政编码、发送电子邮件、称呼和电子邮件地址信息。 例如,地址列包含客户的地址。 每条记录包含有关一个客户的数据,地址字段包含该客户的地址。
确定每个表的初始列集后,可以进一步优化列。 例如,将客户姓名存储为两个单独的列(名字和姓氏)是有意义的,这样您就可以仅对这些列进行排序、搜索和索引。 同样,地址实际上由五个单独的组件组成:地址、城市、州、邮政编码和国家/地区,将它们存储在单独的列中也是有意义的。 例如,如果要按状态执行搜索、筛选或排序操作,则需要将状态信息存储在单独的列中。
您还应该考虑数据库是否仅包含国内信息,还是国际信息。 例如,如果计划存储国际地址,最好使用“区域”列而不是“州”,因为此类列可以容纳国内州和其他国家/地区的区域。 同样,如果您要存储国际地址,邮政编码比邮政编码更有意义。
下表显示了用于确定列的一些提示。
-
不包含计算数据
在大多数情况下,不应将计算结果存储在表中。 相反,你可以在想要查看结果时让 Access 执行计算。 例如,假设有一个“订单产品”报表,该报表显示数据库中每个产品类别的订单量小计。 但是,任何表中都不存在“订单单位”小计列。 相反,“产品”表包括“订单单位”列,该列存储每个产品的订单单位。 每次打印报表时,Access 都会使用这些数据计算小计。 小计本身不应存储在表中。 -
将信息存储在其最小的逻辑部分中
你可能会想为全名或产品名称和产品描述设置一个字段。 如果将一个字段中的多种信息组合在一起,则以后很难检索单个事实。 尝试将信息分解成逻辑部分;例如,为名字和姓氏,或为产品名称、类别和描述创建单独的字段。
细化每个表中的数据列后,您就可以选择每个表的主键了。
指定主键
每个表应包含一列或一组列,以唯一标识表中存储的每一行。 这通常是唯一的标识号,例如员工 ID 号或序列号。 在数据库术语中,此信息称为表的 主键 。 Access 使用主键字段快速关联多个表中的数据,并将数据汇集在一起。
如果您已经具有表的唯一标识符(例如唯一标识目录中每个产品的产品编号),则可以将该标识符用作表的主键 - 但前提是此列中的值始终因每条记录而异。 主键中不能有重复的值。 例如,不要使用人的姓名作为主键,因为姓名不是唯一的。 您可以很容易地在同一个表中拥有两个同名的人。
主键必须始终具有值。 如果某列的值可能在某个时间点 (丢失值) 变为未分配或未知,则它不能用作主键中的组件。
应始终选择其值不会更改的主键。 在使用多个表的数据库中,表的主键可以用作其他表中的引用。 如果主键发生更改,则还必须在引用该键的所有位置应用该更改。 使用不会更改的主键可减少该主键与引用它的其他表不同步的可能性。
通常,任意唯一数字用作主键。 例如,您可以为每个订单分配一个唯一的订单编号。 订单编号的唯一用途是标识订单。 分配后,它永远不会更改。
如果没有想到可能成为良好主键的列或一组列,请考虑使用具有“自动编号”数据类型的列。 使用“自动编号”数据类型时,Access 会自动为你分配一个值。 这样的标识符是无事实的;它不包含描述它所表示的行的事实信息。 无事实标识符非常适合用作主键,因为它们不会更改。 包含有关某行的事实(例如电话号码或客户名称)的主键更有可能发生更改,因为事实信息本身可能会发生更改。
1. 设置为“自动编号”数据类型的列通常是一个很好的主键。 没有两个产品 ID 是相同的。
在某些情况下,可能需要使用两个或多个字段,它们一起提供表的主键。 例如,存储订单行项目的“订单明细”表将在其主键中使用两列:“订单 ID”和“产品 ID”。 主键采用多个列时,它也称为组合键。
对于产品销售数据库,可以为每个表创建“自动编号”列以用作主键:“产品”表的 ProductID,“订单”表的 “OrderID”,“客户”表的 CustomerID 和“供应商”表的 SupplierID。
创建表关系
现在,您已将信息划分到表格中,您需要一种以有意义的方式将信息再次组合在一起的方法。 例如,以下窗体包含来自多个表的信息。
1. 此窗体中的信息来自“客户”表...
2. ...“员工”表...
3. ...“订单”表...
4. ...“产品”表...
5. ...和“订单详细信息”表。
Access 是一个关系数据库管理系统。 在关系数据库中,您将信息划分为单独的、基于主题的表。 然后,您可以使用表关系根据需要将信息汇集在一起。
创建一对多关系
请考虑以下示例:产品订单数据库中的“供应商”和“产品”表。 供应商可以提供任意数量的产品。 因此,对于 Suppliers 表中表示的任何供应商,“Products”表中可以表示许多产品。 因此,“供应商”表和“产品”表之间的关系是一对多关系。
若要在数据库设计中表示一对多关系,请采用关系“一”侧的主键,并将其作为附加列或多列添加到关系“多”侧的表中。 例如,在这种情况下,将“供应商”表中的“供应商 ID”列添加到“产品”表中。 然后,Access 可以使用“产品”表中的供应商 ID 号查找每个产品的正确供应商。
“产品”表中的“供应商 ID”列称为外键。 外键是另一个表的主键。 “产品”表中的“供应商 ID”列是外键,因为它也是“供应商”表中的主键。
您可以通过建立主键和外键的配对为联接相关表提供基础。 如果您不确定哪些表应该共享公共列,则识别一对多关系可确保所涉及的两个表确实需要共享列。
创建多对多关系
请考虑“产品”表和“订单”表之间的关系。
单个订单中可以包含多个产品。 另一方面,一个产品可能出现在多个订单中。 因此,对于“订单”表中的每条记录,都可能与“产品”表中的多条记录对应。 对于 Products 表中的每个记录,Orders 表中可以有许多记录。 这种类型的关系称为多对多关系,因为对于任何产品,都可以有很多订单;对于任何订单,都可以有很多产品。 请注意,要检测表之间的多对多关系,必须考虑关系的双方。
这两个表的主题(订单和产品)具有多对多关系。 这带来了一个问题。 为了理解这个问题,请想象一下,如果您尝试通过将“产品 ID”字段添加到“订单”表来在两个表之间创建关系,会发生什么情况。 要使每个订单具有多个产品,每个订单需要在 Orders 表中多条记录。 您将为与单个订单相关的每一行重复订单信息,从而导致设计效率低下,从而导致数据不准确。 如果将“订单 ID”字段放在“产品”表中,也会遇到同样的问题 — “产品”表中会有针对每种产品的多个记录。 如何解决这个问题?
答案是创建第三个表(通常称为连接表),它将多对多关系分解为两个一对多关系。 将这两个表的主键都插入到第三个表中。 因此,第三个表记录了关系的每个匹配项或实例。
“订单明细”表中的每条记录代表订单上的一个行项。 Order Details 表的主键由两个字段组成 — Orders 表和 Products 表中的外键。 单独使用“订单 ID”字段不能用作此表的主键,因为一个订单可以有多个行项。 订单 ID 对于订单上的每个行项重复,因此该字段不包含唯一值。 单独使用“产品 ID”字段也不起作用,因为一个产品可以出现在许多不同的订单中。 但是,这两个字段始终为每条记录生成一个唯一的值。
在“产品销售”数据库中,“订单”表和“产品”表彼此并不直接相关。 相反,它们通过“订单明细”表间接关联。 订单和产品之间的多对多关系通过使用两个一对多关系在数据库中表示:
- “订单”表和“订单详细信息”表具有一对多关系。 每个订单可以有多个行项,但每个行项仅连接到一个订单。
- “产品”表和“订单详细信息”表具有一对多关系。 每个产品可以有多个与之关联的订单项,但每个订单项仅引用一个产品。
从“订单明细”表中,可以确定特定订单上的所有产品。 还可以确定特定产品的所有订单。
合并“订单详细信息”表后,表和字段的列表可能如下所示:
创建一对一关系
另一种类型的关系是一对一关系。 例如,假设您需要记录一些您很少需要或仅适用于少数产品的特殊补充产品信息。 因为您不需要经常这些信息,并且因为将信息存储在 Products 表中会导致每个不适用的产品都有空空间,所以您可以将其放在单独的表中。 与“产品”表一样,使用“产品 ID”作为主键。 此补充表与 Product 表之间的关系是一对一关系。 对于 Product 表中的每个记录,补充表中都存在一个匹配记录。 标识此类关系时,这两个表必须共享一个公共字段。
当您检测到数据库中需要一对一关系时,请考虑是否可以将两个表中的信息放在一个表中。 如果出于某种原因不想这样做,可能是因为这会导致大量空白空间,下面的列表显示了如何在设计中表示关系:
- 如果两个表具有相同的主题,则可能可以通过在两个表中使用相同的主键来设置关系。
- 如果两个表具有不同的主键的不同主题,请选择其中一个表 () ,并将其主键作为外键插入另一个表中。
确定表之间的关系有助于确保拥有正确的表和列。 当存在一对一或一对多关系时,所涉及的表需要共享一个或多个公共列。 当存在多对多关系时,需要第三个表来表示该关系。
优化设计
拥有所需的表、字段和关系后,应使用示例数据创建和填充表,并尝试使用这些信息:创建查询、添加新记录等。 这样做有助于突出显示潜在问题 — 例如,您可能需要添加一个在设计阶段忘记插入的列,或者您可能有一个应该拆分为两个表以删除重复的表。
看看是否可以使用数据库获取所需的答案。 创建表单和报表的粗略草稿,看看它们是否显示了您期望的数据。 寻找不必要的重复数据,当发现任何重复数据时,请更改设计以消除它。
当您尝试初始数据库时,您可能会发现改进的余地。 以下是一些需要检查的事项:
- 是否忘记了任何列? 如果是这样,这些信息是否属于现有表? 如果是有关其他内容的信息,则可能需要创建另一个表。 为需要跟踪的每个信息项创建一个列。如果无法从其他列计算信息,则可能需要为其创建一个新列。
- 是否有任何列是不必要的,因为它们可以根据现有字段计算? 如果可以从其他现有列计算信息项(例如,根据零售价计算的折扣价),通常最好只这样做,避免创建新列。
- 是否在其中一个表中重复输入重复信息? 如果是这样,则可能需要将表分成两个具有一对多关系的表。
- 您的表是否包含许多字段、有限数量的记录以及单个记录中的许多空字段? 如果是这样,请考虑重新设计表,使其具有更少的字段和更多的记录。
- 每个信息项是否都被分解为最小的有用部分? 如果您需要对某信息项进行报告、排序、搜索或计算,请将该项放在其自己的列中。
- 是否每列都包含有关表主题的事实? 如果某列不包含有关表主题的信息,则它属于另一个表。
- 表之间的所有关系是否都由公用字段或第三个表表示? 一对一和一对多关系需要公用列。 多对多关系需要第三个表。
优化“产品”表
假设产品销售数据库中的每种产品都属于一般类别,例如饮料、调味品或海鲜。 “产品”表可以包含显示每个产品类别的字段。
假设在检查和完善数据库设计后,您决定存储类别的描述及其名称。 如果向“产品”表添加“类别描述”字段,则必须为属于该类别的每个产品重复每个类别描述,这不是一个好的解决方案。
更好的解决方案是使 Categories 成为数据库跟踪的新主题,具有自己的表和自己的主键。 然后,可以将 Categories 表中的主键作为外键添加到 Products 表中。
“类别”和“产品”表具有一对多关系:一个类别可以包含多个产品,但一个产品只能属于一个类别。
当您查看表格结构时,请注意重复组。 例如,请考虑包含以下列的表:
- 产品 ID
- 名称
- 产品 ID1
- Name1
- 产品 ID2
- Name2
- 产品 ID3
- Name3
在这里,每个产品都是一组重复的列,它与其他列的不同之处只是在列名称的末尾添加一个数字。 当您看到以这种方式编号的列时,您应该重新访问您的设计。
这样的设计有几个缺陷。 对于初学者来说,它迫使您对产品数量设定上限。 一旦超过该限制,就必须向表结构添加一组新的列,这是一项主要的管理任务。
另一个问题是,那些产品数量少于最大数量的供应商将浪费一些空间,因为额外的列将是空白的。 这种设计最严重的缺陷是它使许多任务难以执行,例如按产品 ID 或名称对表进行排序或索引。
每当您看到重复组时,请仔细检查设计,注意将表格一分为二。 在上面的示例中,最好使用两个表,一个用于供应商,一个用于产品,按供应商 ID 链接。
应用规范化规则
可以应用数据规范化规则 (有时简称为规范化规则) 作为设计的下一步。 可以使用这些规则来查看表的结构是否正确。 将规则应用于数据库设计的过程称为规范化数据库,或只是规范化。
规范化在表示所有信息项并完成初步设计后最有用。 这个想法是帮助您确保已将信息项划分为适当的表。 规范化无法做到的是确保您从一开始就拥有所有正确的数据项。
您在每一步中连续应用规则,确保您的设计达到所谓的“范式”之一。五种范式被广泛接受——第一范式到第五范式。 本文扩展了前三个,因为它们是大多数数据库设计所需要的全部。
第一范式
第一范式指出,在表中的每一行和每一列的交叉处,都存在一个值,而不是值列表。 例如,不能在名为 Price 的字段中放置多个 Price。 如果将行和列的每个交叉点视为一个单元格,则每个单元格只能保存一个值。
第二范式
第二范式要求每个非键列完全依赖于整个主键,而不仅仅是键的一部分。 当具有由多个列组成的主键时,此规则适用。 例如,假设有一个包含以下列的表,其中订单 ID 和产品 ID 构成主键:
- 订单 ID (主键)
- 产品 ID (主键)
- 产品名称
此设计违反了第二范式,因为“产品名称”依赖于产品 ID,但不依赖于订单 ID,因此它不依赖于整个主键。 必须从表中删除“产品名称”。 它属于不同的表 (“产品) ”。
第三范式
第三范式要求不仅每个非键列都依赖于整个主键,而且非键列彼此独立。
另一种说法是,每个非键列都必须依赖于主键,并且只依赖于主键。 例如,假设有一个包含以下列的表:
- ProductID (主键)
- 名称
- SRP
- Discount
假定折扣取决于建议的零售价 (SRP) 。 此表违反第三范式,因为非键列 Discount 依赖于另一个非键列 SRP。 列独立性意味着您应该能够更改任何非键列而不影响任何其他列。 如果更改 SRP 字段中的值,折扣将相应更改,从而违反该规则。 在这种情况下,应将 Discount 移至另一个以 SRP 键入的表。