SQL Server中的可延迟约束

时间:2009-06-15 20:03:20

标签: sql sql-server database oracle constraints

任何版本的SQL Server是否支持可延迟约束(DC)?

从版本8.0开始,Oracle has supported deferrable constraints - 仅在提交语句组时评估的约束,而不是在插入或更新单个表时。可延迟约束不仅仅是禁用/启用约束,因为约束仍处于活动状态 - 它们只是稍后进行评估(批量提交时)。

DC的好处是它们允许评估单独非法的更新,这些更新累积地导致有效的最终状态。一个示例是在两行之间的表中创建循环引用,其中每行需要存在一个值。没有单独的插入语句会通过约束 - 但组可以。

为了阐明我的目标,我希望将C#中的ORM实现移植到SQLServer - 遗憾的是,实现依赖于Oracle DC来避免在行之间计算插入/更新/删除命令。

7 个答案:

答案 0 :(得分:23)

OT:有一些恕我直言,SQL Server不支持,但在企业环境中有意义:

  • 此处提及的延迟约束
  • MARS:你为什么需要为完全自然的东西设置一个选项?
  • CASCADE DELETE约束:SQL Server仅允许给定CASCADE DELETE约束的单个级联路径。同样,我没有看到为什么不应该允许它通过多个可能的路径级联删除的原因:最后,当它真正执行时,实际上总是只有一条路径被使用,所以为什么这是限制吗?
  • 防止单个ADO.NET连接上的并行事务。
  • 强制执行在此事务中执行事务的连接上执行的每个命令。
  • 创建UNIQUE索引时,NULL被视为实际值,并且只允许在索引中出现一次。然而,SQL将NULL作为“未知值”的概念表明,在创建索引时,将忽略NULL值...

所有这些小东西都会使您在SQL Server中几乎无用的全尺寸RDBMS所具有的许多参照完整性和事务性功能。例如,由于不支持可延迟约束,因此“事务”作为外部一致工作单元的概念被部分否定,唯一可行的解​​决方案 - 除了一些肮脏的解决方法 - 根本就没有定义参照完整性约束。我希望,事务的自然行为是你可以按照你喜欢的操作方式和顺序在其中工作,系统将确保它在你提交它时是一致的。 限制产生了类似的问题,即ON DELETE CASCADE的参照完整性约束只能以只有一个约束可以导致对象的级联删除的方式定义。这真的不适合大多数现实场景。

答案 1 :(得分:11)

到目前为止,SQL Server不支持它们。你正在解决的问题是什么?

答案 2 :(得分:3)

显然不是。

我发现大约有五篇不同的博客帖子都说SQLServer(各种版本)不支持Deferrable Constraints。

另一方面,我还发现了一篇试图通过使用"persisted computed columns,"(滚动到最后一个条目)来模仿此功能的帖子,但是告诫者

答案 3 :(得分:3)

听起来你遇到的问题是SQL不支持Date和Darwen所谓的“多重赋值”。标准SQL对此的响应是“延迟约束”,SQL Server不支持。可以使用NOCHECK标记SQL Server FK或CHECK约束,但它不完全相同。有关详细信息,请参阅MSDN:ALTER TABLE (Transact-SQL)

答案 4 :(得分:2)

有一种方法可以在某些条件下解决丢失的延迟约束强制 (截至2017年1月,SQL Server中不支持延迟约束)。请考虑以下数据库模式:

免责声明:架构的质量或用例不适用于此处的争论,它是作为解决方法的基本示例

CREATE TABLE T (Id TYPE NOT NULL PRIMARY KEY, NextId TYPE NOT NULL);

ALTER TABLE T WITH CHECK ADD CONSTRAINT FK_T2T 
FOREIGN KEY (NextId) REFERENCES T (Id);

CREATE UNIQUE NONCLUSTERED INDEX UC_T ON T (NextId);

其中TYPE是代理键的某种合适的数据类型。假设代理键的值由INSERT操作期间的RDBMS分配(即IDENTITY)。

用例是保持"最新的"具有NextId = NULL的实体T的版本,并通过维护单链表T.NextId - >来存储先前版本。 T.Id。

显然,给定的模式受延迟约束问题的影响,因为插入了新的 - "最新的"版本必须在更新旧版本之前 - "最新版本"在此期间,数据库中将有两条具有相同NextId值的记录。

现在,如果:

主键的数据类型不必是数字,并且可以提前计算(即UNIQUEIDENTIFIER),然后使用MERGE语句回避延迟约束问题,如下所示:

DECLARE @MergeTable TABLE (Id UNIQUEIDENTIFIER);

DECLARE @NewLatestVersion UNIQUEIDENTIFIER = NEWID();

INSERT INTO @MergeTable (Id) VALUES (@NewLatestVersion);
INSERT INTO @MergeTable (Id) VALUES (@OldLatestVersion);

MERGE INTO T
USING @MergeTable m ON T.Id = m.Id
WHEN MATCHED THEN UPDATE SET T.NextId = @NewLatestVersion
WHEN NOT MATCHED THEN INSERT (Id) VALUES (@NewLatestVersion);

显然,MERGE语句在检查约束之前完成所有数据操作。

答案 5 :(得分:1)

如果您有自己的ORM层,问题的一个解决方案可能是通过ORM层的逻辑将对象更新与参考更新分开。 然后,您的ORM将根据您的客户端更改集在几个步骤中处理事务:

  1. 删除更改集定义为删除的所有外键引用,即将相应的外键列设置为NULL,或者对于使用映射表的关系,删除映射表中的条目(如果适用)。
  2. 删除更改集定义为“已删除”的所有对象
  3. 在更改集中创建所有新对象,但尚未设置外键列
  4. 更新更改集中任何更新对象的所有“原始”值更改,即不更新外键列
  5. 设置更改集中定义的外键列值。
  6. 添加映射表映射以映射基于表的关系
  7. 提交
  8. 这可以解决您的问题,因为所有引用的对象都可以在任何时候设置外键值...

答案 6 :(得分:0)

您可以使用此方法

<!-- language-all: lang-or-tag-here -->


    columns: [{
        field: "checkboxDisplay",
        title: "checkboxDisplay",

        template: "# if ('new' =='new') { # <input id = 'checkIDGrid' type='checkbox' checked=true class=''> # }else{# <span class='oldEventArrow'></span> #} #"


      }

你的行动

ALTER TABLE your_table NOCHECK CONSTRAINT your_constraint