5

假设我有一个一对多的关系,其中有两个表,一个 Person 表和一个 Belonging 表。现在,每个人只有一个最喜欢的物品,一个特定的物品也不能属于另一个人。

我的问题是,这些信息最好保存在哪里?在 Person 表中作为 favorite_belonging_id 还是在 Belonging 表中作为 is_favorite 条目?在我看来,首选似乎是更好的版本,但我想听听懂sql的人对此有什么看法。

编辑:一个人有很多物品,但只有一件最喜欢的物品,每件物品只能属于一个人。这是一个一对多的关联。

4

7 回答 7

3

我很想采纳您的第一个建议(表favourite_belonging_id中的一列),因为然后可以在Person表中创建外键引用 from (person_id, favourite_belonging_id)to 。(owner_id, belonging_id)Belonging

如果要走另一条is_favourite在表中创建标志的路线Belonging,则没有明显的方法可以确保个人最喜欢的所有物关系的 1:1 本质(当一个人拥有UNIQUE多个(owner_id, is_favourite)不属于他们的最爱)。

也就是说,感觉这些信息并不真正属于表格,Person因为它实际上不是个人的财产,而是Belonging. 如果您对此有强烈的感觉,您可以创建一个Favourites具有UNIQUE(或PRIMARY)索引的表person_id

于 2012-07-07T19:03:21.903 回答
2

对我来说,它不属于 person 表,因为它与 base person 无关。

如果你只有归属表——我也假设其中有一个 person_id,那么这就是你表达归属与人之间关系的地方,也是限定符应该去的地方。

另一种选择是在中间放置第三张桌子连接两者 - 在这种情况下,最喜欢的标志放在那里。

编辑:我在设计中的偏好是第三个表格选项-在这里您可以输入开始日期和结束日期以及最喜欢的标志-理论上这将允许您在某个时间点交易属于另一个人的物品并且仍然知道发生了什么。

于 2012-07-07T18:48:53.340 回答
1

我看到几乎所有不同的选项都已经在不同的答案中列出,但是我不会对所有选项进行评论以让您对我认为您应该做什么的印象,而是自己创建一个答案。

只是为了清楚我如何理解系统的工作原理:所有用户都可以拥有多个物品,但任何物品只能由一个人帮助。

在这种情况下,最有意义的做法是在物品表中拥有一个 user_id,它可以将物品与一个人联系起来。一旦设置了 user_id,其他人就不能再声明它了。

现在,至于“最喜欢”的部分,您可以做几件事。真正做到这一点的最佳方法在很大程度上取决于您计划在其上运行的查询。有些人考虑添加一个 JOIN 表,但老实说,这是很多没有意义的额外数据;其中可能会有与用户表完全相同的行数,并且通过将其放在单独的表中,您无法做很多事情(例如,看看有多少人没有收藏夹) . 同样,JOIN 表对于 user_belonging 关系也没有意义,因为所有权和可以拥有它的人数之间存在 1:1 的关系。
所以我相信有两个可行的选择:要么在物品表中添加一个字段(/switch)以指示用户的物品是他/她的最爱,或者向用户表添加一个字段以指示用户最喜欢的物品。我个人认为后者最有价值,但根据您运行的查询,前者可能更有意义。总体而言,最大的区别在于您是要处理预插入还是后选择;例如,在后一种情况下,您将不得不运行一个独立的查询来确定用户是否已经收藏(在前一种情况下,这不是必需的,因为您将在用户表中的字段上放置一个唯一索引) ,

如果我清楚地解释了自己,或者您有任何其他问题,请告诉我。

于 2012-07-07T19:25:28.470 回答
1

以下可能不是最佳选择,因为它提供了一种非常规的方法来标记最喜欢的物品。不过,这样做的好处是,您将只有两张没有循环引用的表,并且可以保证每个人都拥有不超过一个最喜欢的物品。

所以,这是两个表,people(或persons)和belongings。该people表具有以下结构:

person_id INT AUTO_INCREMENT,
other columns as necessary,

PRIMARY KEY (person_id)

belongings表是这样创建的:

belonging_id INT AUTO_INCREMENT,
person_id    INT NOT NULL,
is_favourite enum ('1'),
other columns as necessary,

PRIMARY KEY (belonging_id),
FOREIGN KEY (person_id) REFERENCING people (person_id),
UNIQUE (person_id, is_favourite)

关键元素声明为具有单个可能值is_favourite的可空值。enum这样,当您在 的对上声明唯一约束时(person_id, is_favourite),您可以拥有尽可能多的相同person_id且为空 (null)is_favourite的行,因为唯一约束忽略至少一个成员为空的行。而且您将无法创建多个person_idwith is_favourite = '1',因为会违反唯一约束。

于 2012-07-07T21:26:28.373 回答
1

两者都不。我的建议是添加另一个表person_favourite_belonging,如下所示:

CREATE TABLE person
( person_id INTEGER NOT NULL
--- various other columns about Persons
, PRIMARY KEY (person_id)
) ;

CREATE TABLE belonging
( belonging_id INTEGER NOT NULL 
, person_id INTEGER NOT NULL 
--- various other columns about Belongings
, PRIMARY KEY (belonging_id)
, UNIQUE KEY (person_id, belonging_id)       --- this Unique constraint is needed
, FOREIGN KEY (person_id)
    REFERENCES person (person_id)
) ;

CREATE TABLE person_favourite_belonging
( person_id INTEGER NOT NULL 
, belonging_id INTEGER NOT NULL
, PRIMARY KEY (person_id)
, FOREIGN KEY (person_id, belonging_id)      --- for this Foreign Key constraint
    REFERENCES belonging (person_id, belonging_id)
) ;

这只是我的首选方式。有替代方案,并且都有其优点和缺点。这种方法的优点是:

  • 外键约束中没有循环路径(因此):
  • 插入、删除或更新人员、物品或收藏物品时没有鸡和蛋问题。
  • 所有外键列都可以定义为 NOT NULL。
  • 可以在数据库级别强制执行完整性。
  • 如果您的要求发生变化并且您希望每人拥有 2 个(或更多)收藏夹,您只需适当更改收藏夹表中的约束即可。

还要检查我在这个问题中的回答(有一个几乎相同的问题):在 SQL 中,两个表可以相互引用吗?

于 2012-07-07T21:38:58.800 回答
0

favourite_thing 是归属表的 FK(如果该表存在,否则它可能是域),但在附加约束中,您可以强制 person 表中的 belongs_id 是唯一的。

更新:

DROP table belonging;
CREATE table belonging
        ( id INTEGER PRIMARY KEY
        , description varchar
        );

DROP table person;
CREATE table person
        ( id INTEGER PRIMARY KEY
        , description varchar
        , favourite_thing INTEGER REFERENCES belonging (id)
        );

-- Now add the unique constraint
-- NOTE: favourite_thing can still be NULL
ALTER TABLE person
        ADD CONSTRAINT must_be_unique UNIQUE (favourite_thing)
        ;

更新2:如果每件物品都属于一个人,您可以在物品中添加一个所有者字段:

CREATE table belonging
        ( id INTEGER PRIMARY KEY
        , owner_id INTEGER NOT NULL REFERENCES person(id)
        , description varchar
        );

DROP table person CASCADE;
CREATE table person
        ( id INTEGER PRIMARY KEY
        , description varchar
        , favourite_thing INTEGER REFERENCES belonging (id)
        );

ALTER TABLE person
        ADD CONSTRAINT must_be_unique UNIQUE (favourite_thing)
        ;
于 2012-07-07T18:52:01.700 回答
-1

实际上,您呈现的是一对一的关系。因此,您可以: 1. 将其保存在 Person 表中。2. 把它放在归属表中。3. 把它放在两个里面。4. 把它放在单独的桌子上。

于 2012-07-07T18:47:47.600 回答