[ACCEPTED]-How to list out all Foreign Keys with "WITH NOCHECK" in SQL Server-system

Accepted answer
Score: 44

The following will return the name of the 11 foreign keys in the current database that 10 are disabled i.e. WITH NOCHECK

For SQL Server 9 2005/2008:

select * from sys.foreign_keys where is_disabled=1




There was some discussion in the answer about the difference between disabled & not trusted. What's below explains the differnce Here's some code to clarify the difference between is_disabled & isnotrusted.
-- drop table t1
-- drop table t2
create table t1(i int not null, fk int not null)
create table t2(i int not null)
-- create primary key on t2
alter table t2
add constraint pk_1 primary key (i)
-- create foriegn key on t1
alter table t1
add constraint fk_1 foreign key (fk)
    references t2 (i)
--insert some records
insert t2 values(100)
insert t2 values(200)
insert t2 values(300)
insert t2 values(400)
insert t2 values(500)
insert t1 values(1,100)
insert t1 values(2,100)
insert t1 values(3,500)
insert t1 values(4,500)
----------------------------
-- 1. enabled and trusted
select name,is_disabled,is_not_trusted from sys.foreign_keys
GO

-- 2. disable the constraint
alter table t1 NOCHECK CONSTRAINT fk_1
select name,is_disabled,is_not_trusted from sys.foreign_keys
GO

-- 3. re-enable constraint, data isnt checked, so not trusted.
-- this means the optimizer will still have to check the column
alter table  t1 CHECK CONSTRAINT fk_1 
select name,is_disabled,is_not_trusted from sys.foreign_keys
GO

--4. drop the foreign key constraint & re-add 
-- it making sure its checked
-- constraint is then enabled and trusted
alter table t1  DROP CONSTRAINT fk_1
alter table t1 WITH CHECK 
add constraint fk_1 foreign key (fk)
    references t2 (i)
select name,is_disabled,is_not_trusted from sys.foreign_keys
GO


--5. drop the foreign key constraint & add but dont check
-- constraint is then enabled, but not trusted
alter table t1  DROP CONSTRAINT fk_1
alter table t1 WITH NOCHECK 
add constraint fk_1 foreign key (fk)
    references t2 (i)
select name,is_disabled,is_not_trusted from sys.foreign_keys
GO

is_disabled means the constraint is disabled

isnottrusted 8 means that SQL Server does not trust that 7 the column has been checked against the 6 foreign key table.

Thus it cannot be assumed 5 that re-enabling the foreign key constraint 4 will be optimized. To ensure the optimizer 3 trusts the column, it's best to drop the 2 foreign key constraint & re-create it 1 with the WITH CHECK option (4.)

Score: 12
SELECT * FROM sys.foreign_keys AS f Where Is_Not_Trusted = 1

0

Score: 12

The following script will generate the alter 7 statements that will both check existing 6 data and prevent any new violations for 5 foreign keys that are not currently trusted 4 ('with nocheck').

Execute it in SQL Server 3 Management Studio to generate the scripts 2 and then copy them into a query window to 1 execute them.

select
    'alter table ' + quotename(s.name) + '.' + quotename(t.name) + ' with check check constraint ' + fk.name +';'
from 
    sys.foreign_keys fk
inner join
    sys.tables t
on
    fk.parent_object_id = t.object_id
inner join
    sys.schemas s
on
    t.schema_id = s.schema_id
where 
    fk.is_not_trusted = 1
Score: 5

WITH NOCHECK should only ever be applied 11 to FK's temporarily, or they become useless 10 to the optimiser as your linked article 9 points out. From BOL:

The query optimizer 8 does not consider constraints that are 7 defined WITH NOCHECK. Such constraints 6 are ignored until they are re-enabled 5 by using ALTER TABLE table CHECK CONSTRAINT ALL.

This 4 will identify all your Foreign Keys: (working 3 on the WITH NOCHECK bit...)

SELECT C.TABLE_CATALOG [PKTABLE_QUALIFIER], 
       C.TABLE_SCHEMA [PKTABLE_OWNER], 
       C.TABLE_NAME [PKTABLE_NAME], 
       KCU.COLUMN_NAME [PKCOLUMN_NAME], 
       C2.TABLE_CATALOG [FKTABLE_QUALIFIER], 
       C2.TABLE_SCHEMA [FKTABLE_OWNER], 
       C2.TABLE_NAME [FKTABLE_NAME], 
       KCU2.COLUMN_NAME [FKCOLUMN_NAME], 
       RC.UPDATE_RULE, 
       RC.DELETE_RULE, 
       C.CONSTRAINT_NAME [FK_NAME], 
       C2.CONSTRAINT_NAME [PK_NAME], 
       CAST(7 AS SMALLINT) [DEFERRABILITY] 
FROM   INFORMATION_SCHEMA.TABLE_CONSTRAINTS C 
       INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU 
         ON C.CONSTRAINT_SCHEMA = KCU.CONSTRAINT_SCHEMA 
            AND C.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME 
       INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC 
         ON C.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
            AND C.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 
       INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C2 
         ON RC.UNIQUE_CONSTRAINT_SCHEMA = C2.CONSTRAINT_SCHEMA 
            AND RC.UNIQUE_CONSTRAINT_NAME = C2.CONSTRAINT_NAME 
       INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2 
         ON C2.CONSTRAINT_SCHEMA = KCU2.CONSTRAINT_SCHEMA 
            AND C2.CONSTRAINT_NAME = KCU2.CONSTRAINT_NAME 
            AND KCU.ORDINAL_POSITION = KCU2.ORDINAL_POSITION 
WHERE  C.CONSTRAINT_TYPE = 'FOREIGN KEY'

Ref.

As an aside, in 2 both SQL Server 2000 and 2005, you can check 1 if any data violates a constraint using:

DBCC CHECKCONSTRAINTS (table_name)
Score: 3

The following code retrieves all foreign 3 keys that are marked 'WITH NOCHECK' and 2 then uses an ALTER statement to fix them 1 up:

-- configure cursor on all FKs with "WITH NOCHECK"
DECLARE UntrustedForeignKeysCursor CURSOR STATIC FOR
    SELECT  f.name,
            t.name 
    FROM    sys.foreign_keys AS f
            LEFT JOIN sys.tables AS t 
                ON f.parent_object_id = t.object_id 
    Where   Is_Not_Trusted = 1
OPEN UntrustedForeignKeysCursor

-- loop through the untrusted FKs
DECLARE @FKName varchar(100)
DECLARE @TableName varchar(100)
FETCH NEXT FROM UntrustedForeignKeysCursor INTO @FKName, @TableName
WHILE @@FETCH_STATUS = 0
BEGIN

    -- Rebuild the FK constraint WITH CHECK
    EXEC ('ALTER TABLE ' + @TableName + ' WITH CHECK CHECK CONSTRAINT ' + @FKName)

    -- get next user
    FETCH NEXT FROM UntrustedForeignKeysCursor INTO @FKName, @TableName

END

-- cleanup
CLOSE UntrustedForeignKeysCursor
Score: 0

I know this is an old question with some 15 old answers that have some good info. However, I 14 just wanted to share a script that I have 13 been using to address this problem area 12 in quite a few different databases for us:

-- Foreign Keys
SELECT 'ALTER TABLE ' + o.name + ' WITH CHECK CHECK CONSTRAINT ' + i.name + ';' AS AlterStatement
from sys.foreign_keys i
INNER JOIN sys.objects o ON i.parent_object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE i.is_not_trusted = 1 AND i.is_not_for_replication = 0;
GO

-- Constraints
SELECT 'ALTER TABLE ' + o.name + ' WITH CHECK CHECK CONSTRAINT ' + i.name + ';' AS AlterStatement
from sys.check_constraints i
INNER JOIN sys.objects o ON i.parent_object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE i.is_not_trusted = 1 AND i.is_not_for_replication = 0 AND i.is_disabled = 0;
GO

This 11 will generate a collection of ALTER statements 10 to fix this "NOCHECK" problem 9 with foreign keys and constraints. This 8 is based on some queries provided by Brent Ozar but 7 tweaked by me for my purposes and ease of 6 use. This could easily be tweaked with a 5 UNION to make it a single query.

FYI, I have used 4 this exclusively in Azure SQL Database environments. I'm 3 not sure if there are limitations on older 2 versions of SQL Server but it works great 1 in Azure.

More Related questions