【问题标题】:SQL Relationship to Secondary Table Without Adding Duplicate Column不添加重复列与辅助表的 SQL 关系
【发布时间】:2018-09-06 13:41:41
【问题描述】:

有城市、工作类型和任务。城市可以有多种工作类型。为可以具有多种工作类型的城市创建任务。城市可以有许多任务。但是在为分配给城市的任务添加工作类型时,必须确保城市具有该工作类型。

如何在添加/更新 Task_JobTypes 时创建关系/约束以确保与任务关联的城市在 City_JobTypes 中允许该职位类型? Task_JobTypes "FK_Task_JobTypes_JobTypes" 中的约束需要引用它而不仅仅是 JobTypes。

城市 - ID、名称

工作类型 - ID、姓名

CityJobTypes - CityId,JobTypeId(每个城市允许的工作类型)

任务 - Id,CityId,Name(城市任务)

TaskJobTypes - TaskId,JobTypeId(每个任务的JobTypes)

表格 -

CREATE TABLE [dbo].[Cities](
    [Id] [int] IDENTITY(1,1) NOT NULL,  
    [Name] [varchar](500) NOT NULL, 
CONSTRAINT [PK_Cities] PRIMARY KEY CLUSTERED ([Id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO    

CREATE TABLE [dbo].[JobTypes](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NOT NULL
 CONSTRAINT [PK_JobTypes] PRIMARY KEY CLUSTERED ([Id] ASC)
 WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO    

CREATE TABLE [dbo].[City_JobTypes](
    [JobTypeId] [int] NOT NULL,
    [CityId] [int] NOT NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[City_JobTypes]  WITH CHECK ADD  CONSTRAINT [FK_City_JobTypes_Cities] FOREIGN KEY([CityId])
REFERENCES [dbo].[Cities] ([Id])
GO    

ALTER TABLE [dbo].[City_JobTypes]  WITH CHECK ADD  CONSTRAINT [FK_City_JobTypes_JobTypes] FOREIGN KEY([JobTypeId])
REFERENCES [dbo].[JobTypes] ([Id])
GO 

CREATE TABLE [dbo].[Tasks](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [CityId] [int] NOT NULL,
    [Name] [varchar](50) NOT NULL,
 CONSTRAINT [PK_Tasks] PRIMARY KEY CLUSTERED ([Id] ASC)
 WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Tasks]  WITH CHECK ADD  CONSTRAINT [FK_Tasks_Cities] FOREIGN KEY([CityId])
REFERENCES [dbo].[Cities] ([Id])
GO

CREATE TABLE [dbo].[Task_JobTypes](
    [TaskId] [int] NOT NULL,
    [JobTypeId] [int] NOT NULL,
 CONSTRAINT [IX_Task_JobTypes-TaskId,JobTypeId] UNIQUE NONCLUSTERED 
(
    [TaskId] ASC,
    [JobTypeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Task_JobTypes]  WITH CHECK ADD  CONSTRAINT [FK_Task_JobTypes_JobTypes] FOREIGN KEY([JobTypeId])
REFERENCES [dbo].[JobTypes] ([Id])
GO

ALTER TABLE [dbo].[Task_JobTypes]  WITH CHECK ADD  CONSTRAINT [FK_Task_JobTypes_Tasks] FOREIGN KEY([TaskId])
REFERENCES [dbo].[Tasks] ([Id])
GO

【问题讨论】:

  • 为什么“不添加重复列”?没有这些信息,就无法完成。您应该将JobType 添加到与城市关联的任务列表中。然后,您可以使用复合键将其限制在您需要的所有表中。
  • 只是向 TaskJobTypes 添加另一列 (CityId) 来引用任务已经引用的城市,这似乎是多余的。其他一切都已经有关系,这是唯一的方法吗?这只是数据库中许多具有此类设置的表的一个示例,并且添加额外的列似乎只是多余的,但如果它是唯一的选择(或最简单/最干净),这就是我想要看到的
  • 有时,如果我要向表中添加另一列以强制执行此类约束(如此处的CityId),我会将表命名为_TaskJobTypes,而将列命名为_CityId,然后创建一个名为TaskJobTypes 的视图来隐藏该列(加上在INSERT/UPDATE 期间填充该列的触发器)。 知道你的数据库有额外的列,你数据库的用户不需要(因为他们仍然只是INSERT/UPDATE/DELETE针对该视图而不是表格)

标签: sql sql-server foreign-keys constraints relationship


【解决方案1】:

添加/更新时如何创建关系/约束 Task_JobTypes 以确保与任务关联的城市具有 City_JobTypes 中允许的工作类型?

您可以使用调用函数的CHECK CONSTRAINT 来执行此操作。该函数将TaskIDJobTypeID 作为参数并查询连接到City_JobTypes 表的Tasks 表以查看City 是否具有JobType。如果城市有工作类型,则该函数将返回 True (1),否则返回 false (0)

或者,您也可以使用 TRIGGER 执行此操作,但我个人更喜欢 CHECK CONSTRAINTS。

【讨论】:

  • 通过这样的检查约束执行此操作的问题在于,它不会阻止某人从City_JobTypes删除被@ 中的一行“引用”的行987654331@
  • @Damien_The_Unbeliever 是的,如果可以从该表中删除行,则必须由触发器处理参照完整性。
【解决方案2】:

在我看来,您在哲学上反对composite keys。链接表City_JobTypes 有一个复合主键CityId, JobTypeId。任何其他限制 City_JobTypes 的表都需要限制其主键。那恰好是两列,但它仍然是一个键。我没有看到那里的问题。


我对你的结构的看法是……

一个Task 属于一个City 并且有一个JobType

作为一个 Job 必须有 一个 City一个 JobType,让Task 的这些属性?

City
 ↑
Task → JobType


City 也有 0..many JobTypes 是“允许的”。

City ← City_JobTypes
 ↑          ↓
Task → JobType


此时您的Task 表已经有一个CityID 和一个JobTypeID

为什么不对City_JobTypes 表约束该复合键?

City ← City_JobTypes
 ↑   ↗      ↓
Task → JobType


如果单个 Task 实际上可以有 0..many JobTypes...

我会从这里开始,我看不到任何方式来限制基于 City_JobType 链接的 Tasks...

City ← City_JobTypes↘
 ↑                   JobType
Task ← Task_JobTypes↗

然后我决定Task 可以合理地识别为具有复合主键的CityTask。这将允许以下操作。

   City  ←    City_JobTypes ↘
   ↑          ↑     ↑        JobType
CityTask ← CityTask_JobTypes↗

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多