DA, aka Data Administrators + ERWin = MESS
As both parent colum name and child column name have the same name on my database and PK indexes are all named like 'XPK_%', I created the script below to help me out. Take a look at it and let your comments.
/* DROP TABLE #constraints */ -- list all constraints on database SELECT dbo.sysobjects.parent_obj AS tableid, 'PK' AS constraintType, dbo.sysobjects.name AS constraintName, dbo.syscolumns.name AS keyColumn, dbo.sysindexkeys.keyno INTO #constraints FROM dbo.sysobjects INNER JOIN dbo.sysindexes ON dbo.sysobjects.name = dbo.sysindexes.name INNER JOIN dbo.sysindexkeys ON dbo.sysindexes.indid = dbo.sysindexkeys.indid AND dbo.sysindexes.id = dbo.sysindexkeys.id INNER JOIN dbo.syscolumns ON dbo.sysindexkeys.colid = dbo.syscolumns.colid AND dbo.sysobjects.parent_obj = dbo.syscolumns.id WHERE dbo.sysobjects.xtype = 'PK' UNION ALL SELECT sysindexes.id AS tableid, 'AK' AS constraintType, sysindexes.name AS constraintName, syscolumns.name AS keyColumn, sysindexkeys.keyno FROM sysindexes INNER JOIN sysindexkeys ON sysindexes.id = sysindexkeys.id AND sysindexes.indid = sysindexkeys.indid INNER JOIN syscolumns ON sysindexkeys.id = syscolumns.id AND sysindexkeys.colid = syscolumns.colid INNER JOIN sysobjects ON syscolumns.id = sysobjects.id WHERE (sysindexes.status & 2) <> 0 AND sysindexes.name NOT LIKE 'XPK_%' UNION ALL SELECT sysobjects.parent_obj AS tableid, 'FK' AS constraintType, sysobjects.name AS constraintName, syscolumns.name AS keyColumn, sysforeignkeys.keyno FROM sysobjects INNER JOIN sysforeignkeys ON sysobjects.id = sysforeignkeys.constid INNER JOIN syscolumns ON sysforeignkeys.fkeyid = syscolumns.id AND sysforeignkeys.fkey = syscolumns.colid INNER JOIN syscolumns AS syscolumnsParent ON sysforeignkeys.rkey = syscolumnsParent.colid AND sysforeignkeys.rkeyid = syscolumnsParent.id INNER JOIN sysobjects AS sysobjectsParent ON syscolumnsParent.id = sysobjectsParent.id WHERE sysobjects.xtype = 'F' /* DROP TABLE #duplicateKeyColumns */ -- Since both parent and child column names are the same, duplicates which are PK/AK -- on some table might be the starting point of search SELECT sc.name AS columnName, COUNT(*) AS score INTO #duplicateKeyColumns FROM syscolumns sc INNER JOIN sysobjects so ON sc.id = so.id WHERE so.type = 'U' AND so.name NOT IN ('exclude list comes here') AND EXISTS( SELECT #constraints.keyColumn FROM #constraints WHERE #constraints.keyColumn = sc.name AND #constraints.constraintType IN ('PK', 'AK') ) GROUP BY sc.name HAVING COUNT(*) > 1 ORDER BY score DESC /* DROP TABLE #duplicateKeyColumnsRelatedTables */ SELECT sc.name AS columnName, so.name AS tableName, CASE WHEN EXISTS( SELECT #constraints.keyColumn FROM #constraints WHERE #constraints.tableid = so.id AND #constraints.keyColumn = sc.name AND #constraints.constraintType IN ('PK') ) THEN '*' ELSE NULL END AS [PK], CASE WHEN EXISTS( SELECT #constraints.keyColumn FROM #constraints WHERE #constraints.tableid = so.id AND #constraints.keyColumn = sc.name AND #constraints.constraintType IN ('AK') ) THEN '*' ELSE NULL END AS [AK], CASE WHEN EXISTS( SELECT #constraints.keyColumn FROM #constraints WHERE #constraints.tableid = so.id AND #constraints.keyColumn = sc.name AND #constraints.constraintType IN ('FK') ) THEN '*' ELSE NULL END AS [FK] INTO #duplicateKeyColumnsRelatedTables FROM syscolumns sc INNER JOIN sysobjects so ON sc.id = so.id INNER JOIN #duplicateKeyColumns ON sc.name = #duplicateKeyColumns.columnName WHERE so.type = 'U' AND so.name NOT IN ('exclude list comes here') AND ( EXISTS( SELECT #constraints.keyColumn FROM #constraints WHERE #constraints.tableid = so.id AND #constraints.keyColumn = sc.name AND #constraints.constraintType IN ('PK', 'AK') ) OR NOT EXISTS( SELECT #constraints.keyColumn FROM #constraints WHERE #constraints.tableid = so.id AND #constraints.keyColumn = sc.name AND #constraints.constraintType IN ('FK') ) ) ORDER BY #duplicateKeyColumns.score DESC, #duplicateKeyColumns.columnName, so.name -- deletes all duplicate key columns which does not have table(s) missing any FK DELETE #duplicateKeyColumnsRelatedTables WHERE EXISTS( SELECT COUNT(*) FROM #duplicateKeyColumnsRelatedTables AS duplicateKeyColumnsRelatedTablesSQ WHERE duplicateKeyColumnsRelatedTablesSQ.columnName = #duplicateKeyColumnsRelatedTables.columnName AND duplicateKeyColumnsRelatedTablesSQ.[FK] IS NULL HAVING COUNT(*) <= 1 ) -- for each column listed, one of the related tables, with PK containing the column name -- on its list, is the root of information. When you find the root (parentTable), all the -- other tables without FKs containing the column are the the tables missing FKs on them SELECT * FROM #duplicateKeyColumnsRelatedTables WHERE [FK] IS NULL