SQL Server约束不会保存我定义它的方式

时间:2015-02-25 17:52:28

标签: sql-server tsql sql-server-2012

我之前注意到SQL Server(或Management Studio)会调整"通过GUI创建时检查约束。大多数时候它工作正常。但是这种特殊的约束每次都会改变。我甚至尝试在脚本中执行此操作但每次都会恢复为不正确的。为什么呢?

这就是我的目的:

ALTER TABLE [dbo].[DSPTripAssignment] WITH CHECK 
  ADD CONSTRAINT [CK_DSPTripAssignment_CarrierKey_DriverKey] 
  CHECK (([CarrierKey] IS NULL AND NOT [DriverKey] IS NULL) 
         OR ([DriverKey] IS NULL AND NOT [CarrierKey] IS NULL))
GO

这是它恢复的原因(见OR周围缺少大括号 - 杀死逻辑)

ALTER TABLE [dbo].[DSPTripAssignment] WITH CHECK 
  ADD CONSTRAINT [CK_DSPTripAssignment_CarrierKey_DriverKey] 
  CHECK (([CarrierKey] IS NULL AND NOT [DriverKey] IS NULL 
         OR [DriverKey] IS NULL AND NOT [CarrierKey] IS NULL))
GO

或者,也许您可​​以建议如何更好地编写此检查?我想确保指定其中一个键,但不是两个。

1 个答案:

答案 0 :(得分:2)

事实上,它并没有破坏逻辑。在T-SQL中,precedence转到NOT> AND> OR,所以

A AND NOT B OR C AND NOT D

相同
(A AND (NOT B)) OR (C AND (NOT D))

遗漏了多余的括号。检查定义会被重写为可能不太可读的规范形式,但这不会导致错误检查。

您的实际支票定义很好 - 虽然您可以使用ISNULL / COALESCE / CASE进行重写,但这可能会降低检查效率。但是,您可以将NOT X IS NULL重写为X IS NOT NULL,我认为这更具可读性:

([CarrierKey] IS NULL AND [DriverKey] IS NOT NULL) OR ([DriverKey] IS NULL AND [CarrierKey] IS NOT NULL)

如果您不喜欢SQL Server将重写约束的事实,您可以使用不会被重写的表单:

([CarrierKey] IS NULL OR [DriverKey] IS NULL) AND ([DriverKey] IS NOT NULL OR [CarrierKey] IS NOT NULL)

这可以分为两个约束,但由于这些约束本身没有多大意义,我会将它们保持在一起。