根据我对您的规范的理解,您的业务环境涉及概念级别的三元关系。在这方面,您需要定义:
- 实体类型人员和调查之间的关系(或关联)类型;
- 调查与问题之间的关系类型;
- 建立上述两种关系类型之间的关系的关系类型,并因此在Person,Survey和Question之间建立关系,即Response(从我的角度来看,这是简化解释的简称)。
因此,我认为您的方法1处在正确的轨道上,尽管它需要一些小(但很重要)的改进才能使其更加准确。我将在以下各节中详细介绍这种改进和其他相关注意事项。
商业规则
让我们稍微扩展适用的业务规则,并通过以下方式重新制定它们:
- 一个人在零一个或多个调查中注册
- 一个调查获得的零一或一对多的注册人
- 一个调查是由一个一对多的集成问题
- 一问集成了零一或一对多调查
- 一个问题收到零个或多个答复
- 甲响应由恰好酮提供人在恰好酮的背景调查
信息库IDEF1X图表
然后,我已经创建了IDEF1X 一个是在呈现图图1,其合成上述配制的业务规则:
一个 用于信息建模集成定义( 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
行到
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引用的一部分,因此该列非常有用。
使用这种方法,可以确保数据库管理系统从以下方面保证引用完整性:
- (a)
Response
到PersonSurvey
;
- (b)
Response
到SurveyQuestion
;和
- (c)中每一个代表一个关联实体类型静置独立的实体类型,即表中的表
Person
,Survey
和Question
。
派生数据以避免更新异常
我已经在您的图中注意到了我值得一提的两个要素。这些元素与PersonSurvey
可以(应该)派生的两列有关。
在这方面,你可以得出PersonSurvey.IsStarted
一个给定的通过查询基准Person
的发生提供了一个或多个Responses
以Questions
该确切的整合Survey
通过SurveyQuestion
表。
而且,您还可以PersonSurvey.IsCompleted
通过确定给定Person
实例是否在特定行的列中Response
向所有提供Questions
共同值为'TRUE'的实例提供a 来获取数据点。IsMandatory
SurveyQuestion
通过推导这些值,可以防止某些更新异常,如果将这些值保留在该SurveyQuestion
列中,这些更新异常最终会出现。
重要考虑
正如@Dave在他的评论中正确指出的那样,如果您面对将来的需求,要求管理各种不同的响应,这些响应暗示着管理日期,数值,多项选择以及其他可能的方面,那么您将必须扩展此数据库布局。
ID
和Number
,但在其他方面,这是梦幻般的。谢谢。