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

dea*_*ode 13 erd database-design

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

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

我至少有这些实体:

  • 民意调查

至少有这些关系:

  • 每个调查有 1 个或多个问题。
  • 每个问题可用于 0 个或多个调查。
  • 每个人可以参加 0 个或多个调查。

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

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

方法一: 方法一

我不喜欢这种方法的地方:

  • survey_person_question_response表有两个不同的列引用调查:survey_question_survey_idsurvey_person_survey_id
    • survey_id在这两列的一行中引用不同的是错误的。survey_question 必须与该人在survey_person 中进行的调查来自同一个调查。我看不出有什么好的方法来强制执行此操作。
  • 似乎我在这里所做的是在两种关系之间建立关系。出于某种原因,这对我来说是错误的。

方法二:

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

我不喜欢这种方法的地方:

  • 没有强制规定question_idsurvey_idFK 来自有效的survey_question
  • 没有强制规定survey_idperson_idFK 来自有效的survey_person

任何建议:

  • 这些方法之一是否是典型方法
  • 其中一种方法相对于另一种方法的优缺点
  • 完全安排这些数据的更好方法

将不胜感激!

MDC*_*CCL 12

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

  1. 实体类型PersonSurvey之间的关系(或关联)类型;
  2. SurveyQuestion之间的关系类型;
  3. 在上述两种关系类型之间建立联系的关系类型,因此,在PersonSurveyQuestion之间建立联系,即Response(从我的角度来看,这是一个简化解释的较短名称)。

因此,我认为您的方法 1 走在正确的轨道上,尽管它需要一些小的(但重要的)改进以使其更准确。我将在以下部分详细介绍此类改进和其他相关考虑因素。

商业规则

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

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

说明性IDEF1X图

然后,我在 IDEF1X 中创建了一个图,如图 1 所示,它综合了上面制定的业务规则:

图 1 简化调查 IDEF1X


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


PersonSurvey关系

在我看来,PersonSurvey关系需要提供一种授权方式,以便Person可以参与给定的Survey。这样,一旦某个人在特定调查中注册,他或她就被授权对集成了相应调查问题提供答复

SurveyQuestion关系

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

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

响应实体类型

是的,使用Response实体类型,我描述了另外两个关系之间的关系;它可能乍一看尴尬,但有什么不对这种方法,只要它(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)
);
Run Code Online (Sandbox Code Playgroud)

Response表中的两个复合外键

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

  1. SurveyQuestion.SurveyNumber, 和
  2. SurveyPerson.SurveyNumber

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

如 DDL 设计所示,第一个 FK 是对PersonSurvey表 PRIMARY KEY (PK)的引用,即(PersonId, SurveyNumber),并且符合列Response.PersonIdResponse.SurveyNumber

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

通过这种方式,该Response.SurveyNumber列非常有用,因为它在两个不同的约束中用作 FK 参考的一部分。

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

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

派生数据以避免更新异常

我注意到你的图中有两个值得一提的元素。这些元素与PersonSurvey可以(应该)导出的两列相关。

在这方面,您可以PersonSurvey.IsStarted通过查询给定的Person事件是否提供了一个或多个Responses以通过表Questions集成一个精确的Survey来导出数据SurveyQuestion

并且您还可以PersonSurvey.IsCompleted通过确定给定Person实例是否已将 a 提供Response给所有在特定行QuestionsIsMandatory列中包含'TRUE' 值的值来获取数据点SurveyQuestion

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

重要考虑

正如@Dave在他的评论中正确指出的那样,如果您未来需要管理不同类型的响应,这意味着管理日期、数值、多项选择和其他可能的方面,您将不得不扩展此数据库布局。