zoukankan      html  css  js  c++  java
  • 外文转译:数据库设计阶梯3:建筑表

    数据库设计阶梯3:建筑表

    这篇文章是楼梯系列的一部分:楼梯数据库设计

    新设计和创建数据库的任务?作为被SQL的所有作家的最广泛阅读的Joe Celko解释了基础知识。像往常一样,他的作品偶然甚至是被最经验丰富的数据库专业人士所惊喜。乔连续四年获得DBMS杂志读者选择奖。他在美国,英国,北欧国家,南美洲和非洲都教过SQL。他在ANSI / ISO SQL标准委员会任职十年,为SQL-89和SQL-92标准做出了贡献。

    有几种类型的表,每种都有对规则和完整性约束的特殊要求。无论需求如何,表级别的约束将确保执行规则并维护数据完整性。

    在第一级中,我们为数据元素命名了它们并对它们进行了分类。在二级中,我们使用SQL中的数据类型和约束对数据元素建模,以给出行。在三级中,我们将这些行放入表中。一张桌子不仅仅是一堆以一个名字收集在一起的行。

    一个列在表中只能出现一次。这是有道理的 如果你记录了一个人的鞋子大小两次,那么列不同意的。现在我们可以在每行的列之间有表级别的CHECK约束。它们与我们以前使用的CHECK限制没有太大的不同。它们可以被命名,并将出现在CREATE TABLE语句中的列声明列表中,而不附加到任何行。例如:

    CONSTRAINT Valid_Employee_Age--在出生前不要雇用人

     CHECK(emp_birth_date <emp_hire_date)

    不要将约束合并成一个巨大的CHECK()子句通常是个好主意。错误消息将包含约束名称,因此单独的约束将使您更好地了解一个名为“Bad_Things_Happened”约束的单个怪物出错的情况。

    继续我们对冗余的仇恨,在表级,我​​们希望每一行都是独一无二的,原因相同。这可以通过表约束完成。两个表级限制是UNIQUE和PRIMARY KEY,它们都是单列和多列。

    UNIQUE约束表示列中的列或组合在表中是唯一的。但是如果在一个或多个列中有NULL,我们将允许它像一个唯一的值一样。PRIMARY KEY声明与其中的所有列的NOT NULL和UNIQUE具有相同的效果。但是由于历史原因,一个表只能有一个PRIMARY KEY声明。这些列用作表之间的其他约束的默认值,但不要担心现在。

    如何使用唯一性约束取决于所涉及的表的类型。一般来说,我们可以将表格分为三种:

    1.实体

    2.关系

    3.辅

    实体表是由列建模的属性定义的同一类的一组事物。每行都是这种事情的一个实例。每行都有相同的列。如果你能看到它的感觉,看到或触摸它,那么它是一个实体。实体表的名称不应该是单数的(除非真的只有这个集合的一个成员),因为它建立一个集合。这个名字需要是复数形式,如果可能的话,需要集体。例如“员工”不好,“员工”较好,“人事”最好。“树”不好,“树”更好,“森林”最好。你可以添加自己的例子。

    实体也被分类为弱或强。一个强大的实体存在着自己的优点,而一个弱实体存在,因为一个或多个强大的实体。您需要购买才能享受折扣。

    关系表引用一个或多个实体并建立它们之间的关系。除了引用实体之外,关系还可以具有自己的属性。婚姻执照号码属于婚姻,而不是丈夫,妻子或部长。

    关系的程度是关系中的实体数量。二元关系有两个实体,我们在现实世界中喜欢它们,因为它们很简单。递归二进制关系将实体与自身相关联。一般的n-ary关系涉及n个实体,例如与买方,卖方和贷方的房屋抵押。将n-ary关系分解为二元关系并不总是可能的。关系中的成员资格可以是可选的或强制性的。可选的会员资格意味着我们可以拥有一种零个实体 - 购买并不总是得到折扣。

    关系的基数是两个实体中每个实体的相关事件的实际数量。关系的基本连接类型是:一对一,一对多,多对多。这些条款通常具有可选(0或更多)或强制性(1个或更多)成员资格。

    一对一(1:1)的关系是一个实体A的最多一个实例与实体B的一个实例相关联。例如,采取传统的丈夫和妻子之间的关系。每个丈夫只有一个老婆; 每个妻子只有一个丈夫。在这个例子中都是强制性的。

    一对多(1:n)关系是对于实体A的一个实例,实体B有零个,一个或多个实例,但对于实体B的一个实例,实体A只有一个实例。例如,一个部门有很多员工; 每个员工被分配到一个部门。根据您的业务规则,您可能会允许未分配的员工或空的部门。

    有时称为非特定的多对多(m:n)关系是对于实体A的一个实例,实体B有零个,一个或多个实例,并且对于实体B的一个实例,零,一个或多个实体A.一个例子可能是比萨饼和客户。

    辅助表既不是实体也不是关系; 它提供了信息。它们是用于替换SQL中的计算的日历或其他查找表。他们经常被误解,被视为实体或关系表。

    让我们更具体一些。销售订单是客户(实体)和我们的库存(实体)之间的关系。订单详细信息是存在的弱实体,因为我们有订单。该关系具有不是库存或客户的一部分的订单号。运输成本从辅助表获得。下面是这个例子的一些骨架表。我正在为客户使用GTIN(全球贸易商品编号)和DUNS(数据通用编号系统)。设计数据库时,始终寻找行业标准。

    CREATE TABLE Sales_Orders

    (order_nbr INTEGER NOT NULL PRIMARY KEY

     CHECK(order_nbr> 0),

     customer_duns CHAR(9)NOT NULL,

     order_shipping_amt DECIMAL(5,2)NOT NULL

     CHECK(shipping_amt> = 0.00),

     等等);

    CREATE TABLE Sales_Order_Details

    (order_nbr INTEGER NOT NULL,

     gtin CHAR(15)NOT NULL,

     PRIMARY KEY(order_nbr,gtin),

     item_qty INTEGER NOT NULL

     CHECK(item_qty> 0),

     item_unit_price DECIMAL(8,2)NOT NULL

     CHECK(item_unit_price> = 0.00));

    CREATE TABLE客户

    (customer_duns CHAR(9)NOT NULL PRIMARY KEY

     CHECK(customer_duns LIKE'[0-9] [0-9] [0-9] [0-9] [0-9] [0-9] [0-9] [0-9] [0-9] “),

     等等);

    创建表库存

    (gtin CHAR(15)NOT NULL PRIMARY KEY

     CHECK(gtin LIKE'[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 INTEGER NOT NULL

     CHECK(onhand_qty> = 0),

    我们可以看到销售订单是客户和库存之间的关系。订单有自己的密钥(order_nbr),但没有任何东西强制我们仅使用有效的客户DUNS号码或产品GTIN代码,我们实际上在库存中。实际上,我可以把Order DUNS和GTIN的代码插入到Orders表中,现在就是这样宣告的。

    这是REFERENCES子句所在。它是什么让我们从数据模型中强制执行所有的基数和度数。引用不是链接或指针。那些是物理概念,参考是一个逻辑概念,我们不知道它是如何实现的。它执行的是引用表列与引用表中的单个行匹配的规则。这意味着引用表中的行必须是唯一的; 默认情况下,引用表中的PRIMARY KEY是目标,但它不必是。引用表中的值称为外键 - 它们不是表中的键,而是模式中的其他位置。

    以下是具有更多肉体的骨架模式:

    CREATE TABLE Sales_Orders

    (order_nbr INTEGER NOT NULL PRIMARY KEY

     CHECK(order_nbr> 0),

     customer_duns CHAR(9)NOT NULL

     参考客户(customer_duns),

     order_shipping_amt DECIMAL(5,2)DEFAULT 0.00 NOT NULL

     CHECK(shipping_amt> = 0.00),

     等等);

    CREATE TABLE Sales_Order_Details

    (order_nbr INTEGER NOT NULL

     参考订单(order_nbr),

     gtin CHAR(15)NOT NULL

     参考库存(gtin),

     PRIMARY KEY(order_nbr,gtin), - 两列键

     item_qty INTEGER NOT NULL

     CHECK(item_qty> 0),

     item_unit_price DECIMAL(8,2)NOT NULL

     CHECK(item_unit_price> = 0.00));

    CREATE TABLE客户

    (customer_duns CHAR(9)NOT NULL PRIMARY KEY

     CHECK(customer_duns LIKE'[0-9] [0-9] [0-9] [0-9] [0-9] [0-9] [0-9] [0-9] [0-9] “),

     等等);

    创建表库存

    (gtin CHAR(15)NOT NULL PRIMARY KEY

     CHECK(gtin LIKE'[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 INTEGER NOT NULL

     CHECK(onhand_qty> = 0),

     等等);

    请注意,我们只需要在DUNS和GTIN是键的地方使用CHECK()约束,而不是它们在引用表中出现的位置。引用实体表,客户和库存; 关系表,订单,引用其他表。这是一般的模式,但并不具体。

    这个子句的多列形式如下所示:

    FOREIGN KEY(order_nbr,gtin)

    参考Sales_Order_Details(order_nbr,gtin)

    FOREIGN KEY子条款中的列在引用表中必须与引用的键匹配,列为列,但可能有不同的名称。我可以通过在正确的地方放置唯一性约束来获得1:1,1:n和n:m关系。作为腋窝表的一个例子,我们可以根据订单的总价值计算运输成本。桌子可能看起来像这样:

    CREATE TABLE Shipping_Costs

    (start_order_amt_tot DECIMAL(10,2)NOT NULL,

     end_order_amt_tot DECIMAL(10,2)NOT NULL,

    CONSTRAINT Valid_Shipping_Range

     CHECK(start_order_amt_tot <end_order_amt_tot),

    PRIMARY KEY(start_order_amt_tot,end_order_amt_tot),

     shipping_amt DECIMAL(5,2)NOT NULL

     CHECK(shipping_amt> 0.00));

    虽然我们在辅助运输费用表上声明了一个主键,但它不像实体的键 - 没有验证或验证,它不是标识符。要使用此表,我们将使用以下内容查询:

    SELECT shipping_amt

      来自Shipping_Costs

     WHERE <order amount total> BETWEEN start_order_amt_tot AND end_order_amt_tot;

    作为一个练习,尝试编写一个约束,以防止起始和结束范围重叠和间隙。如果需要,可以重新设计桌子。

    在修订的骨架模式中,当您尝试对不在库存中的产品进行订单时,您将收到一条错误,表示“实际上是”缺货!“,您可以尝试其他操作。但是,如果您尝试从库存中删除某个产品,您还会收到一条错误,表示有效,“嘿,有人订购了这个垃圾”,所以你必须去每个订单,用其他的东西替换这个项目或使其为空(如果允许),然后才能从库存中删除它。

    这是使用声明参照完整性(DRI)动作的地方。语法是:

    ON DELETE [NO ACTION | SET DEFAULT | SET NULL | 级联]

    ON UPDATE [NO ACTION | SET DEFAULT | SET NULL | 级联]

    删除和更新称为“数据库事件”; 当它们发生在桌面上时,就会发生DRI动作。

    NO ACTION =事务被回滚并且您收到消息。当你只有一个简单的REFERENCES子句时,这是默认值。

    SET DEFAULT =引用的列由事件更改,但引用列将更改为其默认值。显然,引用列需要在其上声明默认值。这些默认值必须在引用的表中。

    SET NULL =引用的列由事件更改,但引用列更改为NULL。显然,引用列需要为NULL。这就是NULL的“益处”。

    CASCADE =引用的列被事件改变,并且这些相同的值被级联到引用列。这是实践中最重要的选择。例如,如果我们要停止产品,我们可以从库存中删除它,而ON DELETE CASCADE会使SQL引擎自动删除Sales_Order_Details中的匹配行。同样,如果您更新库存中的一个项目,ON UPDATE CASCADE将会自动将旧值替换为引用的新值。

    执行任何这些操作后,引用完整性约束仍然有效。这是最后的骨架:

    CREATE TABLE Sales_Orders

    (order_nbr INTEGER NOT NULL PRIMARY KEY

     CHECK(order_nbr> 0),

     customer_duns CHAR(9)NOT NULL

     参考客户(customer_duns)

     ON UPDATE CASCADE

     ON DELETE CASCADE,

     order_shipping_amt DECIMAL(5,2)DEFAULT 0.00 NOT NULL

     CHECK(shipping_amt> = 0.00),

     等等);

    CREATE TABLE Sales_Order_Details

    (order_nbr INTEGER NOT NULL

     参考订单(order_nbr)

     ON UPDATE CASCADE

     ON DELETE CASCADE,

     gtin CHAR(15)NOT NULL

     参考库存(gtin)

     ON UPDATE CASCADE

     ON DELETE CASCADE,

     PRIMARY KEY(order_nbr,gtin), - 两列键

     item_qty INTEGER NOT NULL

     CHECK(item_qty> 0),

     item_unit_price DECIMAL(8,2)NOT NULL

     CHECK(item_unit_price> = 0.00));

    看看你能否弄清楚:

    客户死亡,我们删除他。

    我们把草坪Gnome雕像变成更有品味的粉红色火烈鸟。

    我们停止粉红色的火烈鸟。

    有人尝试在步骤1到3之后订购草坪Gnome

    显然,我正在放弃补货问题和其他事情,但我们会得到那些。

    转译地址:http://www.sqlservercentral.com/articles/Stairway+Series/69927/

  • 相关阅读:
    CF 142B Tprimes
    CF 231A Team
    poj 2001 Shortest Prefixes ——字典树入门
    hdu 1039 Easier Done Than Said?
    poj 2528 Mayor's posters
    hdu 1061 Rightmost Digit
    poj 2503 Babelfish
    CF271 A. Beautiful Year
    poj 2752
    CF271 B. Prime Matrix
  • 原文地址:https://www.cnblogs.com/fenglianchen/p/7759745.html
Copyright © 2011-2022 走看看