【问题标题】:How do I fix foreign key constraints如何修复外键约束
【发布时间】:2019-04-11 01:21:22
【问题描述】:

我正在创建一个多项选择测验数据库,当我尝试创建 CorrectAnswer 表时,我收到以下错误:

消息 1785,第 16 级,状态 0,第 15 行 在表 'CorrectAnswer' 上引入 FOREIGN KEY 约束 'FK__CorrectAn__Answe__5BE2A6F2' 可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 消息 1750,第 16 级,状态 1,第 15 行 无法创建约束或索引。查看以前的错误。

CREATE DATABASE PeriodicTableQuiz

CREATE TABLE Question(
QuestionID INT IDENTITY(1,1) PRIMARY KEY,
QuizQuestion VARCHAR(MAX) DEFAULT NULL
);

CREATE TABLE AnswerChoices(
AnswerID INT IDENTITY(1,1) PRIMARY KEY,
Answer VARCHAR(MAX) DEFAULT NULL,
QuestionID INT NOT NULL,
FOREIGN KEY(QuestionID) REFERENCES Question(QuestionID) ON DELETE CASCADE ON UPDATE CASCADE
);

CREATE TABLE CorrectAnswer(
CorrectAnswerID INT IDENTITY(1,1) PRIMARY KEY,
QuestionID INT NOT NULL,
FOREIGN KEY(QuestionID) REFERENCES Question(QuestionID) ON DELETE CASCADE ON UPDATE CASCADE,
AnswerID INT NOT NULL,
FOREIGN KEY(AnswerID) REFERENCES AnswerChoices(AnswerID) ON DELETE CASCADE ON UPDATE CASCADE
);

我想在 Question 表中插入问题,在 AnswersChoices 表中插入答案。 CorrectAnswer 应该有 QuestionID 和 AnswerID 分别引用 Question 和 AnswerChoices 表。

【问题讨论】:

  • 为什么CorrectAnswer bit 不只是AnswerChoices 中的一列?您可以轻松地将其限制为只有一个可能正确的答案,而无需引入所有这些(可能不必要的)级联复杂性 - 您不会找到很多粉丝。
  • 如果会有多个答案,您可以在答案表中创建另一列 IsCorrect。并且您不能在 CorrectAnswer 表上允许级联,因此如果您删除一个答案,您需要删除该问题,并且与该问题相关的所有答案,它将成为循环依赖。
  • @AaronBertrand 那么您是否建议在 AnswerChoices 表中添加一个 CorrectAnswer 列?
  • 您确实需要处理该架构。就像其他人指出的那样,CorrectAnswer 表是不必要的
  • 除了在AnswerChoices 中有一个标志似乎是最好的选择,在CorrectAnswer 中不需要QuestionID。加入AnswerChoices即可获得。

标签: sql sql-server


【解决方案1】:

虽然您确实不需要 QuestionID 中的 QuestionID 列,因为它是多余的,但以下设计将解决当前问题:

CREATE TABLE dbo.CorrectAnswer(
CorrectAnswerID INT IDENTITY(1,1) PRIMARY KEY,
AnswerID INT NOT NULL,
FOREIGN KEY(AnswerID) REFERENCES dbo.AnswerChoices(AnswerID) 
  ON DELETE CASCADE ON UPDATE CASCADE
);

我建议采用这种设计:

CREATE TABLE dbo.Questions
(
  QuestionID INT IDENTITY(1,1) PRIMARY KEY,
  Question VARCHAR(MAX) DEFAULT NULL
);

CREATE TABLE dbo.Answers
(
  AnswerID INT IDENTITY(1,1) PRIMARY KEY,
  Answer VARCHAR(MAX) DEFAULT NULL,
  QuestionID INT NOT NULL,
  IsCorrectAnswer bit NOT NULL,
  CONSTRAINT FK_Question FOREIGN KEY(QuestionID) 
    REFERENCES dbo.Questions(QuestionID) 
    ON DELETE CASCADE ON UPDATE CASCADE
);

约束不能强制每个问题只有一行正确,但您可以通过触发器强制执行此操作(此问题的范围蔓延)。强制至少一行可能有点棘手(很像在您的原始设计中强制在CorrectAnswer 中必须存在一行,因为你什么时候可以这样做?),仅仅是因为这意味着你必须先插入正确答案。

您可能还需要一些元数据来定义测验中出现的顺序选择,特别是如果您确实打算以某种可预测的顺序插入正确/错误的答案。

【讨论】:

    【解决方案2】:

    因为问题是必需的,所以涉及问题的所有一对多关系都启用了级联删除。这意味着,如果您删除一个问题

    • 删除将直接级联到 AnswerChoices
    • 删除将直接级联到 CorrectAnswer,因为 CorrectAnswer 和 AnswerChoices 与级联具有必需的一对多关系 启用删除后,它将从 AnswerChoices 级联到 正确答案

    因此,您有两个从 Question 到 CorrectAnswer 的级联删除路径 - 这会导致异常。

    您必须在至少一个表中将 QuestionId 设为可选。

    我提出以下建议:

    CREATE DATABASE PeriodicTableQuiz
    
    CREATE TABLE Question(
    QuestionID INT IDENTITY(1,1) PRIMARY KEY,
    QuizQuestion VARCHAR(MAX) DEFAULT NULL
    );
    
    CREATE TABLE Answer(
    AnswerID INT IDENTITY(1,1) PRIMARY KEY,
    Answer VARCHAR(MAX) DEFAULT NULL,
    );
    
    CREATE TABLE CorrectAnswer(
    CorrectAnswerID INT IDENTITY(1,1) PRIMARY KEY,
    QuestionID INT NOT NULL,
    FOREIGN KEY(QuestionID) REFERENCES Question(QuestionID) ON DELETE CASCADE ON UPDATE CASCADE,
    AnswerID INT NOT NULL,
    FOREIGN KEY(AnswerID) REFERENCES AnswerChoices(AnswerID) ON DELETE CASCADE ON UPDATE CASCADE
    );
    

    CorrectAnswer 现在具有一对多关系。删除问题将删除正确答案行。现在可以将答案与不同的问题相关联。

    同样,答案是子问题还是独立答案取决于您的要求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-19
      • 2019-10-26
      • 2016-03-27
      • 1970-01-01
      • 2014-01-20
      • 2022-08-22
      • 2019-01-11
      相关资源
      最近更新 更多