代码之家  ›  专栏  ›  技术社区  ›  Samir

同一业务规则的多个外键

  •  -1
  • Samir  · 技术社区  · 8 年前

    让我们跳到一个示例,该示例演示了引用多个表的表:

    CREATE TABLE Corses
    (
       ID int PRIMARY KEY,
       .....
    )  
    
    CREATE TABLE Questions
    (
        ID int PRIMARY KEY,
        .....
    )
    
    CREATE TABLE Answers
    (
        ID int PRIMARY KEY,
        .....
    )
    
    CREATE TABLE Files
    (
        ID INT PRIMARY KEY,
    
        Corse_ID INT,
        Question_ID INT,
        Answer_ID INT,
    
        FOREIGN KEY (Corse_ID) REFERENCES Corses(ID),
        FOREIGN KEY (Question_ID) REFERENCES Questions(ID),
        FOREIGN KEY (Answer_ID) REFERENCES Answers(ID)
    )
    

    上面的例子说明了学习应用程序中与其他对象(corse、questions和answers)的文件关系,所有对象的业务规则都是相同的,如下所示:

    • 一个对象可以没有或多个附加文件 这就形成了1对多的关系,并如上所述。

    我的问题:

    当业务规则为1-Many时,这会使文件的其他Forign Key列过时,例如,如果一个文件附加到一个问题(如屏幕截图)上,则它仅附加到该问题,而不附加到答案和corse。 每次出现时实际上只使用一个外键。 必须有更好的方法来模拟这种情况。

    当添加基于同一业务规则的多个一对多关系时,当子表必须依赖于父表中的一行(文件必须附加到对象上)时,我不能添加“not NULL”约束来实施此规则,因为我不知道我的文件将附加到哪个对象。

    2 回复  |  直到 8 年前
        1
  •  1
  •   Jesús López Sean Lange    8 年前

    这里有一个没有这些问题的替代设计:

    CREATE TABLE Objects
    (
        Id int PRIMARY KEY
    );
    
    CREATE TABLE Courses
    (
       CourseId int PRIMARY KEY,
       CONSTRAINT FK_Courses_Objects FOREIGN KEY (CourseId) REFERENCES Objects(Id)
    )  
    
    CREATE TABLE Questions
    (
        QuestionId int PRIMARY KEY,
        CONSTRAINT FK_Questions_Objects FOREIGN KEY (QuestionId) REFERENCES Objects(Id)
    
    )
    
    CREATE TABLE Answers
    (
        AnswerId int PRIMARY KEY,
        CONSTRAINT FK_Answers_Objects FOREIGN KEY (AnswerId) REFERENCES Objects(Id)
    
    )
    
    CREATE TABLE Files
    (
        FileId int PRIMARY KEY,
        ObjectId int NOT NULL CONSTRAINT FK_Files_Objects REFERENCES Objects(Id)
    )
    

    CREATE TABLE Files
    (
        FileId int PRIMARY KEY,
    
        CourseId int REFERENCES Courses(CourseId),
        QuestionId int REFERENCES Questions(QuestionId),
        AnswerId int REFERENCES Answers(AnswerId),
    
        CONSTRAINT CHK_JustOneObjectReferenced  CHECK (
            CourseId IS NOT NULL AND QuestionId IS NULL AND AnswerId IS NULL
            OR CourseId IS NULL AND QuestionId IS NOT NULL AND AnswerId IS NULL
            OR CourseId IS NULL AND QuestionId IS NULL AND AnswerId IS NOT NULL
        )
    )
    
        2
  •  1
  •   Samir    8 年前

    这个问题可能有多个答案,但我下面的答案4是一个更好的解决这个多态性关联在我的意见。

    1. 基数设计:

      • 每个文件的出现只使用一个FK,其余的已过时。
      • 不为空 检查
    2. 创建一个带有ID列的基本抽象对象表,并在引用抽象对象表ID并最终引用File表中抽象对象表ID的所有对象表(Corse、Question and Answer)中添加FK。 该设计存在以下问题:

      • 当一个对象被创建时,它是用来表示一个Corse、一个问题或一个答案(只有一个对象和一个对象),但是使用这个设计,我可以创建一个假设是一个问题的Objet,并使用相同的对象来表示Corse。 检查 必须使用带函数的约束来避免这种情况。
    3. 基于对象类型的设计: 独一无二的 对ObjectType_ID和Object_ID列的约束。 本设计存在以下问题:

      • 文件可以附加到根本不存在的(corse、Questions或Answers)。 必须使用带函数的约束来避免这种情况。
    4. 多种多样的设计: 即使对象(Corse、Question或Answer)和文件之间的关系是1-Many,但它相当于修改关系表PK的多个关系。 这是文件Corse关系的DDL,问题和答案也是一样的:


    CREATE TABLE Files
    (
        ID INT PRIMARY KEY,
        .....
    )
    
    CREATE TABLE Corses
    (
       ID INT PRIMARY KEY,
       .....
    )
    
    CREATE TABLE Files_Corses
    (
        File_ID INT PRIMARY KEY,
        Corse_ID INT NOT NULL,
    
        FOREIGN KEY (File_ID) REFERENCES Files(ID),
        FOREIGN KEY (Corse_ID) REFERENCES Corses(ID)
    )