最佳数据建模方法,用于处理有关调查,问题和响应的数据库中的冗余外键


13

我正在寻找有关最佳关系建模方法以存储调查,问题和响应的建议。

我正在寻找以下两种方法中哪一种看起来最好,或者是另一种替代方法。

我至少有以下实体:

  • 调查

至少这些关系:

  • 每个调查有1个或多个问题。
  • 每个问题可用于0个或更多调查中。
  • 每个人可能进行0项或多项调查。

这是我遇到麻烦的地方:如何对个人调查问题的回答建模。

这是我考虑过的两种方法,对我来说都不是很好。此处的图已大大简化以说明问题。

方法1: 方法1

我不喜欢这种方法:

  • survey_person_question_response表有两个引用调查的不同列:survey_question_survey_idsurvey_person_survey_id
    • 如果survey_id这两行在一行中引用了不同的,那将是一个错误。survey_question必须与接受survey_person的人来自同一调查。我看不出执行此操作的好方法。
  • 似乎我在这里所做的是在两个关系之间建立关系。由于某种原因,我觉得这很不对劲。

方法二:

尝试避免方法1中的两个FK应该引用相同的值... 在此处输入图片说明

我不喜欢这种方法:

  • 没有强制执行,question_id并且survey_idFK来自有效survey_question
  • 没有强制执行,survey_id并且person_idFK来自有效survey_person

关于以下方面的任何建议:

  • 这些方法之一是否是典型方法
  • 这些方法之一相对于其他方法的利弊
  • 更好地安排这些数据的更好方法

将不胜感激!

Answers:


12

根据我对您的规范的理解,您的业务环境涉及概念级别的三元关系。在这方面,您需要定义:

  1. 实体类型人员调查之间的关系(或关联)类型;
  2. 调查问题之间的关系类型;
  3. 建立上述两种关系类型之间的关系的关系类型,并因此在PersonSurveyQuestion之间建立关系,即Response(从我的角度来看,这是简化解释的简称)。

因此,我认为您的方法1处在正确的轨道上,尽管它需要一些小(但很重要)的改进才能使其更加准确。我将在以下各节中详细介绍这种改进和其他相关注意事项。

商业规则

让我们稍微扩展适用的业务规则,并通过以下方式重新制定它们:

  • 一个在零一个或多个调查中注册
  • 一个调查获得的零一或一对多的注册
  • 一个调查是由一个一对多的集成问题
  • 集成了零一或一对多调查
  • 一个问题收到零个或多个答复
  • 响应由恰好酮提供在恰好酮的背景调查

信息库IDEF1X图表

然后,我已经创建了IDEF1X 一个是在呈现图图1,其合成上述配制的业务规则:

图1简化的测量IDEF1X


一个 用于信息建模集成定义 IDEF1X)是被确立为一个非常可取的建模技术标准通过标准的美国国家技术研究所(1993年12月 NIST)。它是有坚实基础的由创作理论工作独资创办的的关系模型,即 EF科德博士也对实体关系图由开发 PP Chen博士


人员调查关系

正如我所看到的,要求PersonSurvey关系提供一种授权方式,以便一个可以参加给定的Survey。这样,一旦某人已在特定调查中注册,则他或她被授权对整合了各自调查问题提供答复

SurveyQuestion关系

我假设您图中的suvery_question.question_number属性(或属性)用于表示给定Question实例相对于特定Survey的表示顺序。如您所见,我已将该属性表示为SurveyQuestion.PresentationOrder,并且我认为您应该防止(i)两个或多个Question.QuestionNumber值共享(ii)在(iii)同一SurveyQuestion事件中共享相同的PresentationOrder值。

为了描述这种需求,我在代表该实体类型的框中添加了一个组合的ALTERNATE KEY(AK),它由属性的组合(SurveyNumber,QuestionNumber,PresentationOrder)组成。如您所知,可以在多列UNIQUE约束的帮助下以逻辑DDL设计声明复合AK(正如我在示例SurveyQuestion性DDL布局的一部分表格中所举例说明的那样,在以下几节中进行了阐述)。

响应实体类型

是的,对于响应实体类型,我正在描述其他两个关系之间的关系;它可能乍一看尴尬,但有什么不对这种方法,只要它(a)代表的准确利息及(b)业务环境的特点是在逻辑层次布局适当的代表。

是的,您完全正确,通过从同一行中两个不同列引用的两个Response.SurveyNumber(或Response.SurveyId)值在逻辑抽象级别上描述场景的那部分是错误的Response

派生逻辑SQL-DDL布局

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- As one would expect, you are free to make use of 
-- your preferred (or required) naming conventions.

CREATE TABLE Person (
    PersonId        INT      NOT NULL,
    FirstName       CHAR(30) NOT NULL,
    LastName        CHAR(30) NOT NULL,
    GenderCode      CHAR(3)  NOT NULL,
    BirthDate       DATE     NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Person_PK PRIMARY KEY (PersonId),
    CONSTRAINT Person_AK UNIQUE      (
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    )
);

CREATE TABLE Survey (
    SurveyNumber    INT       NOT NULL,
    Description     CHAR(255) NOT NULL,
    CreatedDateTime DATETIME  NOT NULL,
    --
    CONSTRAINT Survey_PK PRIMARY KEY (SurveyNumber),
    CONSTRAINT Survey_AK UNIQUE      (Description)
);

CREATE TABLE PersonSurvey (
    PersonId           INT      NOT NULL,
    SurveyNumber       INT      NOT NULL,
    RegisteredDateTime DATETIME NOT NULL,
    --
    CONSTRAINT PersonSurvey_PK         PRIMARY KEY (PersonId, SurveyNumber),
    CONSTRAINT PersonSurveyToPerson_FK FOREIGN KEY (PersonId)
        REFERENCES Person (PersonId),
    CONSTRAINT PersonSurveyToSurvey_FK FOREIGN KEY (SurveyNumber)
        REFERENCES Survey (SurveyNumber)
);

CREATE TABLE Question (
    QuestionNumber  INT       NOT NULL,
    Wording         CHAR(255) NOT NULL,
    CreatedDateTime DATETIME  NOT NULL,
    --
    CONSTRAINT Question_PK PRIMARY KEY (QuestionNumber),
    CONSTRAINT Question_AK UNIQUE      (Wording)
);

CREATE TABLE SurveyQuestion (
    SurveyNumber       INT      NOT NULL,
    QuestionNumber     INT      NOT NULL,
    PresentationOrder  TINYINT  NOT NULL,
    IsMandatory        BIT      NOT NULL,
    IntegratedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT SurveyQuestion_PK PRIMARY KEY (SurveyNumber, QuestionNumber),
    CONSTRAINT SurveyQuestion_AK UNIQUE      (
        QuestionNumber,
        SurveyNumber,
        PresentationOrder
    ),
    CONSTRAINT SurveyQuestionToSurvey_FK   FOREIGN KEY (SurveyNumber)
        REFERENCES Survey   (SurveyNumber),
    CONSTRAINT SurveyQuestionToQuestion_FK FOREIGN KEY (QuestionNumber)
        REFERENCES Question (QuestionNumber)
);

CREATE TABLE Response (
    SurveyNumber     INT      NOT NULL,
    QuestionNumber   INT      NOT NULL,
    PersonId         INT      NOT NULL,
    Content          TEXT     NOT NULL,
    ProvidedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Response_PK                 PRIMARY KEY (SurveyNumber, QuestionNumber, PersonId),
    CONSTRAINT ResponseToPersonSurvey_FK   FOREIGN KEY (PersonId, SurveyNumber)
        REFERENCES PersonSurvey   (PersonId, SurveyNumber),
    CONSTRAINT ResponseToSurveyQuestion_FK FOREIGN KEY (SurveyNumber, QuestionNumber)
        REFERENCES SurveyQuestion (SurveyNumber, QuestionNumber)
);

Response表格中的两个复合外键

这可能是讨论中最重要的一点:从给定Response行到

  1. SurveyQuestion.SurveyNumber
  2. SurveyPerson.SurveyNumber

必须具有匹配的值。就我而言,以声明方式强制执行此条件的最佳选择是使用两个复合外键(FK)。

如DDL设计所示,第一个FK正在引用PersonSurvey表PRIMARY KEY(PK),即,(PersonId, SurveyNumber)并由Response.PersonId和所组成Response.SurveyNumber

第二个FK指向SurveyQuestion表PK,即(SurveyNumber, QuestionNumber),并且因此由列Response.SurveyNumber和组成Response.QuestionNumber

这样,Response.SurveyNumber由于在两个不同的约束中将其用作FK引用的一部分,因此该列非常有用。

使用这种方法,可以确保数据库管理系统从以下方面保证引用完整性:

  • (a)ResponsePersonSurvey
  • (b)ResponseSurveyQuestion;和
  • (c)中每一个代表一个关联实体类型静置独立的实体类型,即表中的表PersonSurveyQuestion

派生数据以避免更新异常

我已经在您的图中注意到了我值得一提的两个要素。这些元素与PersonSurvey可以(应该)派生的两列有关。

在这方面,你可以得出PersonSurvey.IsStarted一个给定的通过查询基准Person的发生提供了一个或多个ResponsesQuestions该确切的整合Survey通过SurveyQuestion表。

而且,您还可以PersonSurvey.IsCompleted通过确定给定Person实例是否在特定行的列中Response向所有提供Questions共同值为'TRUE'的实例提供a 来获取数据点。IsMandatorySurveyQuestion

通过推导这些值,可以防止某些更新异常,如果将这些值保留在该SurveyQuestion列中,这些更新异常最终会出现。

重要考虑

正如@Dave在他的评论中正确指出的那样,如果您面对将来的需求,要求管理各种不同的响应,这些响应暗示着管理日期,数值,多项选择以及其他可能的方面,那么您将必须扩展此数据库布局。


1
哇,这完全回答了我的问题,然后教给我更多!由于意见应提出改进建议:它是稍微有一些混乱既结束了按键IDNumber,但在其他方面,这是梦幻般的。谢谢。
Zach Mierzejewski

@Zach非常欢迎您,我很高兴该帖子对您有所帮助。感谢您的反馈意见,我们强烈要求进行一些改进。
MDCCL '18 -10-23

1

这就是为什么我不喜欢在将列迁移为外键时给它们加上前缀的原因之一。在第一种情况下,建模工具可能会强制您为survey_id表中的列添加前缀survey_person_question_response。建立关系后,您也许可以调整此设置。

如果需要,在构建不需要重复列的物理模型时,请删除多余的调查ID字段。如您所确定的,两个模型都存在问题,但是我相信第一个模型总体上会更好。


感谢您的洞察力-我确实将物理模型中的第1栏折叠了下来,以实施我想要的所有内容。
死码2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.