Technical Article

Detect invalid FK-data after using "WITH NOCHECK"

,

In situations where FK's have been created using the "WITH NOCHECK" option you can get into troubles because the FK-data is not checked ! (so there may be invalid data in the FK-column !)

E.g. ALTER TABLE [dbo].[mytable] WITH NOCHECK add constraint [FK__USED_RESO__Actio__1162CF5F] FOREIGN KEY ( Action_Type ) REFERENCES [dbo].[Action_Types] ( Action_Type )

BOL states "... If you do not want to verify new CHECK or FOREIGN KEY constraints against existing data,
use WITH NOCHECK.
We do not recommend doing this, except in rare cases. ..."


I've commented the proc because I found the DBCC command that does even more than that !

Avoid all the hassle with my poc and use :
-- DBCC CHECKCONSTRAINTS (TableName) - checks an individual table 
-- DBCC CHECKCONSTRAINTS (ConstraintName) - checks an individual constraint 
-- DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS - checks all constraints in the database 
-- DBCC CHECKCONSTRAINTS WITH ALL_ERRORMSGS - returns all rows that violate constraints 
-- DBCC CHECKCONSTRAINTS WITH NO_INFOMSGS - suppress messages when query runs


/*
create procedure Spc_ALZDBA_GenCheckLegacyFKErrors
  @ParentTbName  varchar(128)
, @ParentTbOwner varchar(128) = NULL
, @ConsolidateResults char(1) = 'N'
, @CommentInto char(1) = 'Y'

as 
begin
-- 
-- Generate Execution 
-- select 'exec Spc_ALZDBA_GenCheckLegacyFKErrors @ParentTbName = '''+ TABLE_NAME + ''' ,@ParentTbOwner = ''' + TABLE_SCHEMA + ''' , @ConsolidateResults=''N'' ,@CommentInto = ''Y'' ' + char(10) + 'go'
-- from INFORMATION_SCHEMA.TABLES
-- where TABLE_TYPE = 'BASE TABLE'
-- -- and TABLE_SCHEMA = 'Insite_Dev'
-- order by TABLE_SCHEMA, TABLE_NAME
-- 

SET nocount on

create table #tmpPKeys(
TABLE_QUALIFIER sysname, 
TABLE_OWNER sysname not null,
TABLE_NAME sysname not null,
COLUMN_NAME sysname not null,
KEY_SEQ smallint not null,
PK_NAME sysname  null )

Create index ix#tmpPKeys on #tmpPKeys (TABLE_QUALIFIER, TABLE_OWNER,TABLE_NAME, KEY_SEQ)


-- Get PK-info
insert into #tmpPKeys
exec sp_pkeys @table_name = @ParentTbName
,  @table_owner = @ParentTbOwner
--    [ , [ @table_qualifier = ] 'qualifier' ] -- DBName

create table #tmpFKeys 
(PKTABLE_QUALIFIER sysname not null, 
PKTABLE_OWNER sysname not null, 
PKTABLE_NAME sysname not null, 
PKCOLUMN_NAME sysname not null, 
FKTABLE_QUALIFIER sysname not null, 
FKTABLE_OWNER sysname not null,
FKTABLE_NAME sysname not null,
FKCOLUMN_NAME sysname not null,
KEY_SEQ smallint not null,
UPDATE_RULE smallint not null,
DELETE_RULE smallint not null,
FK_NAME sysname not null,
PK_NAME sysname not null,
DEFERRABILITY int not null)

Create index #tmpFKeys on #tmpFKeys (FK_NAME, KEY_SEQ)


-- Get FK-info (all dependent objects)
insert into #tmpFKeys
exec sp_fkeys  @pktable_name = @ParentTbName
, @pktable_owner = @ParentTbOwner
--     [ , [ @pktable_qualifier = ] 'pktable_qualifier' ] 
--     { , [ @fktable_name = ] 'fktable_name' } 
--     [ , [ @fktable_owner = ] 'fktable_owner' ] 
--     [ , [ @fktable_qualifier = ] 'fktable_qualifier' ]


if NOT exists (select * from #tmpFKeys where Key_SEQ = 1 )
  begin
print '-- No dependencies for ' + isnull(@ParentTbOwner + '.', '') + @ParentTbName 
  end

declare @Tabs as char(5) 
set @Tabs = ''
if exists (select * from #tmpFKeys where Key_SEQ = 1 )
begin
if @ConsolidateResults <> 'N'
begin
print '-- Create table #tmp (idnr int identity(1,1) not null primary key,  FK_Errorcount integer not null, FK_Constraint varchar(500) not null )'
end

print '--  Select rows with invalid FK-data --'
Print 'Set nocount on ; '
select 'print ''-- constraint [' + FK1.FK_NAME + '] for table [' + FK1.FKTABLE_OWNER + '].[' + FK1.FKTABLE_NAME + '] ''' + char(10)
+ case when @ConsolidateResults = 'N' then '' else 'Insert into #tmp (FK_Errorcount, FK_Constraint) ' + char(10) end
+ 'Select count(*) as [FK_Errorcount_' + FK1.FK_NAME + '], ' + '''constraint [' + FK1.FK_NAME + '] for table [' + FK1.FKTABLE_OWNER + '].[' + FK1.FKTABLE_NAME + ']'' as ConstraintInfo ' + char(10)
+ case when isnull(@CommentInto ,'Y') = 'N' then ''
       else '-- ' end
+ ' into  [Legacy_FK_Errors].[' + FK1.FKTABLE_OWNER + '__' + FK1.FKTABLE_NAME + ']' + char(10)
+ ' FROM [' + FK1.FKTABLE_OWNER + '].[' + FK1.FKTABLE_NAME + '] ChildTbl with (Nolock) '  + char(10) 
+ 'where not exists (Select * from [' + FK1.PKTABLE_OWNER + '].[' + FK1.PKTABLE_NAME + '] ParentTbl with (Nolock) ' + char(10)
+ @Tabs + ' where ChildTbl.[' + FK1.FKCOLUMN_NAME +'] = ParentTbl.[' + FK1.PKCOLUMN_NAME + ']'
+ case when FK2.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK2.FKCOLUMN_NAME +'] = ParentTbl.[' + FK2.PKCOLUMN_NAME + ']' end 
+ case when FK3.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK3.FKCOLUMN_NAME +'] = ParentTbl.[' + FK3.PKCOLUMN_NAME + ']' end 
+ case when FK4.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK4.FKCOLUMN_NAME +'] = ParentTbl.[' + FK4.PKCOLUMN_NAME + ']' end 
+ case when FK5.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK5.FKCOLUMN_NAME +'] = ParentTbl.[' + FK5.PKCOLUMN_NAME + ']' end 
+ case when FK6.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK6.FKCOLUMN_NAME +'] = ParentTbl.[' + FK6.PKCOLUMN_NAME + ']' end 
+ case when FK7.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK7.FKCOLUMN_NAME +'] = ParentTbl.[' + FK7.PKCOLUMN_NAME + ']' end 
+ case when FK8.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK8.FKCOLUMN_NAME +'] = ParentTbl.[' + FK8.PKCOLUMN_NAME + ']' end 
+ case when FK9.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK9.FKCOLUMN_NAME +'] = ParentTbl.[' + FK9.PKCOLUMN_NAME + ']' end 
+ case when FK10.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK10.FKCOLUMN_NAME +'] = ParentTbl.[' + FK10.PKCOLUMN_NAME + ']' end 
+ case when FK11.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK11.FKCOLUMN_NAME +'] = ParentTbl.[' + FK11.PKCOLUMN_NAME + ']' end 
+ case when FK12.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK12.FKCOLUMN_NAME +'] = ParentTbl.[' + FK12.PKCOLUMN_NAME + ']' end 
+ case when FK13.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK13.FKCOLUMN_NAME +'] = ParentTbl.[' + FK13.PKCOLUMN_NAME + ']' end 
+ case when FK14.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK14.FKCOLUMN_NAME +'] = ParentTbl.[' + FK14.PKCOLUMN_NAME + ']' end
+ case when FK15.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK15.FKCOLUMN_NAME +'] = ParentTbl.[' + FK15.PKCOLUMN_NAME + ']' end 
+ case when FK16.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK16.FKCOLUMN_NAME +'] = ParentTbl.[' + FK16.PKCOLUMN_NAME + ']' end 
+ case when FK17.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK17.FKCOLUMN_NAME +'] = ParentTbl.[' + FK17.PKCOLUMN_NAME + ']' end 
+ case when FK18.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK18.FKCOLUMN_NAME +'] = ParentTbl.[' + FK18.PKCOLUMN_NAME + ']' end 
+ ' ) ' +  char(10)
+ ' and ChildTbl.[' + FK1.FKCOLUMN_NAME + '] is not null ' 
+ case when FK2.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK2.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK3.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK3.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK4.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK4.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK5.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK5.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK6.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK6.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK7.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK7.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK8.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK8.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK9.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK9.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK10.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK10.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK11.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK11.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK12.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK12.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK13.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK13.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK14.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK14.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK15.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK15.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK16.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK16.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK17.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK17.FKCOLUMN_NAME +'] is not null ' end 
+ case when FK18.FKCOLUMN_NAME is null then '' else char(10) + @Tabs + ' and ChildTbl.[' + FK18.FKCOLUMN_NAME +'] is not null ' end 
+ ' ; ' +  char(10) + 'GO ' 
from #tmpFKeys FK1
left join #tmpFKeys FK2
on FK1.FK_NAME = FK2.FK_NAME and FK1.KEY_SEQ = 1 and FK2.KEY_SEQ = 2
left join #tmpFKeys FK3
on FK1.FK_NAME = FK3.FK_NAME and FK1.KEY_SEQ = 1 and FK3.KEY_SEQ = 3
left join #tmpFKeys FK4
on FK1.FK_NAME = FK4.FK_NAME and FK1.KEY_SEQ = 1 and FK4.KEY_SEQ = 4
left join #tmpFKeys FK5
on FK1.FK_NAME = FK5.FK_NAME and FK1.KEY_SEQ = 1 and FK5.KEY_SEQ = 5
left join #tmpFKeys FK6
on FK1.FK_NAME = FK6.FK_NAME and FK1.KEY_SEQ = 1 and FK6.KEY_SEQ = 6
left join #tmpFKeys FK7
on FK1.FK_NAME = FK7.FK_NAME and FK1.KEY_SEQ = 1 and FK7.KEY_SEQ = 7
left join #tmpFKeys FK8 
on FK1.FK_NAME = FK8.FK_NAME and FK1.KEY_SEQ = 1 and FK8.KEY_SEQ = 8
left join #tmpFKeys FK9
on FK1.FK_NAME = FK9.FK_NAME and FK1.KEY_SEQ = 1 and FK9.KEY_SEQ = 9
left join #tmpFKeys FK10
on FK1.FK_NAME = FK10.FK_NAME and FK1.KEY_SEQ = 1 and FK10.KEY_SEQ = 10
left join #tmpFKeys FK11
on FK1.FK_NAME = FK11.FK_NAME and FK1.KEY_SEQ = 1 and FK11.KEY_SEQ = 11
left join #tmpFKeys FK12
on FK1.FK_NAME = FK12.FK_NAME and FK1.KEY_SEQ = 1 and FK12.KEY_SEQ = 12
left join #tmpFKeys FK13
on FK1.FK_NAME = FK13.FK_NAME and FK1.KEY_SEQ = 1 and FK13.KEY_SEQ = 13
left join #tmpFKeys FK14
on FK1.FK_NAME = FK14.FK_NAME and FK1.KEY_SEQ = 1 and FK14.KEY_SEQ = 14
left join #tmpFKeys FK15
on FK1.FK_NAME = FK15.FK_NAME and FK1.KEY_SEQ = 1 and FK15.KEY_SEQ = 15
left join #tmpFKeys FK16
on FK1.FK_NAME = FK16.FK_NAME and FK1.KEY_SEQ = 1 and FK16.KEY_SEQ = 16
left join #tmpFKeys FK17
on FK1.FK_NAME = FK17.FK_NAME and FK1.KEY_SEQ = 1 and FK17.KEY_SEQ = 17
left join #tmpFKeys FK18
on FK1.FK_NAME = FK18.FK_NAME and FK1.KEY_SEQ = 1 and FK18.KEY_SEQ = 18

where FK1.KEY_SEQ = 1
order by FK1.FKTABLE_OWNER, FK1.FKTABLE_NAME, FK1.FK_NAME
  
if @ConsolidateResults <> 'N'
begin
print '-- Select * from #tmp Order by idnr '
end

end

-- cleanup
drop table #tmpPKeys
drop table #tmpFKeys



end

*/

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating