SQL 服务器约束不会保存我定义它的方式

SQL Server constraint won't save the way I define it

我之前注意到 SQL 服务器(或 Management Studio)会在我通过 GUI 创建约束时 "adjust" 检查约束。大多数时候它工作正常且正确。但是这个特定的约束每次都会改变。我什至尝试用脚本来做,但每次都会恢复到不正确的状态。为什么?

这就是我运行:

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

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

事实上,它并没有扼杀逻辑。在 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 服务器将重写约束这一事实,您可以使用不会被重写的形式:

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

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