-- Based on http://richarddingwall.name/2008/12/21/find-missing-foreignprimary-keys-in-sql-server/ Thanks!
-- Pretty printed with http://www.dpriver.com/pp/sqlformat.htm Thanks!
-- Find columns with names like K% on %_Fact tables which:
-- are also a primary key column name on a '%_Dim' table
-- and aren't part of the primary key
-- and should probably be foreign keys, but aren't.
-- Updates: NOCHECK * WITH CHECK
--
-- Limitations:
-- Sorry, not designed for compound primary keys.
-- Only works with DBO schema
SELECT 'ALTER TABLE ' + Quotename(Object_name(t.object_id)) + ' WITH NOCHECK ADD CONSTRAINT [FK_' + Object_name(t.object_id) + '_' + rpkc.NAME + '] ' + 'FOREIGN KEY([' + rpkc.NAME + ']) REFERENCES [' + pkt.NAME + '] ([' + rpkc.NAME + ']) ;' + Char(10) AS SQLCreateConstraint
,'ALTER TABLE ' + Quotename(Object_name(t.object_id)) + ' WITH CHECK CHECK CONSTRAINT [FK_' + Object_name(t.object_id) + '_' + rpkc.NAME + '] ;' + Char(10) AS SQLCheckConstraint
FROM sys.tables t
INNER JOIN sys.syscolumns c ON c.id = t.object_id
-- And it's a primary key elsewhere
INNER JOIN sys.columns AS rpkc ON c.NAME = rpkc.NAME
INNER JOIN sys.index_columns AS pkic ON pkic.object_id = rpkc.object_id
AND pkic.column_id = rpkc.column_id
INNER JOIN sys.indexes AS pki ON pki.object_id = pkic.object_id
AND pki.index_id = pkic.index_id
AND pki.is_primary_key = 1
INNER JOIN sys.tables AS pkt ON pki.object_id = pkt.object_id
-- Join on foreign key columns
LEFT JOIN sys.foreign_key_columns fkc ON (
fkc.parent_object_id = t.object_id
AND c.colid = fkc.parent_column_id
)
OR (
fkc.referenced_object_id = t.object_id
AND c.colid = fkc.referenced_column_id
)
-- Join on primary key columns
LEFT JOIN sys.indexes i ON i.object_id = t.object_id
AND i.is_primary_key = 1
LEFT JOIN sys.index_columns ic ON ic.object_id = t.object_id
AND ic.index_id = i.index_id
AND ic.column_id = c.colid
WHERE t.is_ms_shipped = 0
AND (c.NAME LIKE 'K%')
AND (
fkc.constraint_object_id IS NULL -- Not part of a foreign key
AND ic.object_id IS NULL -- Not part of a primary key
)
AND t.NAME LIKE '%[_]Fact'
AND pkt.NAME LIKE '%[_]Dim'
AND (
-- Ignore some tables
t.NAME != 'sysdiagrams'
AND t.NAME NOT LIKE '[_]%' -- temp tables
AND t.NAME NOT LIKE '%temp%'
AND t.NAME NOT LIKE '%Log%' -- log tables
AND t.NAME NOT LIKE '%[_]bak' -- _bak tables
-- Ignore some columns
AND c.NAME NOT IN ('xxx') -- external keys
)
AND Object_schema_name(t.object_id) = 'dbo'
AND Object_schema_name(pkt.object_id) = 'dbo'
ORDER BY t.NAME
,c.NAME
-- Pretty printed with http://www.dpriver.com/pp/sqlformat.htm Thanks!
-- Find columns with names like K% on %_Fact tables which:
-- are also a primary key column name on a '%_Dim' table
-- and aren't part of the primary key
-- and should probably be foreign keys, but aren't.
-- Updates: NOCHECK * WITH CHECK
--
-- Limitations:
-- Sorry, not designed for compound primary keys.
-- Only works with DBO schema
SELECT 'ALTER TABLE ' + Quotename(Object_name(t.object_id)) + ' WITH NOCHECK ADD CONSTRAINT [FK_' + Object_name(t.object_id) + '_' + rpkc.NAME + '] ' + 'FOREIGN KEY([' + rpkc.NAME + ']) REFERENCES [' + pkt.NAME + '] ([' + rpkc.NAME + ']) ;' + Char(10) AS SQLCreateConstraint
,'ALTER TABLE ' + Quotename(Object_name(t.object_id)) + ' WITH CHECK CHECK CONSTRAINT [FK_' + Object_name(t.object_id) + '_' + rpkc.NAME + '] ;' + Char(10) AS SQLCheckConstraint
FROM sys.tables t
INNER JOIN sys.syscolumns c ON c.id = t.object_id
-- And it's a primary key elsewhere
INNER JOIN sys.columns AS rpkc ON c.NAME = rpkc.NAME
INNER JOIN sys.index_columns AS pkic ON pkic.object_id = rpkc.object_id
AND pkic.column_id = rpkc.column_id
INNER JOIN sys.indexes AS pki ON pki.object_id = pkic.object_id
AND pki.index_id = pkic.index_id
AND pki.is_primary_key = 1
INNER JOIN sys.tables AS pkt ON pki.object_id = pkt.object_id
-- Join on foreign key columns
LEFT JOIN sys.foreign_key_columns fkc ON (
fkc.parent_object_id = t.object_id
AND c.colid = fkc.parent_column_id
)
OR (
fkc.referenced_object_id = t.object_id
AND c.colid = fkc.referenced_column_id
)
-- Join on primary key columns
LEFT JOIN sys.indexes i ON i.object_id = t.object_id
AND i.is_primary_key = 1
LEFT JOIN sys.index_columns ic ON ic.object_id = t.object_id
AND ic.index_id = i.index_id
AND ic.column_id = c.colid
WHERE t.is_ms_shipped = 0
AND (c.NAME LIKE 'K%')
AND (
fkc.constraint_object_id IS NULL -- Not part of a foreign key
AND ic.object_id IS NULL -- Not part of a primary key
)
AND t.NAME LIKE '%[_]Fact'
AND pkt.NAME LIKE '%[_]Dim'
AND (
-- Ignore some tables
t.NAME != 'sysdiagrams'
AND t.NAME NOT LIKE '[_]%' -- temp tables
AND t.NAME NOT LIKE '%temp%'
AND t.NAME NOT LIKE '%Log%' -- log tables
AND t.NAME NOT LIKE '%[_]bak' -- _bak tables
-- Ignore some columns
AND c.NAME NOT IN ('xxx') -- external keys
)
AND Object_schema_name(t.object_id) = 'dbo'
AND Object_schema_name(pkt.object_id) = 'dbo'
ORDER BY t.NAME
,c.NAME
Edited to add with NOCHECK and WITH CHECK. Thanks http://www.brentozar.com/blitz/foreign-key-trusted/
ReplyDelete