【问题标题】:SQL One-to-Many Table vs. multiple one-to-one relationshipsSQL 一对多表与多个一对一关系
【发布时间】:2011-08-24 22:25:49
【问题描述】:

我正在开展一个具有以下目标的项目:用户可以创建一个挑战并选择一个可选的竞争对手来参加这个挑战。挑战会生成每日条目,并将跟踪这些条目的统计数据。

基本的 User 和 Entry 实体如下所示:

CREATE TABLE users (
    id (INT),
    PRIMARY KEY (id)
);

CREATE TABLE entries (
    challengeId INT,
    userId INT,
    entryDate DATE,
    entryData VARCHAR,
    PRIMARY KEY (challengeId, userId, entryDate)
)

我遇到问题的部分是带有竞争对手概念的挑战部分。我可以看到两种方法。

// Hard code the concept of a Challenge Owner and Rival:
CREATE TABLE challenges (
    id INT,
    name VARCHAR,
    ownerId INT,
    rivalId INT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY (ownerId, name)
);

// Create Many-to-one relationship.
CREATE TABLE challenges (
    id INT,
    name VARCHAR,
    PRIMARY KEY (id),
    UNIQUE KEY (name)
)
CREATE TABLE participant (
    challengeId INT,
    userId INT,
    isOwner BIT,
    PRIMARY KEY (challengeId, userId)
)

第一种方法的问题是参照完整性很难,因为现在有两列 userId 驻留(ownerId 和 CompetitionId)。为了设置外键,我必须为所有内容(owner_entries、competitive_entries、owner_stats 等)创建两个表。

第二种方法解决了这个问题,并且具有一些优势,例如将来允许多个竞争对手。但是,我不能再用这种方法做的一件事是在单个用户而不是整个挑战表中强制挑战名称唯一性。此外,寻找挑战所有者等任务现在变得更加棘手。

挑战表的正确方法是什么?无论如何以开发人员友好的方式设置这些表,还是我应该一直跳到类表继承并在那里管理所有者/竞争对手的概念?

【问题讨论】:

  • 您使用的是什么数据库?我们一直在 SQL Server 中对同一个 pk 字段执行多个外键。这消除了您对第一种方法的反对。如果您需要超过 2 个人参与挑战,则第二种方法可能仍然更好。
  • 他真正反对的不是为同一个 pk 字段设置多个 fk(他无论如何都在这样做),而是将单个 fk 字段设置为多个 pk。我认为这在任何情况下都是不可能的,除了相当有问题......
  • 我经常在 SQL Server 中使用触发器来强制执行特殊的唯一性要求,例如“用户名”只需要在活动帐户中是唯一的。

标签: sql schema one-to-many one-to-one class-table-inheritance


【解决方案1】:

我认为我的设置方式如下(使用第二种方法):

CREATE TABLE challenges (id INT, 
                         name VARCHAR, 
                         owner_id INT, 
                         PRIMARY KEY (id),
                         UNIQUE KEY (name, owner_id))

CREATE TABLE participant (challengeId INT,
                          userId INT, 
                          PRIMARY KEY (challengeId, userId))

这可以轻松跟踪拥有挑战,同时提取个别参与者。
这也将允许您安全地由所有者唯一地挑战名称,并且participant 中的userId 上的外键很容易。那么“竞争对手”就是所有不是挑战所有者的参与者。

【讨论】:

    【解决方案2】:

    我认为第一种方法是正确的。 您可以有一张供用户使用的表格,一张供挑战使用。

    你知道你可以像下面这样引用一个表两次吗?

    SELECT * FROM CHALLENGES 
    INNER JOIN USERS AS OWNERS ON OWNERS.ID = CHALLENGES.OWNERID
    INNER JOIN USERS AS RIVALS ON RIVALS.ID = CHALLENGES.RIVALID
    

    在这种情况下,您无需创建新表即可同时引用竞争对手和所有者。

    【讨论】:

    • 获得这样的用户很容易,我关心的是条目和可能的统计信息。以我描述的条目模型为例,我如何在单个表中跟踪用户条目,同时强制执行参照完整性,以便只有属于挑战的用户才能进行条目?似乎我需要一个带有 challengeId 和 ownerId 的 OwnerEntries 表,然后是一个带有 challengeId 和竞争者Id 的 RivalEntries 表。
    • 在这种情况下,您可以添加一个引用挑战的统计表,具体取决于确切需要的数据。或者,您可以将一种审核模式应用于您的表:查看this 帖子。
    猜你喜欢
    • 1970-01-01
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 2021-07-11
    相关资源
    最近更新 更多