是否可以实现真正的一对一关系?

时间:2015-10-08 16:29:06

标签: sql database-design relational-database one-to-one

考虑以下模型,其中 GUI: QT: NO Win32 UI: YES OpenGL support: NO VTK support: NO 应该只有一个CustomerAddress应该只属于一个Address

enter image description here

为了实现它,几乎DB领域的每个人都说,Customer是解决方案:

enter image description here

但是我认为这是一种假的一对一的关系。 因为数据库关系方面没有任何内容阻止删除表Shared PK 中的任何行。所以,它真的是1 .. [0..1]而不是1..1

我是对的吗?有没有其他方法可以实现真正的1..1关系?

更新

为什么级联删除不是解决方案:

如果我们考虑将级联删除作为解决方案,我们应该将其放在任一表上。假设如果从表Address中删除了一行,则会导致表Address中的相应行被删除。没关系,但解决方案的一半。如果删除Customer中的行,则也应删除Customer中的相应行。这是解决方案的后半部分,它显然是一个循环。

7 个答案:

答案 0 :(得分:2)

抱歉,这是真实的数据库关系吗?在我使用客户数据构建的所有数据库中,始终存在具有多个地址的客户或同一地址的多个组织的真实案例。

我不想通过暗示任何不同的方式引导你进入数据库建模谬误。

答案 1 :(得分:2)

除了我的评论

  • 您可以实施DELETE CASCADE请参阅HOW

我意识到插入问题也存在。

  • 您必须先插入Customer,然后再插入Address

所以我认为如果你真的想要一个1:1,最好的办法就是创建一个单独的表。

客户

CustomerID
Name
Address
City

答案 2 :(得分:1)

原则上可以在某些DBMS中实现真正的1-1数据结构。然而,使用标准SQL在这样的结构中添加数据或修改数据非常困难。标准SQL只允许一次更新一个表,因此只要在一个或另一个表中插入一行,就会破坏预期的约束。

以下是两个例子。首先使用教程D.注意两个INSERT语句之间的逗号确保1-1约束永远不会被破坏:

VAR CUSTOMER REAL RELATION {
    id INTEGER} KEY{id};

VAR ADDRESS REAL RELATION {
    id INTEGER} KEY{id};

CONSTRAINT one_to_one (CUSTOMER{id} = ADDRESS{id});

INSERT CUSTOMER RELATION {
    TUPLE {id 1234}
    },
INSERT ADDRESS RELATION {
    TUPLE {id 1234}
    };

现在在SQL中也是如此。

CREATE TABLE CUSTOMER (
    id INTEGER NOT NULL PRIMARY KEY);

CREATE TABLE ADDRESS (
    id INTEGER NOT NULL PRIMARY KEY);

INSERT INTO CUSTOMER (id)
    VALUES (1234);

INSERT INTO ADDRESS (id)
    VALUES (1234);

ALTER TABLE CUSTOMER ADD CONSTRAINT one_to_one_1
    FOREIGN KEY (id) REFERENCES ADDRESS (id);

ALTER TABLE ADDRESS ADD CONSTRAINT one_to_one_2
    FOREIGN KEY (id) REFERENCES CUSTOMER (id);

SQL版本使用两个外键约束,这是大多数SQL DBMS支持的唯一一种多表约束。它需要两个INSERT语句,这意味着我只能在添加约束之前插入一行,而不是在。

之后

严格的一对一约束在实践中可能并不是非常有用,但它实际上只是一个更重要和有趣的特例:加入依赖。连接依赖实际上是一个"至少一个"表之间的约束而不是"恰好一个"。在数据库之外的世界中,通常会遇到应该作为连接依赖项实现的业务规则示例("每个客户必须至少有一个地址","每个订单必须至少有一个其中的项目")。在SQL DBMS中,实现连接依赖性很难或不可能。通常的解决方案是忽略此类业务规则,从而削弱数据库的数据完整性值。

答案 3 :(得分:1)

是的,"共享PK"你展示的成语是1对0或1。

真正的一对一通信的直接方法是将一个表与Customer和Address作为CK(候选键)。 (通过UNIQUE NOT NULL和/或PRIMARY KEY。)您可以提供单独的表作为视图。遗憾的是,典型的DBMS限制了您可以通过视图执行的操作,尤其是重新更新。

具有单独的CUSTOMER和ADDRESS表以及第三个表/关联/关系的关系方式,客户和地址列为客户与客户之间的CK和FK以及来自ADDRESS的地址(或等效约束) )。不幸的是,大多数DBMS不必要地让你在FK中声明循环,并且你不能在没有触发器/复杂性的情况下施加约束。 (最终,如果您希望在典型的SQL数据库中具有正确的完整性,则需要使用触发器和复杂的习惯用法。)

不幸的是,面向实体的设计方法人为地区分了实体,关联和属性。这里有一个例子,如果你认为最简单的设计只是一个带PK的表,那么你不希望总是必须为每个实体都有不同的表。或者如果你认为最简单的设计是带有PK和FK的三个表(甚至两个)(或者一对一的一些其他约束),那么不幸的是,典型的DBMS只是没有声明性地/符合人体工程学地支持特定的设计情况。

(简单的关系设计是将值(有时用作id)与应用程序事物进行1对1,然后只需要具有相应的应用程序关系/关联/关系以及相应/表示表/关系来描述你的申请情况。)

答案 4 :(得分:1)

是的,你说的是真的,1:1关系的依赖方可能不存在 - 只是在创建独立实体后创建依赖实体所花费的时间。事实上,所有关系的一方或另一方都可能为零。您甚至可以通过将地址的FK放在Customer行并创建字段word.contains(stopword)来将关系转换为1:m。您仍然可以拥有任何客户都没有引用的地址。

乍一看,m:n可能看起来像个例外。通常定义交集条目,使得FK都不能为空。但是可能有客户和地址都没有引用它们的条目。所以这真的是一个0..m:0..n的关系。

它是什么?我曾与之合作的每个人都明白“一个”(如1:1)或“多个”(如1:m或m:n)意味着“不超过这个”。没有“确切地说,没有更多或更少”。例如,我们可以在纸上设计1:3的关系。我们不能在任何数据库中严格执行它。我们必须使用触发器,存储过程和/或计划任务来寻找并引起我们对偏差的注意。例如,每周执行一次存储过程,它将查找并标记或删除任何此类孤立的地址。

把它想象成“无摩擦的表面”。它只存在于纸上。

答案 5 :(得分:0)

是的,实际上非常简单:只需将两个实体放在同一张桌子上即可!

OTOH,如果你需要将它们保存在some reason的单独表中,那么你需要一个表中的一个键引用 1 一个键在另一个表中,而反之亦然即可。当然,这代表了鸡肉和鸡蛋等#34;问题 2 可以通过推迟强制执行FK到事务结束 3 来解决。这仅适用于支持延迟约束的DBMS(例如OraclePostgreSQL)。

1 通过外键。

2 在第一个表中插入一行是不可能的,因为这会违反第二个表的参照完整性,但是在第二个表中插入一行是不可能的,因为这会违反对第一个表等的引用完整性...同样删除。

3 所以你只需插入两行,然后检查两个FK。

答案 6 :(得分:0)

我认为这个问题是一个概念上的误解。 关系介于不同的之间。具有“真正的一对一关系”的事物根据定义相同的事物的方面或属性,并且属于同一个表。不,当然一个人和地址不一样,但如果它们是不可分割的,并且必须始终作为一个单元插入,删除或以其他方式行事,那么作为数据它们是“相同的东西”。这正是这里描述的内容。