表格之间的外键交叉引用

时间:2015-07-11 09:55:50

标签: ruby-on-rails database activerecord database-design schema

我是数据库设计的初学者。所以我有两个用于实现多项选择的表,一个名为MC,用于保存问题,MC_choice用于保存每个问题的选项。因此MC_choice有一个外键限制为引用MC。到目前为止,非常好。

在我的第一次迭代中,我使用布尔列在MC_choice表中存储了正确的选择。然后我想,嗯,有一些冗余和潜在的更新异常,并且由于哪个选择是正确的,在功能上取决于问题本身,我将在{{1}中存储正确的选择表自己。

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

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

2 个答案:

答案 0 :(得分:1)

您滥用“功能依赖”。这适用于一个表中的列集。你的意思是问题的正确答案是问题的函数。

情况确实只是“喜欢”“递归”。 FK表引用中有一个循环。但这并没有定义 FKs彼此,所以没有递归。我们可以说这两个表是相互或同时受约束的。或者更清楚地说,某些约束限制了两个表。 (可以表示为两个FK约束的结合。)

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

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周期。 (此外,问答的FK不需要声明/明确,因为它们是FK对要约及其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])

因为表的成员资格条件的AND是表格的NATURAL JOIN的成员资格标准,

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

1)如果我想坚持这个递归的外键引用,我该如何保存到数据库?

在SQL中,如果声明的FK子行有一些列为NULL(还有其他模式),那么DBMS会认为约束已满足。因此允许MC辅助可以为空。首先使用NULL辅助插入MC qid,然后将qid和aid插入MC_choice,然后将MC NULL更改为qid的MC_choice辅助。

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

  

2)这种设计有意义吗?我觉得功能依赖性对它有争议,但在实践中看起来很麻烦。

这很麻烦,但正确答案是其问题的一个功能并不意味着答案必须在任何特定的表格中提出问题。

  

3)Rails中的ActiveRecord是否支持这种操作?

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

  

4)如果上面的架构很愚蠢,我应该如何设计我的表?

在最好和愚蠢之间存在一些分歧,即繁琐并不意味着愚蠢,而只是使用上述设计,或者这种变体:

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

始终尝试识别最简单的表谓词(成员资格条件,句子模板,填写[named-]空白语句),以便描述您的情况。您可能希望将多个表收集到一个表中,但对于函数关系的位置可能有多个选择。

答案 1 :(得分:0)

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

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 

插入新问题时,请在null列中插入Question_Correct_Answer,并在插入问题答案时填写。
问题及其答案的插入应该在一个单独的交易中,因此如果没有它的答案及其正确的答案ID,就无法插入问题。

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

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

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)
相关问题