在我的数据库中指定关系有什么好处?

What do I gain from specifying relationships in my database?

我正在 MS Access 2010 中构建一个项目。我以前使用过 Oracle。我正在阅读有关 MS Access 的信息,并不断看到对 table 关系的引用。它看起来像是一种方便的方式来帮助普通人进行数据输入和验证以及查询构建,但我只在 SQL 模式下编写查询并强制使用具有自己的验证规则的表单的用户输入数据。

真的有必要加强关系吗?它似乎并没有真正让我在高级水平上获得任何东西,而且实际上可能会给我或其他人带来问题,这些人最终会在以后接管我的维护工作。我以前从未使用过它们,而且我并没有真正看到现在开始的好处。任何人都可以阐明这一点吗?

如果您的用例不需要它,那么您不一定会使用它。这可能是 "required" 的用例是在基于订单的场景中。

假设您有一个创建和跟踪订单的数据库。每个订单可以有多个与同一个订单相关联的行。但是出于规范化的目的,大多数人会将它们分成两个单独的表。 OrderHead 和 OrderDetail。您可能希望在此处强制执行引用完整性,以确保 OrderDetail 中永远不会有不 link 返回父订单的子记录。

我敢肯定,如果没有它,您可以防止类似的事情发生,但它主要只是强制执行。

关系有助于保持数据完整性,我同意您的观点,即如果用户从访问表单输入,则由于完整性而导致错误的可能性较小。但将来如果用户从 MS Access 转向纯 RDBMS,这种关系肯定会有所帮助。

虽然 objective 的关系不适合在以后的时间点迁移,但对于你的情况,这是我能想到的一个有效理由。

除此之外,MS Access 自带的表单关系可能不会添加特定值。

你说你以前有Oracle的经验。您从未在 Oracle 中定义外键约束吗?如果您这样做了,那么这就是您在 Access 中定义关系时所做的事情。您可以使用它来强制引用完整性(如果子记录仍然存在,则不允许您删除父记录),或者,如果您使用 cascade delete 选项,则在删除父记录时自动删除子记录。这是一个有用的备份,可以覆盖编码错误,如果您没有定义关系 (FK),您可能会忘记可能的子记录,否则这些记录将被孤立。

如果您纯粹在 SQL 模式下构建查询,那么定义关系可能对您没有任何影响。唯一可能有用的是,如果您构建了一些东西,然后几个月没有再看它,您将能够从概念上快速重新认识这些关系。

对于任何使用 Access 查询生成器的人来说,定义关系可以让您快速将表添加到查询中,同时 Access 会自动为查询 JOIN 构建适当的 (GIGO) 关系。同样,如果您在 SQL 中编写,您可能已经这样做了,因此对您的查询构建没有太大帮助。

底线 - 它更像是一个简化查询过程的图形工具,至少在您尝试将表导出到 "real" RDBMS 之前,正如其他人已经提到的那样。

对于一个只是查询数据的人来说,关系并不是那么重要。然而,从应用的角度来看,即使不是非常重要,它们也非常有用。

例如,您可能有一个客户的 table,然后说一个订单 table。业务规则是,除非您首先拥有客户,否则您无法创建订单。因此,如果您随意编写一些 SQL 来添加没有客户的订单,您的 update/insert 查询将不起作用。如果您需要删除一个客户,那么该客户的所有订单 can/will 都会自动为您删除,而无需编写复杂的 delete SQL 语句。例如,您可能想要删除所有超过 5 年或 10 年的客户(因此他们不活跃)。当您删除这些客户时,您希望所有订单也被删除。 (如果您必须删除每个客户的子记录,这是一个非常难以编写的查询。具有强制关系,那么所有子记录将自动为您删除(强制级联删除))。

从报告的角度来看,这也很重要。如果您编写一个查询来显示本月的所有客户及其账单总额,那么您将得到一个总结果。但是,如果您决定不想要 display/include 客户,您可能只点击订单 table 并以这种方式获得总金额。问题是没有 RI,那么你可能(偶然或者甚至只是一些用户启动订单)输入了订单信息(总金额)但没有客户。

现在发生的事情是当你 运行 两个不同 reports/quires 时,你会发现总数是不同的!在关于“为什么”两个报告不同的复杂应用程序中,可能需要几天时间,或者如果有大量数据,甚至需要一周时间才能弄清楚为什么两个关于月度销售额的报告彼此不一致。如果您执行业务规则,即除非他们有客户,否则不能将订单输入系统,那么您就可以消除报告中的此类错误。你可以“说”你是 SQL 的完美用户,但是有很多代码,很多数据输入表单,你怎么能确定没有客户就永远不会输入订单。在数据输入过程中,用户可能会忘记在该订单中输入客户。即使您在该订单中编写代码以确保必须选择客户,也可能您在编写某些 SQL 时不小心将没有客户的订单记录插入系统。但是,您的月度客户总报告查询“假设”您有一条客户记录,然后将其加入订单总数据中。

然而,有些报告必须 运行 订单数据(每月汇总总数不需要包括客户)。现在的问题是在系统的某个地方,您有一个订单记录,其中包含没有客户的总数据。结果是不同的报告,现在对销售总额的要求不一致。这简直就是一场噩梦。

因此,应用程序代码中可能会出现一些错误或错误,并导致本应是关系数据的内容现在具有“孤立”记录。也许您的业务规则允许在没有分配客户的情况下输入订单,但是您的月度销售报告必须显示这一事实,或者任何命中订单 table 且不包括客户的查询都必须“检查”这些查询中可能还没有客户记录存在。

以上只是对突然出现的 GAZILLION 问题的简单描述。因此,虽然您可能只是对数据创建简单的查询,但问题是数据在系统中是否正确关联?关于垃圾输入 = 垃圾输出的老话在这里是正确的。

一天结束时,当您 SQL 要求使用多个 table 提取数据时,您必须对该数据及其关系完整性 (RI) 做出假设。因此,当您编写该查询以显示客户及其订单总数时,您假定并放入客户 table,然后关系加入订单 table。但是,如果没有客户记录的订单存在,那么您的查询将不会产生正确的值。更糟糕的是,一份达到订单 table 的报告现在会产生不同的结果。

如果您强制执行 RI,那么无论如何,您都不能在没有首先创建客户记录的情况下意外或强制输入订单。如果您不执行此类规则,那么您的数据将产生不正确的结果。

而一个典型的复杂应用程序将有 40 或 70 个相关的 table。这些 table 中的每一个都会假设父(或子)记录是否“假定”已根据您的一组业务假设正确创建。

您可能有一个旅游预订系统。客户可能 phone 支付定金但尚未预订特定的旅游。如果您允许此设置,那么您本月对客户的查询和他们预订的旅游将必须考虑到这一点。然而,业务规则可能是系统中任何付钱的客户也必须预订旅游(因此您查询以获取该信息将考虑此规则)。

如果您总是进行的每个查询都不会包含来自多个 table 的数据,那么您可能不会从强制执行关系数据中获益太多。然而,当您开始将查询与多个 table 捆绑在一起时,您必须知道在编写查询之前对该数据所做的假设。那么,您是否允许在没有旅游预订的情况下在系统中支付押金的客户?此规则将决定您必须如何编写该查询。如果强制执行 RI,那么您可以查询客户“预订”,并且您知道它将附加到旅游活动。如果任何预订 + 押金不需要预订,情况也是如此——但您必须知道对该数据所做的假设。

因此,基于对数据所做的假设是创建查询以基于这些假设提取数据的唯一实用方法。如果您强制执行 RI,那么您至少知道数据必须相关并根据这些假设进行设置。

一天结束的时候?任何在不强制执行 RI 的情况下创建对业务应用程序和规则建模的数据库的人都在建造一艘没有舵和指南针的船。

并且从每个 table 导出数据不是问题。但是,如果该数据一团糟并且有孤立的记录,那么您最终只会将不正确的数据模型导出到另一个数据库,所有问题和问题仍然存在。