【问题标题】:Proper way to make a relation between multiple rows of single table在单表的多行之间建立关系的正确方法
【发布时间】:2017-10-24 22:07:51
【问题描述】:

我遇到以下情况:我想将一张表中的多条记录与某种关系连接起来。记录可能与其他记录没有联系,或者可能有多个(1 个或多个)。这种关系没有层次结构。

例如:

CREATE TABLE x
(
  x_id SERIAL NOT NULL PRIMARY KEY,
  data VARCHAR(10) NOT NULL
);

我想到了两个想法:

  1. 在此表中创建一个新列,其中将包含一些关系 ID。它不会引用任何东西。插入新记录时,我将生成新的relationId 并将其放在那里。如果我想将其他记录与这条记录连接,我将简单地放置相同的relationId。

例子:

CREATE TABLE x
(
  x_id NUMBER(19, 0) NOT NULL PRIMARY KEY,
  data VARCHAR(10) NOT NULL,
  relation_id NUMBER(19, 0) NOT NULL
);

insert into x values (nextval, 'blah', 1);
insert into x values (nextval, 'blah2', 1);

它将连接这两行。

优点:

  • 非常简单
  • 轻松查询以获取连接到特定记录的所有记录
  • 没有开销

缺点:

  • hibernate 实体将只包含relationId,不包含 相关记录(或者也许有可能?)

    1. 制作一个单独的连接表,并以多对多关系连接行。连接表将包含两列带有 ID,因此一个条目将连接两行。

例子:

CREATE TABLE x
(
  x_id SERIAL NOT NULL PRIMARY KEY,
  data VARCHAR(10) NOT NULL
);

CREATE TABLE bridge_x
(
  x_id1 NUMBER(19, 0) NOT NULL REFERENCES x (x_id),
  x_id2 NUMBER(19, 0) NOT NULL REFERENCES x (x_id),
  PRIMARY KEY(x_id1, x_id2)
);

insert into x values (1, 'blah');
insert into x values (2, 'blah2');

insert into bridge_x values (1, 2);
insert into bridge_x values (2, 1);

优点:

  • 归一化关系
  • 简单的休眠实体映射,包含相关的集合 记录

缺点:

  • 开销(有多个连接的行,必须插入每一对)

最好的方法是什么?除了这两种方法还有其他方法吗?

【问题讨论】:

  • 您能否更具体地说明允许哪些关系,哪些不允许?如果一行与其他行有多个连接,这是否意味着所有这些行都像一组一样相互连接? (例如,第 1 行、第 2 行、第 3 行是同一关系的一部分,它们不能是另一个关系的一部分)?
  • @AlexG,没错。行只能与一个或多个其他行存在一种关系。
  • 您的第一个想法似乎不错。我认为您应该允许“null”,并且仅在需要时设置relationId。如果记录单独存在于其关系中,则保留记录的 relationshipId 是没有意义的。
  • @AlexG 是否有可能将休眠实体映射到 Set 中的相关行列表?

标签: sql oracle hibernate database-design


【解决方案1】:

根据我的经验,最好的方法是使用您在第二个选项中所说的规范化。您在这里寻找的是创建一个foreign key

因此,如果您使用示例 2 中给出的示例,然后应用以下 SQL 语句,您将创建一个可以有 0 到多个关系的关系数据库。

ALTER TABLE `bridgex` ADD  CONSTRAINT `fk_1` FOREIGN KEY (`xID`) REFERENCES `x`(`xID`) ON DELETE NO ACTION ON UPDATE NO ACTION;

【讨论】:

  • 这真的是最好的选择吗?这种方法还有其他优点和缺点吗?
  • 个人是的,从你的问题来看,如果你想保持数据库的一致性并避免孤立数据,这似乎就是你正在寻找的东西(以确保你在 tablebridgeX 中的 x_id 实际上链接到 x_id在表 X 中。所以使用我上面给你的外键,这将确保如果你想从表 X 中删除一条记录,则必须先删除 bridgeX 中的所有记录。如果你想删除表 X 中的一行并删除表bridgeX中该行的所有关联数据,您可以在删除时将外键更改为CASCADE。
  • 另外,this stackoverflow thread 是一个了解外键优缺点的好地方。
猜你喜欢
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-03
相关资源
最近更新 更多