Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
532 views
in Technique[技术] by (71.8m points)

sql server 2008 - How to make foreign key constraints trusted?

I have two tables, Sale and Product. Sale has a foreign key constraint referencing Product. The foreign key was created WITH NOCHECK and immediately disabled after creation. I want to enable and trust the foreign key constraint. Enabling it works but I can't get it to be trusted.

Similar questions on StackOverflow and various blogs indicate that running ALTER TABLE T WITH CHECK CHECK CONSTRAINT C should result in is_disabled=0 and is_not_trusted=0, but is_not_trusted is always 1 for me. What am I doing wrong?

I tried to put sample code on SQL Fiddle but it didn't like the "DBCC" commands, so here it is:

-- "_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.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Based on your examples, I have also tried:

  • Drop and recreate the foreign key.
  • Drop and recreate the table.

Then I noticed something in the command:

NOT FOR REPLICATION

It seems if a constraint is created with NOT FOR REPLICATION, it is always not trusted.

Quoting from Books Online:

In some cases, it is desirable for user activity in a replication topology to be treated differently from agent activity. For example, if a row is inserted by a user at the Publisher and that insert satisfies a check constraint on the table, it might not be required to enforce the same constraint when the row is inserted by a replication agent at the Subscriber. The NOT FOR REPLICATION option allows you to specify that the following database objects are treated differently when a replication agent performs an operation:

Foreign key constraints

The foreign key constraint is not enforced when a replication agent performs an insert, update, or delete operation.

It looks like the IS_NOT_TRUSTED setting is only relevant for replication influenced by IS_NOT_FOR_REPLICATION. I guess as long as the constraint is enforced on the server you are working on, it should be fine. So I went ahead and confirmed it:

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.

If you still want to see IS_NOT_TRUSTED = 0 for peace of mind, just recreate the foreign key without NOT FOR REPLICATION.

In case if those of you are wondering, I have verified the same effect on CHECK constraints as well.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...