时间:2021-07-01 10:21:17 帮助过:16人阅读
Stairway to Database Design Level 3: Building Tables
作者:Joe Celko,2013年3月9日(第一次出版:2010/05/25)
该系列
本文是楼梯系列的一部分:数据库设计的阶梯
为设计和创建数据库做了一个新任务?Joe Celko是所有关于SQL的最广泛的作家之一,他解释了基本的问题。像往常一样,他偶尔会为最老练的数据库专业人士带来意外惊喜。乔是“DBMS杂志读者选择奖”的获得者,连续四年获奖。他曾在美国、英国、北欧国家、南美和非洲教过SQL。他在ansi/iso SQL标准委员会工作了10年,并为SQL-89和SQL-92标准做出了贡献。
有几种类型的表,每个表都有它们对规则和完整性约束的特殊要求。无论需求是什么,表级的约束将确保执行规则,并维护数据的完整性。 |
在第一级中,我们将用数据元素为它们命名,并对它们进行分类。在第二级中,我们用SQL中的数据类型和约束对数据元素进行建模来实现数据库为我们提供行的操作。在第三级中,我们把这些行放入表中。一个表不仅仅是一个名字集合在一起的一堆行。
一个列只能在表中出现一次。只有这有才有意义。如果你把某人的鞋号记录了两次,顶多就只能算是数据多余,而当两列不一致的时候,系统就会模棱两可无法执行。现在我们可以在每行的列之间设置表级别检查约束。它们与我们以前的一列检查约束实际上并没有那么大的不同。它们可以被命名,并会出现在创建表语句中的列声明列表中,而不是连接到任何行。例如:
将约束组合成一个大的检查()子句是个好方式。错误信息会包含约束名,所以单独的约束会让你更好的理解错误,而不是一个单一的怪物叫 ”bad_things_happened”约束。
继续我们对冗余的讨厌,在表级上,我们希望每一行都是惟一的,原因相同。这可以通过表约束来完成。这两个表级约束是唯一的和主键,它同时出现在单个和多个列版本中。
惟一的约束条件是,列或列的组合在表中是唯一的。但是如果在一个或多个列中有一个空值,我们允许它作为一个唯一值。主键声明与它中所有列的非空和唯一的效果相同。但是由于历史原因,一个表只能有一个主键声明。这些列被用作表之间其他约束的默认值,但是现在不用担心。
如何使用唯一性约束取决于所涉及的表的类型。广义来说,我们可以将一个表归为为三种类型之一:
实体表是一组相同类型的东西,它们由列所建模的属性定义。每一行都是这样的一个例子。每一行都有相同的列。如果你能有看到它的感觉,或者看到、触摸到它,那它就是一个实体。实体表的名称不应该是单数(除非真的只有这个集合中的一个成员),因为它为一个集合建模。这个名称需要是复数,如果可能,最好是集合。例如,“员工”是不好的,“员工”比较好,“员工”是最好的。“树”不好,“树”比较好,“森林”是最好的。您可以添加自己的示例。
实体也被划分为弱或强。一个强大的实体存在于它自身的优点中,而一个脆弱的实体存在于一个或多个强大的实体中。你会购买消费前提可能是在打折。
关系表引用一个或多个实体,并在其中建立关系。除了对实体的引用之外,关系还可以拥有自己的属性。结婚证是属于婚姻的,而不是丈夫、妻子或牧师的。
关系的程度是关系中实体的数量。二元关系有两个实体,在现实世界中我们最喜欢它们,因为它们很简单。递归二进制关系将实体与自身联系起来。一般的n元关系涉及到N的实体,如一个买方按揭,卖方和银行。它并不总是能够分解成n元关系的二元关系。关系中的成员可以是可选的,也可以是强制性的。可选的会员意味着我们只能有一种方式可以有一个零实体的方式—一种购买并不总是能得到折扣的方式。
关系的基数是两个实体中每一个实体的相关事件的实际数量。关系的连接性的基本类型是:一对一,一对多,多对多。这些术语通常具有可选(0个或更多)或强制性(1个或更多)成员资格。
一对一(1:1)关系是一个实体A的一个实例最多与实体B的一个实例相关联,例如,传统夫妻之间的关系。每个丈夫只有一个妻子,每个妻子只有一个丈夫。在本例中这两个都是强制性的。
一对多(1,n)关系是实体A的一个实例,实体B有一个、一个或多个实例,但对于一个实体B的实例,只有一个实体A. An实例,可能是一个部门有许多雇员,每个雇员被分配给一个部门。根据你的业务规则,你可能会允许一个指定的员工或空处。
一个多对多(m:n)关系,有时被称为非特定的,是当实体A的一个实例,有零个,一个或多个实体B的实例,一个实体B的实例有零个,一个,或多个实体A的实例,一个例子可能是披萨和客户。
辅助表既不是实体也不是关系;它提供信息。它们类似于日历或其他查找SQL中计算的表。他们经常被误解,被当作实体或关系表对待。
让我们把它变得更具体。销售订单是客户(实体)和库存(实体)之间的关系。订单细节是存在的一个弱实体,因为我们有一个订单。该关系有一个订单号,而不是库存或客户的一部分。运输成本是从一个辅助表中获得的。下面是这个示例的一些框架表。我正在使用GTIN(全球贸易项目编号)为客户提供订单项和DUNS(数据通用编号系统)。在设计数据库时,总是要寻找行业标准。
我们可以看到,销售订单是客户和库存之间的关系。订单有他们自己的密钥(order_nbr),但是没有任何东西可以强迫我们只使用有效的客户DUNS号码或产品GTIN代码来满足我们在库存中实际拥有的东西。事实上,我可以在命令表中插入明显无效的DUNS和GTIN代码,就像现在声明的那样。
这就是引用子句的用武之地。它使我们能够从数据模型中执行所有的基数和程度的东西。引用不是链接,也不是指针。这些是物理概念,参考是一个逻辑概念,我们不知道它是如何实现的。它所强制执行的规则是引用表列与引用表中的一行匹配。这意味着引用表中的行必须是惟一的;默认情况下,引用表中的主键是目标,但它不必是。引用表中的值被称为外键—它们不是表中的键,而是模式中的其他位置。
下面是骨架模式,上面有更多的肉:
注意,在DUNS和GTIN是键的地方,我们只需要检查()约束,而不是在引用表中出现的地方。实体表、客户和库存都被引用;关系表、订单、引用其他表。这是一个一般的模式,但不是具体的。
这个子句的多列形式如下:
外键子句中的列在引用表中,必须匹配列的引用键,但可以有不同的名称。我可以通过在正确的位置放置唯一性约束来得到1:1、1:n和n:m的关系。作为一个下面表的例子,我们可以根据订单的总价值计算运费。表格可以是这样的:
虽然我们已经声明了辅助运输成本表的主键,但它不像实体的键——没有验证或验证,它不是标识符。要使用此表,我们将查询类似的问题:
作为一个练习,试着写一个约束,以防止开始和结束范围从重叠和有差距。如果需要,可以重新设计表。
在修改后的骨架模式中,当您试图为一个没有库存的产品执行订单时,您将会得到一个错误,它实际上是说,“它已经脱销了!”你可以试试别的办法。但如果你尝试删除一个产品库存,您还将得到一个错误实际上说,“嘿,有人命令这个垃圾”,所以你必须去每个订单和用别的东西代替的项目或NULL(如果允许)之前您可以删除它从库存。
这是使用声明引用完整性(DRI)操作的地方的语法是:
删除和更新被称为“数据基事件”;当它们发生在表上时,会发生DRI操作。
1 .工作不采取行动=回滚事务,您将得到一条消息。当您只有一个简单的引用子句时,这就是默认值。
2. SET DEFAULT =引用的列由事件改变,但是引用列被更改为默认值。显然,引用列需要在它们上声明默认值。这些默认值必须在引用表中。
3 .项目SET NULL =引用的列被事件更改,但是引用列被更改为NULLs。显然,引用列需要为空。这就是“怀疑的好处”的原因。
4。级联=被引用的列被事件改变,相同的值被级联到引用列。这是实践中最重要的选择。例如,如果我们想要停止一个产品,我们可以从库存中删除它,而在delete CASCADE中,SQL引擎会自动删除Sales_Order_Details中的匹配行。同样,如果您在库存中更新项目,则更新级联将在引用的任何地方将旧值替换为新值。
在执行这些操作之后,引用完整性约束仍然有效。这是最后的骨架:
看看你是否能弄清楚发生了什么事:
1 .一个工作客户去世了,我们把他删除了。
2. 我们把草坪上的侏儒雕像换成了更有品位的火烈鸟。
3 .项目让我们停止了粉红色的火烈鸟。
4. 在第1到3步之后,有人试图订购草坪Gnome
很明显,我不考虑重新进货的问题和其他事情,但我们将会得到这些。
该系列
阅读数据库设计系列的其余部分并查看其他文章。
本文是数据库设计楼梯阶梯的一部分。
翻译:数据库设计层次3:构建表
标签:细节 blog .com 记录 标识 意义 默认 cal 其他