为两个不同的实体创建单个表

时间:2017-11-08 18:05:27

标签: sql sql-server database

为以下场景构建数据库表的适当方法是什么?

我试图对事故报告进行建模,其中一部分将记录(作为事件的一部分)员工或客户是否必须接受医疗护理。两者都要记录相同的细节。在表单的纸质版本和界面中,它显示为单个表。表格标题为:

  • 人(员工或客户)
  • 损伤
  • 施行急救
  • 住院
  • 详细

我们已经有单独的员工和客户表格,这些表格会显示其个人详细信息。新表将包括身份证,有关该人是否受伤,接受急救,住院以及任何其他详细信息的详细信息。

所以我一直在思考如何构建这种结构的几种可能性:

  1. 两个单独的员工和客户事件表。这两个表将主要包含相同的字段,但EmployeeID或CustomerID的外键除外。
  2. 单个表,其中包含EmployeeID和CustomerID的所有与事件相关的字段和其他字段,其中这些字段分别是Employee和Customer表的主键的可空外键。确保EmployeeID XOR CustomerID不为空的约束。
  3. 创建3个新表:一个用于保存事件,一个用于将客户ID与事件相关联,另一个用于将员工ID与事件相关联 - 这是否过于规范化? (假设我将永远不会有超过客户或员工记录事件详情)
  4. 包含所有与事件相关的字段的单个表,其中包含一个字段,用于存储员工ID或客户ID以及类型字段,以指定其是员工还是客户。
  5. 我倾向于选项1,它似乎是最干净的,如果需要为客户和员工记录不同的字段,在不影响另一个表的情况下更新单个表很容易。我打折了选项4,我认为这是糟糕的设计,因为我无法在ID列中添加FK约束。

    我有什么理由不参加选项1,还是有更好的选择我还应该考虑?

3 个答案:

答案 0 :(得分:1)

我会创建“链接”表。并且不要重复事件的DDL。

然后您就可以创建一个视图,将客户和员工与事件数据结合在一起。

我同意之前的回答,将事件细节分开。

-- START TSQL

SET NOCOUNT ON


IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwIncidents' and TABLE_TYPE = N'VIEW' ) 
BEGIN 
DROP VIEW [dbo].[vwIncidents] 
END 
GO

IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'CustomerToIncidentLink' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[CustomerToIncidentLink] 
END 
GO


IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'EmployeeToIncidentLink' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[EmployeeToIncidentLink] 
END 
GO

IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Incident' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[Incident] 
END 
GO

IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[Employee] 
END 


IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Customer' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN DROP TABLE [dbo].[Customer] 
END 




CREATE TABLE [dbo].[Employee] ( 

    [EmployeeUUID] [uniqueidentifier] NOT NULL,
    [TheVersionProperty] [timestamp] NOT NULL,
    [SSN] [nvarchar](11) NOT NULL,
    [LastName] [varchar](64) NOT NULL,
    [FirstName] [varchar](64) NOT NULL,
    [CreateDate] [datetime] NOT NULL,
    [HireDate] [datetime] NOT NULL
    )

GO

ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeUUID) 
GO


ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_SSN_Unique UNIQUE (SSN) 
GO




CREATE TABLE [dbo].[Customer] ( 

    [CustomerUUID] [uniqueidentifier] NOT NULL,
    [TheVersionProperty] [timestamp] NOT NULL,
    [CustomerNumber] [nvarchar](11) NOT NULL,
    [LastName] [varchar](64) NOT NULL,
    [FirstName] [varchar](64) NOT NULL,
    [CreateDate] [datetime] NOT NULL
    )

GO

ALTER TABLE dbo.Customer ADD CONSTRAINT PK_Customer PRIMARY KEY NONCLUSTERED (CustomerUUID) 
GO


ALTER TABLE [dbo].[Customer] ADD CONSTRAINT CK_CustomerNumber_Unique UNIQUE (CustomerNumber) 
GO






IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[Incident]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) 
BEGIN DROP TABLE [dbo].[Incident] 
END 
GO

CREATE TABLE [dbo].[Incident] 
( 
  IncidentUUID [UNIQUEIDENTIFIER] NOT NULL DEFAULT NEWSEQUENTIALID() 
, IncidentName varchar(24) not null 
, CreateDate smalldatetime not null
)

GO

ALTER TABLE dbo.Incident ADD CONSTRAINT PK_Incident PRIMARY KEY NONCLUSTERED (IncidentUUID) 
GO

ALTER TABLE [dbo].[Incident] ADD CONSTRAINT CK_IncidentName_Unique UNIQUE (IncidentName) 
GO




IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[EmployeeToIncidentLink]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) 
BEGIN DROP TABLE [dbo].[EmployeeToIncidentLink] 
END 
GO

CREATE TABLE [dbo].[EmployeeToIncidentLink] ( 
    [LinkSurrogateUUID] [uniqueidentifier] NOT NULL,
    [TheEmployeeUUID] [uniqueidentifier] NOT NULL,
    [TheIncidentUUID] [uniqueidentifier] NOT NULL
)


GO

ALTER TABLE dbo.EmployeeToIncidentLink ADD CONSTRAINT PK_EmployeeToIncidentLink PRIMARY KEY NONCLUSTERED (LinkSurrogateUUID) 
GO

ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT FK_EmployeeToIncidentLinkToEmployee FOREIGN KEY (TheEmployeeUUID) REFERENCES dbo.Employee (EmployeeUUID) 
GO

ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT FK_EmployeeToIncidentLinkToIncident FOREIGN KEY (TheIncidentUUID) REFERENCES dbo.Incident (IncidentUUID) 
GO


ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT CONST_UNIQUE_EmpUUID_InciUUID UNIQUE (TheEmployeeUUID , TheIncidentUUID) 
GO




IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[CustomerToIncidentLink]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) 
BEGIN DROP TABLE [dbo].[CustomerToIncidentLink] 
END 
GO

CREATE TABLE [dbo].[CustomerToIncidentLink] ( 
    [LinkSurrogateUUID] [uniqueidentifier] NOT NULL,
    [TheCustomerUUID] [uniqueidentifier] NOT NULL,
    [TheIncidentUUID] [uniqueidentifier] NOT NULL
)


GO

ALTER TABLE dbo.CustomerToIncidentLink ADD CONSTRAINT PK_CustomerToIncidentLink PRIMARY KEY NONCLUSTERED (LinkSurrogateUUID) 
GO

ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT FK_CustomerToIncidentLinkToCustomer FOREIGN KEY (TheCustomerUUID) REFERENCES dbo.Customer (CustomerUUID) 
GO

ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT FK_CustomerToIncidentLinkToIncident FOREIGN KEY (TheIncidentUUID) REFERENCES dbo.Incident (IncidentUUID) 
GO

ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT CONST_UNIQUE_CustomerUUID_InciUUID UNIQUE (TheCustomerUUID , TheIncidentUUID) 
GO



CREATE VIEW dbo.vwIncidents  
AS  
/* combine what is in common with employees and customers for this view */
select e.LastName, e.FirstName, inc.IncidentName
from dbo.Employee e
join
dbo.EmployeeToIncidentLink link on e.EmployeeUUID = link.TheEmployeeUUID
join
dbo.Incident inc on inc.IncidentUUID = link.TheIncidentUUID
UNION ALL
select c.LastName, c.FirstName, inc.IncidentName
from dbo.Customer c
join
dbo.CustomerToIncidentLink link on c.CustomerUUID = link.TheCustomerUUID
join
dbo.Incident inc on inc.IncidentUUID = link.TheIncidentUUID



GO  

还有另一种选择(我认为?)

创建一个Person表,(这与客户和员工有共同的信息),然后为客户和员工创建对该实体数据唯一的“子类”表。

这本身就是一个话题。

How do we implement an IS-A Relationship?

“是一个” 或“如何在数据库中进行子类化”将是搜索提示。

我有一个接近你的例子,它做了一个“子类化”

-- START TSQL

SET NOCOUNT ON

IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwPersonEmail' and TABLE_TYPE = N'VIEW' ) 
BEGIN 
DROP VIEW [dbo].[vwPersonEmail] 
END 
GO



IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'PersonEmail' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[PersonEmail] 
END 
GO


IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Customer' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[Customer] 
END 
GO

IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[Employee] 
END 
GO

IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'PersonSuperType' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[PersonSuperType] 
END 
GO


IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Department' and TABLE_TYPE = N'BASE TABLE' ) 
BEGIN 
DROP TABLE [dbo].[Department] 
END 
GO



CREATE TABLE [dbo].[Department](
    [DepartmentUUID] [uniqueidentifier] NOT NULL,
    [TheVersionProperty] [timestamp] NOT NULL,
    [DepartmentName] [nvarchar](80) NULL,
    [CreateDate] [datetime] NOT NULL,
    [MyTinyInt] tinyint not null
    )


ALTER TABLE dbo.[Department] ADD CONSTRAINT PK_Department PRIMARY KEY NONCLUSTERED ([DepartmentUUID]) 
GO

ALTER TABLE [dbo].[Department] ADD CONSTRAINT CK_DepartmentName_Unique UNIQUE ([DepartmentName]) 
GO




CREATE TABLE [dbo].[PersonSuperType] (
    [PersonSuperTypeUUID] [uniqueidentifier] not null default NEWSEQUENTIALID(),
    [LastName] [varchar](64) NOT NULL,
    [FirstName] [varchar](64) NOT NULL  
)

GO

ALTER TABLE dbo.PersonSuperType ADD CONSTRAINT PK_PersonSuperTypeUUID PRIMARY KEY CLUSTERED (PersonSuperTypeUUID)
GO


CREATE TABLE [dbo].[Employee] ( 

    [EmployeeUUID] [uniqueidentifier] NOT NULL,
    [ParentDepartmentUUID] [uniqueidentifier] NOT NULL,
    [TheVersionProperty] [timestamp] NOT NULL,
    [SSN] [nvarchar](11) NOT NULL,
    [CreateDate] [datetime] NOT NULL,
    [HireDate] [datetime] NOT NULL
    )

GO

ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeUUID) 
GO


ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_SSN_Unique UNIQUE (SSN) 
GO

ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToDepartment FOREIGN KEY (ParentDepartmentUUID) REFERENCES dbo.Department (DepartmentUUID) 
GO

ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToPersonSuperType FOREIGN KEY (EmployeeUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID) 
GO



CREATE TABLE [dbo].[Customer] ( 

    [CustomerUUID] [uniqueidentifier] NOT NULL,
    [TheVersionProperty] [timestamp] NOT NULL,
    [CustomerNumber] [nvarchar](11) NOT NULL,
    [CreateDate] [datetime] NOT NULL,
    )

GO

ALTER TABLE [dbo].[Customer] ADD CONSTRAINT PK_Customer PRIMARY KEY NONCLUSTERED (CustomerUUID) 
GO

ALTER TABLE [dbo].[Customer] ADD CONSTRAINT CK_Customer_CustomerNumber_Unique UNIQUE (CustomerNumber) 
GO

ALTER TABLE [dbo].[Customer] ADD CONSTRAINT FK_CustomerToPersonSuperType FOREIGN KEY (CustomerUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID) 
GO




CREATE TABLE [dbo].[PersonEmail] ( 

    [PersonEmailUUID] [uniqueidentifier] NOT NULL,
    [PersonSuperTypeUUID] [uniqueidentifier] NOT NULL,
    [EmailAddress] [varchar](256) NOT NULL
    )

GO

ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT PK_PersonEmail PRIMARY KEY NONCLUSTERED (PersonEmailUUID) 
GO

ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT CK_PersonEmail_EmailAddress_Unique UNIQUE (EmailAddress) 
GO

ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT FK_PersonEmailToPersonSuperType FOREIGN KEY (PersonSuperTypeUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID) 
GO


CREATE VIEW dbo.vwPersonEmail  
AS  
/* combine what is in common with employees and customers for this view */
select per.LastName, per.FirstName, [UniqueIdentifier] = emp.SSN, pemail.EmailAddress
from dbo.PersonSuperType per
join
dbo.Employee emp on per.PersonSuperTypeUUID = emp.EmployeeUUID
join
dbo.PersonEmail pemail on per.PersonSuperTypeUUID = pemail.PersonSuperTypeUUID
UNION ALL
select per.LastName, per.FirstName, [UniqueIdentifier] = cust.CustomerNumber, pemail.EmailAddress
from dbo.PersonSuperType per
join
dbo.Customer cust on per.PersonSuperTypeUUID = cust.CustomerUUID
join
dbo.PersonEmail pemail on per.PersonSuperTypeUUID = pemail.PersonSuperTypeUUID



GO  

所以现在我考虑一下,我可能会倾向于“子类化”方式。因为你们两种类型的人可能有很多共同的属性,还有一些不同的属性。

答案 1 :(得分:0)

如果您只想在一个中显示有关2个不同表的信息,则可以使用View。在这里你有一个例子来检查它。

https://www.w3schools.com/sql/sql_view.asp =>教程

https://www.ibm.com/support/knowledgecenter/en/ssw_i5_54/rzatc/rzatcviewmultsql.htm =>示例

答案 2 :(得分:0)

我将事件和细节之间的区别正式化。

INCIDENT_HEADER
   Customer ID <nullable, fk into the customer table>
   Employee ID <nullable, fk into the employee table, which already exsits>
   Summary
   Date
   Status (?)

INCIDENT_DETAIL
   DETAIL_TYPE_ID <fk into a type table, it's up next...>
   DESCRIPTION

DETAIL_TYPE
   ID
   DESCRIPTION

DETAIL_TYPE将最终出现“伤害”,“住院”和“急救”等内容。您可以稍后向该表添加更多内容,而无需触及详细信息表。

此设计允许您在不更改标题表的情况下添加更多种类的详细信息。