表之间的外键交叉引用

Foreign Key Cross-Reference Between Tables

我是数据库设计的初学者。所以我有两个 table 用于实现多项选择,一个称为 MC,用于保存问题,另一个称为 MC_choice,用于保存每个问题的选项。所以 MC_choice 有一个外键被限制为引用 MC。到目前为止,还不错。

在我的第一次迭代中,我使用布尔列将正确的选择存储在 MC_choice table 中。然后我想,嗯,有一些冗余和潜在的更新异常,因为哪个选择是正确的在功能上取决于问题本身,我将把正确的选择存储在 MC table本身。

所以我在 MC table 中添加了一个字段,它是一个限制指向 MC_choice 的外键。但是现在插入新的选择或问题变得非常困难,因为这两者现在就像递归约束一样。我正在使用 Rails 并且也是初学者,我觉得这种模式设计让我的生活变得相当困难。

1)如果我想坚持这个递归外键引用,如何保存到数据库?
2)这个设计有意义吗?我觉得功能依赖支持它,但在实践中似乎很麻烦。
3) Rails中的ActiveRecord是否支持这种操作?
4) 如果上面的模式很愚蠢,我应该如何设计我的 tables?

假设您的目标是将多项选择题及其答案保存在数据库中,我可能会这样做:

tblQuestions
------------
Question_Id (pk)
Question_Text
Question_Correct_Answer (nullable, fk to tblAnswers)

tblAnswers
----------
Answer_Id (pk)
Answer_Question_Id (fk to tblQuestion)
Answer_Text 

插入新问题时,在 Question_Correct_Answer 列中插入 null,并在插入问题答案时填充它。
问题及其答案的插入应该在单个事务中,这样就不可能在没有答案和正确答案 ID 的情况下插入问题。

要保留用户选择的答案,只需要保留答案id (因为每个答案只属于一个问题)。

向select问题文本和答案文本添加视图以显示结果,如下所示:

select question_text, 
       answer_text, 
       case when answer_Id = question_correct_answer then
         1
       else
         0
       end as IsCorrect
from tblUserAnswer
inner join tblAnswer ON(UserAnswer_Answer_Id = Answer_Id)
inner join tblQuestion  ON(Answer_Question_Id = Question_Id)

您在滥用 "functionally dependent"。这适用于一个 table 内的列集。你的意思是问题的正确答案是问题的函数。

情况确实只有"like""recursive"。 FK table 引用中有一个循环。但这并没有定义 FKs 彼此相关,所以没有递归。可以说两个table是相互约束或者同时约束的。或者更清楚地说,某些约束同时约束了 table。 (可以表示为两个FK约束的合取。)

您的情况可以用 tables 和简单的行成员资格标准来描述,如下所示:

Question(qid,text) -- question [qid] has text [text]
    key qid
Answer(aid,text) -- answer [aid] has text [text]
    key aid
Offers(qid,aid) -- question [qid] offers answer [aid]
    key (qid,aid)
    fk qid to Question, fk aid to Answer
Ok(qid,aid) -- [aid] is the right answer to [qid]
    key (qid,aid)
    fk (qid,aid) to Offers
    fk qid to Question, fk aid to Answer

这是一个简单的设计。碰巧没有 FK 循环。 (此外,Question and Answer 的 FK 不需要 declared/explicit,因为它们是 FK 对 Offers 及其 FK 的结果。)

可以通过多种方式组合这些。你选择了一些东西(有 FK 循环),比如:

MC(qid,text,aid)
    -- question [qid] has answer [aid]
    AND [aid] is the right answer to [qid]
MC_choice(aid,qid,text)
    -- question [qid] offers answer [aid]
    AND answer [aid] has text [text])

因为 tables 的成员标准的 AND 是 tables 的自然连接的成员标准,

MC = Question NATURAL JOIN Ok
MC_choice = Offers NATURAL JOIN Answer

1) If I want to insist on this recursive foreign key reference, how do I save to the database?

在SQL中,如果声明的 FK 子行有一些列为 NULL(对此还有其他模式),则 DBMS 认为约束已满足。所以允许 MC aid 可以为空。先插入一个mc qid,aid为NULL,然后把qid和aid插入MC_choice,然后把MC NULL改成qid的MC_choice aid.

但是在典型的 SQL DBMS 中,您不能有 FK 循环。 (没有充分的理由。)如果你的意思是你想要那些 tables 中的那些列,那么你可以删除 FK 声明但添加触发器。 SQL DBMS 仅提供少数声明性约束形式;一般来说,还必须使用触发器来表达约束。

2) Does this design make sense? I feel like the functional dependency argues for it, but seems so cumbersome in practice.

这很麻烦,但正确答案是其问题的函数这一事实并不意味着答案必须在任何特定的 table 中包含他们的问题。

3) Does ActiveRecord in Rails support this kind of operation?

是的。使 MC 模型 (table) 辅助字段(列)可为空。

4) If the above schema is just silly, how should I be designing my tables?

not best 和 silly 之间有一些区别,即 cumbersome 并不意味着愚蠢,而是使用上面的设计,或者这个变体:

MC = Question
MC_choice = Offers NATURAL JOIN Answer
MC_ok = Ok

始终尝试识别最简单的 table 谓词(成员资格标准、句子模板、填写-[命名-]空白语句)用于描述您的情况。您可能希望集数于一身 table,但函数关系的走向可能不止一种选择。