dea*_*ode 13 erd database-design
我正在寻找有关存储调查、问题和响应的最佳关系建模方法的建议。
我正在寻找以下两种方法中的哪一种看起来最好,或者另一种方法。
我至少有这些实体:
至少有这些关系:
这就是我遇到麻烦的地方:如何对一个人对调查问题的回答进行建模。
这是我考虑过的两种方法,对我来说似乎都不是很好。此处的图表已大大简化以说明问题。
我不喜欢这种方法的地方:
survey_person_question_response
表有两个不同的列引用调查:survey_question_survey_id
和survey_person_survey_id
survey_id
在这两列的一行中引用不同的是错误的。survey_question 必须与该人在survey_person 中进行的调查来自同一个调查。我看不出有什么好的方法来强制执行此操作。方法二:
尽量避免方法 1 中的两个 FK 应该引用相同的值......
我不喜欢这种方法的地方:
question_id
和survey_id
FK 来自有效的survey_question
对survey_id
和person_id
FK 来自有效的survey_person
对任何建议:
将不胜感激!
MDC*_*CCL 12
根据我对您的规范的理解,您的业务环境涉及概念级别的三元关系。对此,您需要定义:
因此,我认为您的方法 1 走在正确的轨道上,尽管它需要一些小的(但重要的)改进以使其更准确。我将在以下部分详细介绍此类改进和其他相关考虑因素。
让我们稍微扩展适用的业务规则并按以下方式重新制定它们:
说明性IDEF1X图
然后,我在 IDEF1X 中创建了一个图,如图 1 所示,它综合了上面制定的业务规则:
一个 用于信息建模集成定义( 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
。
-- 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
行到
SurveyQuestion.SurveyNumber
, 和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 参考的一部分。
使用这种方法,可以确保数据库管理系统保证的引用完整性从
Response
至PersonSurvey
;Response
至SurveyQuestion
;和Person
,Survey
和Question
。派生数据以避免更新异常
我注意到你的图中有两个值得一提的元素。这些元素与PersonSurvey
可以(应该)导出的两列相关。
在这方面,您可以PersonSurvey.IsStarted
通过查询给定的Person
事件是否提供了一个或多个Responses
以通过表Questions
集成一个精确的Survey
来导出数据SurveyQuestion
。
并且您还可以PersonSurvey.IsCompleted
通过确定给定Person
实例是否已将 a 提供Response
给所有在特定行Questions
的IsMandatory
列中包含'TRUE' 值的值来获取数据点SurveyQuestion
。
通过推导这些值,您可以防止某些更新异常,如果您将这些值保留在SurveyQuestion
列中,最终会出现这些异常。
正如@Dave在他的评论中正确指出的那样,如果您未来需要管理不同类型的响应,这意味着管理日期、数值、多项选择和其他可能的方面,您将不得不扩展此数据库布局。
归档时间: |
|
查看次数: |
2042 次 |
最近记录: |