SQL Server猜测丢失了外键

时间:2016-03-03 13:26:33

标签: sql-server foreign-keys

我尝试使用以下SQL代码猜测丢失的外键

DECLARE @ColumnList AS TABLE 
( 
     TableName      varchar(255) NOT NULL, 
     ColumnName     varchar(255) NOT NULL,
     PKTableName    varchar(255),
     PKColumnName   varchar(255),
     HasForeignKey  bit NOT NULL             
) 

-- Find all column names that occur more than once. 
-- Exclude archive and staging tables. 
INSERT INTO @ColumnList 
            (TableName, 
             ColumnName, 
             PKTableName,
             PKColumnName,
             HasForeignKey)          
SELECT t.NAME AS TableName, 
       c.NAME AS ColumnName,
       NULL AS PKTableName,
       NULL AS PKColumnName,           
       CASE 
         WHEN f1.parent_object_id IS NOT NULL THEN 1 
         WHEN f2.referenced_object_id IS NOT NULL THEN 1 
         ELSE 0 
       END AS HasForeignKey
FROM   sys.tables AS t 
       JOIN sys.columns AS c 
         ON c.object_id = t.object_id 
       JOIN sys.types AS y 
         ON c.system_type_id = y.system_type_id 
       LEFT JOIN sys.foreign_key_columns AS f1 
              ON f1.parent_object_id = t.object_id AND f1.parent_column_id = c.column_id 
       LEFT JOIN sys.foreign_key_columns AS f2 
              ON f2.referenced_object_id = t.object_id AND f2.referenced_column_id = c.column_id 
WHERE  t.is_ms_shipped = 0 AND y.NAME IN ('bigint', 'int', 'smallint', 'tinyint', 'uniqueidentifier');

SELECT TableName, 
       ColumnName,
       PKTableName,
       PKColumnName
FROM   @ColumnList 
WHERE  HasForeignKey = 0 
       AND ColumnName IN (SELECT ColumnName 
                          FROM   @ColumnList 
                          GROUP  BY ColumnName 
                          HAVING Count(*) > 1) 
ORDER  BY ColumnName, 
          TableName;

工作正常并展示了许多候选人。但是,我不知道如何显示可能的主键的表名和列名。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

试试这个

DECLARE @ColumnList AS TABLE 
  ( 
     TableName      varchar(255) NOT NULL, 
     ColumnName     varchar(255) NOT NULL,
     PKTableName    varchar(255),
     PKColumnName   varchar(255),
     HasForeignKey  bit NOT NULL             
  ) 

-- Find all column names that occur more than once. 
-- Exclude archive and staging tables. 
INSERT INTO @ColumnList 
            (TableName, 
             ColumnName, 
             PKTableName,
             PKColumnName,
             HasForeignKey) 
SELECT t.NAME AS TableName, 
       c.NAME AS ColumnName,
       t2.NAME AS PKTableName,
       c2.NAME AS PKColumnName,
       CASE 
         WHEN f1.parent_object_id IS NOT NULL THEN 1 
         WHEN f2.referenced_object_id IS NOT NULL THEN 1 
         ELSE 0 
       END AS HasForeignKey
FROM   sys.tables AS t 
       JOIN sys.columns AS c 
         ON c.object_id = t.object_id 
       JOIN sys.types AS y 
         ON c.system_type_id = y.system_type_id 
       LEFT JOIN sys.columns c2
         ON (c.Name = c2.Name)
       JOIN sys.tables t2
         ON (c2.object_id = t2.object_id AND t.object_id <> t2.object_id)
       LEFT JOIN sys.foreign_key_columns AS f1 
              ON f1.parent_object_id = t.object_id AND f1.parent_column_id = c.column_id 
       LEFT JOIN sys.foreign_key_columns AS f2 
              ON f2.referenced_object_id = t.object_id AND f2.referenced_column_id = c.column_id 
WHERE  t.is_ms_shipped = 0 AND y.NAME IN ('bigint', 'int', 'smallint', 'tinyint', 'uniqueidentifier');

SELECT TableName, 
       ColumnName,
       PKTableName,
       PKColumnName
FROM   @ColumnList 
WHERE  HasForeignKey = 0 
       AND ColumnName IN (SELECT ColumnName 
                          FROM   @ColumnList 
                          GROUP  BY ColumnName 
                          HAVING Count(*) > 1) 
ORDER  BY ColumnName, 
          TableName;

答案 1 :(得分:0)

我会尝试根据列名称对主键执行LEFT OUTER JOIN

LEFT OUTER JOIN 
(
        INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
    INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CCU ON
        CCU.CONSTRAINT_CATALOG = TC.CONSTRAINT_CATALOG AND
        CCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA AND
        CCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME AND
        CCU.TABLE_CATALOG = TC.TABLE_CATALOG AND
        CCU.TABLE_SCHEMA = TC.TABLE_SCHEMA AND
        CCU.TABLE_NAME = TC.TABLE_NAME
) ON
    CCU.COLUMN_NAME = C.ColumnName AND    -- Use the @ColumnList.ColumnName here
    TC.CONSTRAINT_TYPE = 'PRIMARY KEY'

这与复合PK有点分解。如果名称不匹配也不起作用 - 例如,有些人会将“id”用于“人物”的PK,但在FK中它将是“person_id”。