9

我有两张表,销售和产品。Sale 有一个引用 Product 的外键约束。外键已创建WITH NOCHECK并在创建后立即禁用。我想启用并信任外键约束。启用它可以工作,但我无法信任它。

StackOverflow 和各种博客上的类似问题表明运行ALTER TABLE T WITH CHECK CHECK CONSTRAINT C应该导致is_disabled=0and is_not_trusted=0,但is_not_trusted对我来说始终是 1。我究竟做错了什么?

我试图将示例代码放在 SQL Fiddle 上,但它不喜欢“DBCC”命令,所以这里是:

-- "_Scratch" is just a sandbox DB that I use for testing stuff.
USE _Scratch

CREATE TABLE dbo.Product
(
  ProductKeyId INT PRIMARY KEY NOT NULL,
  Description VARCHAR(40) NOT NULL
)

CREATE TABLE dbo.Sale
(
  ProductKeyId INT NOT NULL,
  SaleTime DATETIME NOT NULL,
  Value MONEY NOT NULL
)

ALTER TABLE dbo.Sale WITH NOCHECK
  ADD CONSTRAINT FK_Product_ProductKeyId FOREIGN KEY (ProductKeyId)
  REFERENCES dbo.Product (ProductKeyId) NOT FOR REPLICATION;

ALTER TABLE dbo.Sale NOCHECK CONSTRAINT FK_Product_ProductKeyId

INSERT INTO dbo.Product VALUES (1, 'Food')
INSERT INTO dbo.Sale VALUES (1, GETDATE(), 1.00)

-- Check the disabled/trusted state
SELECT name, is_disabled, is_not_trusted
FROM sys.foreign_keys
WHERE name = 'FK_Product_ProductKeyId'

  -- name                     is_disabled  is_not_trusted
  -- FK_Product_ProductKeyId  1            1

-- Check the FK_Product_ProductKeyId constraint
DBCC CHECKCONSTRAINTS('FK_Product_ProductKeyId')

  -- DBCC execution completed.
  -- If DBCC printed error messages, contact your system administrator.

-- Check all constraints on Sale table
DBCC CHECKCONSTRAINTS('Sale')

  -- DBCC execution completed.
  -- If DBCC printed error messages, contact your system administrator.

-- Add the constraint and check existing data
ALTER TABLE Sale WITH CHECK CHECK CONSTRAINT FK_Product_ProductKeyId

-- Check the disabled/trusted state
SELECT name, is_disabled, is_not_trusted
FROM sys.foreign_keys
WHERE name = 'FK_Product_ProductKeyId'

  -- name                     is_disabled  is_not_trusted
  -- FK_Product_ProductKeyId  0            1

-- Check the FK_Product_ProductKeyId constraint
DBCC CHECKCONSTRAINTS('FK_Product_ProductKeyId')

  -- DBCC execution completed.
  -- If DBCC printed error messages, contact your system administrator.

-- Check all constraints on Sale table
DBCC CHECKCONSTRAINTS('Sale')

  -- DBCC execution completed.
  -- If DBCC printed error messages, contact your system administrator.
4

1 回答 1

18

根据您的示例,我也尝试过:

  • 删除并重新创建外键。
  • 删除并重新创建表。

然后我注意到命令中有一些东西:

NOT FOR REPLICATION

似乎如果使用 NOT FOR REPLICATION 创建约束,它总是不受信任的。

引用在线书籍

在某些情况下,希望将复制拓扑中的用户活动与代理活动区别对待。例如,如果用户在发布服务器插入一行,并且该插入满足对表的检查约束,则当复制代理在订阅服务器插入该行时,可能不需要强制执行相同的约束。NOT FOR REPLICATION 选项允许您指定在复制代理执行操作时以不同方式处理以下数据库对象:

外键约束

当复制代理执行插入、更新或删除操作时,不强制执行外键约束。

看起来该IS_NOT_TRUSTED设置仅与IS_NOT_FOR_REPLICATION. 我想只要在您正在处理的服务器上强制执行约束,就应该没问题。所以我继续确认:

SELECT name, is_disabled, is_not_trusted
FROM sys.foreign_keys
WHERE name = 'FK_Product_ProductKeyId'

name                    is_disabled is_not_trusted
FK_Product_ProductKeyId 0            1

INSERT INTO dbo.Sale VALUES (2, GETDATE(), 1.00)

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Product_ProductKeyId". The conflict occurred in database "_Scratch", table "dbo.Product", column 'ProductKeyId'.
The statement has been terminated.

如果您仍然想IS_NOT_TRUSTED = 0安心查看,只需重新创建没有NOT FOR REPLICATION.

如果你们想知道,我也验证了对 CHECK 约束的相同效果。

于 2013-05-01T06:26:20.990 回答