更改表添加约束与更改表添加检查约束

时间:2016-06-10 11:06:18

标签: sql-server

我在SSMS中遇到了一个奇怪的问题。

我的表格设计大量使用复合键来强制执行所有传递关系中严格而强大的引用完整性 - 代价是违反BCNF,但在实践中它证明非常方便,特别是对于Entity Framework&#39 ; s自动导航属性(与我之前发布的这个问题相关:How can I enforce second-degree relationships without composite keys?)。

无论如何,我在使用SSMS 2014的图表编辑器添加外键关系方面遇到了问题。

以下是我的问题的简化示例:

System.currentTimeMillis() // Store this as start time in SharedPrefs

我有很多像这样的列的表,并使用图编辑器创建复合键的参照完整性关系工作正常(您只需按住Ctrl键并单击每个复合FK列,然后拖到主键表,然后单击“确定”,即可。

然而有时,它失败了。例如,如果我在CREATE TABLE Tenants ( TenantId bigint IDENTITY(1,1) PRIMARY KEY ) CREATE TABLE Shops ( TenantId bigint, -- Is a FOREIGN KEY( Tenants REFERENCES TenantId ) ShopId bigint IDENTITY(1,1) PRIMARY KEY( TenantId, ShopId ) ) CREATE TABLE Job ( TenantId bigint, -- Is a FOREIGN KEY( Tenants REFERENCES TenantId ) ShopId bigint, -- Is a FOREIGN KEY( Shops REFERENCES TenantId ) JobId bigint IDENTITY(1,1) PRIMARY KEY( TenantId, ShopId, JobId ) ) 中选择TenantIdShopId并将其拖到Jobs表格,则会出现此错误:

  

表格中的列'商店'不匹配现有的主键或UNIQUE约束。

...即使这两列 Shops表的主键!

我让SSMS为它试图添加的约束生成SQL,它给了我这个(格式化我的,删除了额外的Shops代码):

TRANSACTION

当我直接运行时,SQL Server给了我这个错误:

  

Msg 1776,Level 16,State 0,Line 1   引用表中没有主键或候选键' ALTER TABLE dbo.Jobs ADD CONSTRAINT FK_Jobs_Shops FOREIGN KEY ( ShopId, TenantId ) REFERENCES dbo.Shops ( ShopId, TenantId ) ON UPDATE NO ACTION ON DELETE NO ACTION '与外键' dbo.Shops'中的引用列列表匹配。

     

Msg 1750,Level 16,State 0,Line 1   无法创建约束或索引。查看以前的错误。

请注意,其他表已经与FK_Jobs_Shops定义了外键关系 - 所以我想知道发生了什么。所以我告诉SSMS 脚本来创建看似有效的约束 - 然后我重命名了一些东西以使它创建我原本想要的约束(在ShopsJobs之间),然后它给了我不同的输出(格式化我的):

Shops

当我跑步时,它有效!

请注意差异:

  • 添加ALTER TABLE [dbo].Jobs WITH CHECK ADD CONSTRAINT [FK_Jobs_Shops] FOREIGN KEY ([TenantId], [ShopId]) REFERENCES [dbo].[Shops] ([TenantId], [ShopId]) GO ALTER TABLE [dbo].[Jobs] CHECK CONSTRAINT [FK_Jobs_Shops] GO
  • 缺少WITH CHECK / ON UPDATE陈述
  • 约束是在两个陈述中实现的,而不是一个。

我的问题:

  • 我在SQL Server中发现了一个错误吗?
  • 两个约束定义语法之间是否存在语义差异?
  • 或者更确切地说,为什么一个有效但另一个无效?

1 个答案:

答案 0 :(得分:2)

两个脚本之间唯一重要的区别是外键字段/引用主键字段的顺序。

失败的脚本使用的(ShopId, TenantId)不是主键定义的顺序:

PRIMARY KEY(TenantId, ShopId) 

无法找到官方参考,但seems您必须按照与PK定义相同的顺序指定FK字段。