数据库设计三级阶梯:构建表
通过乔Celko,2013/09/18(第一次出版:2010/05/25)
该系列
本文是楼梯系列的一部分:数据库设计的阶梯
新设计和创建一个数据库的任务吗? 乔Celko,谁是最被广泛阅读的作家之一对SQL,解释了基础知识。 像往常一样,他想到偶尔的惊喜,即使最老练的专业数据库。 乔是DBMS的赢家连续四年杂志读者选择奖。 他教会了SQL在美国、英国、北欧国家,南美和非洲。 他10年ANSI / ISO SQL标准委员会和导致SQL - 89和SQL - 92标准。
有几种类型的表,各有其特殊的要求和完整性约束规则。 无论要求,表级约束将确保规则执行和数据完整性得到维护。
在一级,我们命名数据元素是什么和分类。 在两个水平,我们建模的数据元素的数据类型和约束在SQL给我们行。 在三个水平,我们要把这些行成表。 表不仅仅是一群行收集在一起下一个名字。
一列在一个表中只能出现一次。 只有有意义; 如果你两次记录别人的鞋码,最好将冗余和模棱两可的列不同意。 现在我们可以表检查约束水平在每一行的列。 他们并不是真的那么多不同的比列我们之前检查约束。 他们可以命名,并将出现在列表中列在CREATE TABLE语句中声明,不附加到任何行。。 例如:
检查(emp_birth_date < emp_hire_date)
通常是一个好主意不是将约束结合到一个巨大的检查()条款。 错误消息将包括约束的名称,所以单独的约束将会给你一个更好的主意出现了什么问题比一个怪物叫“Bad_Things_Happened”约束。
继续我们仇恨的冗余,在表级别我们希望每一行是独特的因为同样的原因。 这个可以用表约束。 这两个表级约束是唯一的主键,这在一个或多个列的版本。
独特的约束表示表中的列或列的组合是独一无二的。 但是如果有一个空的一个或多个列,我们将允许它,就好像它是一个独特的价值。 主键宣言有同样的效果为NOT NULL和独特的所有列。 但由于历史原因,声明一个表只能有一个主键。 这些列作为默认值对于其他表之间的约束,但是不要担心。
如何使用唯一性约束取决于类型的表。 一般来说,我们可以将一个表的三种类型:
- 实体
- 的关系
- 辅助
一个实体表是一组同样的事情列定义的属性建模。 每一行是一个实例的那种东西。 每一行有相同的列。 如果你能看到它的感觉,看到或触摸它,那么它是一个实体。 实体表的名字不应该是单数(除非真的有一只这组的成员),因为它一组模型。需要复数或名称,如果可能的话,集体。 例如,“员工”不好,“员工”是更好,“人员”是最好的。 “树”不好,“树”是更好,“森林”是最好的。 您可以添加您自己的例子。
实体也被归类为弱或强。 一个强大的实体存在于自己的优点,而弱实体存在,因为一个或多个强大的实体。 你需要购买之前,你可以有一个折扣。
一个关系表引用一个或多个实体和它们之间建立一个关系。 一个关系可以有自己的属性除了对实体的引用。 婚姻登记号码属于婚姻,而不是丈夫,妻子或部长。
的程度的关系是实体的数量关系。 二元关系有两个实体,我们喜欢他们在现实世界中,因为它们很简单。 一个递归二元关系与一个实体本身。 一般包括n n元关系实体,如住房抵押贷款与买方,卖方和银行。 不可能总是n元关系分解为二元关系。 成员的关系可以是可选的或强制性的。 可选的会员意味着我们可以有零个实体的一种——购买并不总是得到一个折扣。
关系的实际数量的基数相关事件的两个实体。 连接关系的基本类型有:一对一、一对多、多对多。 这些术语通常是合格的可选(0或多个)或强制(1或更多)会员资格。
一对一的最多(1:1)的关系是当一个实例的实体与一个实例相关联的实体b .例如,采取传统的丈夫和妻子之间的关系。 每个丈夫都有且只有一个妻子; 每个妻子都有且只有一个丈夫。 在这个例子中都是强制性的。
一对多(1:n)的关系是当一个实例的实体,零,一个或多个实例的实体B B,但对一个实例的实体只有一个实例的实体A一个例子可能是一个部门有许多雇员; 每个员工被分配给一个部门。 根据您的业务规则,你可能会允许一个未派职务的员工或一个空的部门。
多对多关系(m:n),有时被称为非特异性,是当一个实体的实例,有0,1,或许多实例的实体B和实体B有0的一个实例,一个或多个实体的实例A一个例子可能是披萨和客户。
一个辅助表既不是一个实体,也不是一个关系; 它提供信息。 他们像日历或其他替代计算在SQL的查找表。 他们常常被误解,当作实体或关系表。
让我们使这个更具体。 销售订单是客户(实体)之间的关系和我们的库存(实体)。 订单细节是弱实体存在,因为我们有一个订单。 的关系有一个订单号,不是库存或客户的一部分。 运输成本从一个辅助表。 这里有一些骨架表对于这个示例。 我使用GTIN(全球贸易项目编号)订单项和兔褐(数据统一编号系统)的客户。 总是寻找行业标准,当你设计一个数据库。
创建表Sales_Orders
(order_nbr整数非空主键
检查(order_nbr > 0),
customer_duns CHAR(9)不是零,
order_shipping_amt十进制(5,2)NOT NULL
检查(shipping_amt > = 0.00),
等);
创建表Sales_Order_Details
(order_nbr整数非空,
gtin CHAR(15)不是零,
主键(order_nbr gtin),
item_qty整数非空
检查(item_qty > 0),
item_unit_price十进制(8,2)NOT NULL
检查(item_unit_price > = 0.00));
创建表的客户
(customer_duns CHAR(9)NOT NULL主键
检查(customer_duns像“[0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9]”),
等);
创建表的库存
(gtin CHAR(15)NOT NULL主键
检查(gtin像“[0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9]”),
onhand_qty整数非空
检查(onhand_qty > = 0),
我们可以看到,销售订单是客户和库存之间的关系。 订单有自己的关键(order_nbr)但是没有强迫我们只使用有效客户兔褐数字或产品GTIN编码的事情我们有库存。 事实上,我可以将明显无效的兔褐和GTIN代码插入Orders表这样的声明。
这是引用条款的由来。 这就是让我们执行所有的基数和学位从数据模型。 不是一个链接或一个指针的引用。 这是物理概念和参考是一个逻辑概念,我们不知道它是如何实现的。 它执行的是一条规则,引用表列匹配引用表中的一行。 这意味着引用表中的行必须是独特的; 默认情况下,引用表的主键是目标,但它dos不是必须的。 引用表中的值被称为外键表——他们不是钥匙,但其他地方的模式。
这是与更多的肉骨架模式:
(order_nbr整数非空主键
检查(order_nbr > 0),
customer_duns CHAR(9)不是零
引用客户(customer_duns),
order_shipping_amt小数(5,2)默认0.00 NOT NULL
检查(shipping_amt > = 0.00),
等);
创建表Sales_Order_Details
(order_nbr整数不是零
引用订单(order_nbr),
gtin CHAR(15)不是零
引用库存(gtin),
主键(order_nbr gtin)——两个列的关键
item_qty整数非空
检查(item_qty > 0),
item_unit_price十进制(8,2)NOT NULL
检查(item_unit_price > = 0.00));
创建表的客户
(customer_duns CHAR(9)NOT NULL主键
检查(customer_duns像“[0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9]”),
等);
创建表的库存
(gtin CHAR(15)NOT NULL主键
检查(gtin像“[0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9][0 - 9]”),
onhand_qty整数非空
检查(onhand_qty > = 0),
等);
注意,我们只有检查()约束的地方兔褐和GTIN钥匙,不出现在引用表。 引用的实体表、客户和库存; 关系表、订单、引用其他表。 这是一个通用的模式,但它不是设置在混凝土。
这个条款的多个列的形式是这样的:
引用Sales_Order_Details(gtin order_nbr)
列引用表中的外键副条款中引用键必须匹配,列的列,但可能有不同的名称。 我可以得到1:1,1:n和n:m关系通过唯一性约束在正确的地方。 腋表的一个例子,我们可以计算出运输成本基于订单的总价值。 表可能看起来像这样:
创建表Shipping_Costs
(start_order_amt_tot小数(10、2)非空,
end_order_amt_tot小数(10、2)非空,
约束Valid_Shipping_Range
检查(start_order_amt_tot < end_order_amt_tot),
主键(start_order_amt_tot end_order_amt_tot),
shipping_amt十进制(5,2)NOT NULL
检查(shipping_amt > 0.00));
虽然我们已经宣布在辅助运输成本表主键,它不像实体的键——没有确认或验证,它不是一个标识符。 使用此表,我们将查询的时候可以这样说:
选择shipping_amt
从Shipping_Costs
其中<订单总金额> start_order_amt_tot和end_order_amt_tot之间;
作为练习,试着写一个约束,防止开始和结束范围重叠和空白。 如果你需要可以重新设计表。
在修改后的骨架模式中,当你试图把订单没有库存的产品,你会得到一个错误,说,实际上,“这是脱销! “你可以尝试别的东西。 但如果你尝试删除一个产品库存,您还将得到一个错误实际上说,“嘿,有人命令这个垃圾”,所以你必须去每个订单和用别的东西代替的项目或NULL(如果允许)之前您可以删除它从库存。
这就是声明引用完整性(DRI)操作。 的语法是:
在删除任何行动|设置默认零| |设置级联)
在更新任何行动|设置默认零| |设置级联)
删除和更新被称为“数据基础事件”; 当他们发生在桌上,然后DRI行动发生。
- 没有ACTION =事务回滚,你会得到一个消息。 这是默认条款当你只是有一个简单的引用。
- 设置默认=引用的列(s)都随着时间的改变而改变,但引用列更改为默认值。 显然,引用列需要违约声明。 这些默认值必须在引用表中。
- 设置空=引用的列(s)都随着时间的改变而改变,但引用列更改为NULL。 显然,需要NULL-able引用列。 这就是“无罪推定”为null。
- 级联=引用的列(s)改变的事件,和级联到相同的值引用列。 在实践中这是最重要的选择。 例如,如果我们想要停止一个产品,我们可以删除它从库存和级联删除将SQL引擎Sales_Order_Details自动删除匹配的行。 同样地,如果你更新一个项目在库存,在级联更新将专制地将旧值替换为新的地方引用它。
在执行这些动作之后,引用完整性约束仍然有效。 这是最后一个框架:
(order_nbr整数非空主键
检查(order_nbr > 0),
customer_duns CHAR(9)不是零
引用客户(customer_duns)
在级联更新
在级联删除,
order_shipping_amt小数(5,2)默认0.00 NOT NULL
检查(shipping_amt > = 0.00),
等);
创建表Sales_Order_Details
(order_nbr整数不是零
引用订单(order_nbr)
在级联更新
在级联删除,
gtin CHAR(15)不是零
引用库存(gtin)
在级联更新
在级联删除,
主键(order_nbr gtin)——两个列的关键
item_qty整数非空
检查(item_qty > 0),
item_unit_price十进制(8,2)NOT NULL
检查(item_unit_price > = 0.00));
看你能不能找出当:
- 客户死了,我们删除了他。
- 我们改变草坪Gnome雕像更雅致的粉红色的火烈鸟。
- 我们停止了粉红色的火烈鸟。
- 有人试图顺序步骤1到3后草坪Gnome
显然,我离开补充问题,其他的事情,但我们会得到的。
该系列
读到的其余部分数据库设计系列的楼梯并查看其他文章。