从 sys 表编写外键脚本——与具有多列的键作斗争

Scripting foreign keys from sys tables -- struggling with keys that have multiple columns

大家好,提前致谢。

我一直在尝试编写现有数据库中的外键脚本,但在引用多列的键时遇到问题。

我使用的脚本如下:

    SELECT
    'FOREIGN_KEY' as KeyType,'ALTER TABLE ' +  OBJECT_NAME(f.parent_object_id) +
    ' WITH CHECK ADD CONSTRAINT ' + '[' + OBJECT_NAME(f.object_id) + 
    ']' + ' FOREIGN KEY ([' + col_name(fc.parent_object_id,fc.parent_column_id) + 
    ']) REFERENCES ' + OBJECT_NAME(f.referenced_object_id) + 
    ' ([' + COL_NAME(fc.referenced_object_id,fc.referenced_column_id) + ']) ALTER TABLE ' + 
    OBJECT_NAME(f.parent_object_id) + ' CHECK CONSTRAINT [' + 
    OBJECT_NAME(f.object_id) + ']' as result
    FROM 
       sys.foreign_keys AS f
    INNER JOIN 
       sys.foreign_key_columns AS fc 
      ON f.OBJECT_ID = fc.constraint_object_id
    INNER JOIN 
       sys.tables t 
         ON t.OBJECT_ID = fc.referenced_object_id
    WHERE 
       OBJECT_NAME (f.referenced_object_id) = @TableName

这将 return 所需的外键,但如上所述,我遇到以下结果的问题:

ALTER TABLE [dbo].[TreatmentPlanItems] WITH CHECK ADD CONSTRAINT [FK_TreatmentPlanItems_TPNumber] FOREIGN KEY([PatientCode]) REFERENCES [dbo].[TreatmentPlans] ([PatientCode]) ALTER TABLE [dbo].[TreatmentPlanItems] CHECK CONSTRAINT [FK_TreatmentPlanItems_TPNumber]  


ALTER TABLE [dbo].[TreatmentPlanItems] WITH CHECK ADD CONSTRAINT [FK_TreatmentPlanItems_TPNumber] FOREIGN KEY([TPNumber]) REFERENCES [dbo].[TreatmentPlans] ([TPNumber]) ALTER TABLE [dbo].[TreatmentPlanItems] CHECK CONSTRAINT [FK_TreatmentPlanItems_TPNumber]  

我需要的输出应该是这样的:

ALTER TABLE [dbo].[TreatmentPlanItems] WITH CHECK ADD CONSTRAINT [FK_TreatmentPlanItems_TPNumber] FOREIGN KEY([Patientcode],[TPNumber]) REFERENCES [dbo].[TreatmentPlans] ([Patientcode],[TPNumber]) ALTER TABLE [dbo].[TreatmentPlanItems] CHECK CONSTRAINT [FK_TreatmentPlanItems_TPNumber] 

如有任何帮助,我们将不胜感激。

谢谢

下面是代码示例,希望您能根据自己的需要采纳:

declare @tName sysname;
set @tName = 'dbo.TableName';

with vPKColumns as (
    select c.object_id, c.column_id, c.name, ixc.key_ordinal
    from sys.key_constraints pk
        join sys.index_columns ixc on ixc.object_id = pk.parent_object_id and ixc.index_id = pk.unique_index_id
        join sys.columns c on c.object_id = pk.parent_object_id and c.column_id = ixc.column_id
    where pk.parent_object_id = object_id(@tName) and pk.type = 'PK'
),
vFKs as (
    select
        quotename(fk.name) as name,
        fk.parent_object_id,
        fk.object_id,
        case
            when fk.delete_referential_action_desc collate database_default = 'NO_ACTION' then NULL
            else ' on delete ' + replace(lower(FK.delete_referential_action_desc) collate database_default, '_', ' ')
        end as onDelete,
        case
            when fk.update_referential_action_desc collate database_default = 'NO_ACTION' then NULL
            else ' on update ' + replace(lower(FK.update_referential_action_desc) collate database_default, '_', ' ')
        end as onUpdate
    from sys.foreign_keys fk
    where exists (
            select 1
            from sys.foreign_key_columns fkc
                join vPKColumns pkc on pkc.object_id = fkc.referenced_object_id and pkc.column_id = fkc.referenced_column_id
            where fkc.referenced_object_id = fk.referenced_object_id
        )
)
select
    'alter table ' + quotename(s.name) + '.' + quotename(t.name) + '
    with nocheck add constraint ' + fk.name + ' foreign key (' + stuff(
            (select ', ' + quotename(c.name)
            from sys.foreign_key_columns fkc
                join sys.columns c on c.object_id = fkc.parent_object_id and c.object_id = fkc.parent_object_id and c.column_id = fkc.parent_column_id
            where fkc.constraint_object_id = fk.object_id
            order by fkc.constraint_column_id
            for xml path(''), type).value('text()[1]','nvarchar(max)'),1,2,'') + ') references ' + @tName + ' (' + 
        stuff(
            (select ', ' + quotename(pkc.name)
            from vPKColumns pkc
            order by pkc.key_ordinal
            for xml path(''), type).value('text()[1]','nvarchar(max)'),1,2,'') + ')' +
        isnull('
        ' + onDelete, '') +
        isnull('
        ' + onUpdate, '') + ';
GO
alter table ' + quotename(s.name) + '.' + quotename(t.name) + '
    check constraint ' + fk.name + ';
GO'
from vFKs fk
    join sys.tables t on t.object_id = fk.parent_object_id
    join sys.schemas s on s.schema_id = t.schema_id
order by s.name, t.name, fk.name;