2

当我CHECK CONSTRAINT在表上定义 a 时,我发现存储的条件子句可能与我输入的不同。
例子:

Alter table T1 add constraint C1 CHECK (field1 in (1,2,3))

查看存储的内容:

select cc.Definition from sys.check_constraints cc
inner join sys.objects o on o.object_id = cc.parent_object_id
where cc.type = 'C' and cc.name = 'T1';

我懂了:

([field1]=(3) OR [field1]=(2) OR [field1]=(1))

虽然这些是等价的,但它们不是相同的文本。(使用BETWEEN子句时会发生类似的行为)。

我希望这不会发生的原因是,我试图CHECK通过将用于定义约束的文本与存储的文本进行比较,以编程方式确保我的所有约束都是正确的sys.check_constraints——如果不同,则删除并重新创建约束。

但是,在这些情况下,它们总是不同的,因此程序总是认为它需要重新创建约束。

问题是:

  1. SQL Server 进行这种翻译有什么已知的原因吗?它只是删除了一些语法糖并以更简单的形式存储子句吗?
  2. 有没有办法避免这种行为(除了以长格式编写我的约束子句以匹配 SQL Server 将其更改为的内容)?
  3. 有没有另一种方法来判断我的检查约束是否“过时”并且需要重新创建?
4

1 回答 1

2

SQL Server 进行这种翻译有什么已知的原因吗?它只是删除了一些语法糖并以更简单的形式存储子句吗?

我不知道联机丛书中或其他地方记录的任何原因。但是,我的猜测是它已针对 SQL Server 内部的某些目的进行了规范化。它可能允许 SQL Server 在定义表达式时稍微宽松一些(例如Database用于列名),但保证对于需要解析表达式的任何引擎(即[Database]),列名总是被适当地转义。

有没有办法避免这种行为(除了以长格式编写我的约束子句以匹配 SQL Server 将其更改为的内容)?

可能不是。但是,如果您的约束不是非常复杂,那么以长格式重写约束子句是个坏主意吗?

有没有另一种方法来判断我的检查约束是否“过时”并且需要重新创建?

在我直接回答这个问题之前,我要指出这里涉及到一些编程哲学。SQL Server 为 CHECK 约束的文本提供的 API 仅保证您将获得与原始表达式等效的内容。虽然您当然可以构建一些奇特的方法来尝试确保始终能够重现 SQL Server 的规范化版本的表达式,但不能保证 Microsoft 将来不会更改其规范化规则。事实上,可能无法保证两个等价的表达式总是相同地标准化!

因此,我首先建议您重新检查您的架构,看看您是否可以在不必依赖未记录的 API 行为的情况下完成相同的结果。

Having said that, there are a number of methods outlined in this question (and answer).

Another alternative, which is a bit more brute-force but perhaps acceptable, would be to always assume that the expression is "out of date" and simply drop/re-create the constraint every time you check. Unless you're expecting these constraints to frequently become out-of-date (or the tables are quite large), it seems this would be a decent solution. You could probably even run it in a transaction, so that if the new constraint is already violated, simply roll-back the transaction and report the error.

于 2013-03-16T02:14:15.507 回答