如何解决外键约束

时间:2019-04-11 01:21:23

标签: sql sql-server

我正在创建一个选择题测验数据库,当我尝试创建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
);

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

2 个答案:

答案 0 :(得分:0)

虽然确实是多余的,但是您根本不需要在QuestionID中的CorrectAnswer列,而以下设计将解决当前的问题:

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中必须存在一行,因为何时才能执行该操作?),这仅仅是因为它将意味着您必须首先插入正确的答案。

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

答案 1 :(得分:0)

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

  • 删除操作将直接级联到AnswerChoices
  • 删除操作将直接级联到CorrectAnswer,因为CorrectAnswer和 选择与级联具有必要的一对多关系 启用删除功能后,它将从AnswerChoices级联到 CorrectAnswer

因此,您有两个从“问题”到“ 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现在具有一对多关系。删除问题将删除正确的答案行。现在,答案可以与不同的问题关联。

再次,答案是问题的孩子还是独立的孩子,这取决于您的要求。