【问题标题】:tsql get fk_key specificationtsql 获取 fk_key 规范
【发布时间】:2017-10-18 06:21:17
【问题描述】:

所以我需要重新创建一堆外键。原因是我想向密钥添加级联,为此我需要删除并重新创建密钥。当然我可以通过右键单击键->修改->并添加级联来通过ssms来完成。 但我有 100 把钥匙,我想在脚本中执行此操作。

我有一个想法,我应该能够调用 ssms 中的方法,该方法将密钥脚本写入新的查询编辑器,而是将生成的脚本推送到变量中。删除现有密钥。更新key的字符串表示,然后执行动态sql创建。

虽然我无法编写密钥脚本。 有谁知道如何做到这一点,或者有其他方法吗?

【问题讨论】:

    标签: sql-server sql-server-2008 tsql ssms


    【解决方案1】:

    Aaron Bertrand 的 article 准确地描述了这一点,它将为您完成工作。

    它正在动态创建@create 和@drop sql 查询。您只需更改创建脚本,以便在 @create 查询的这一部分添加 'on delete cascade':

    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ') 
    ON DELETE CASCADE;'
    

    它将删除并重新创建数据库每个表中的每个外键。

    确保在执行之前检查生成的查询。

    您可以尝试一个工作版本here,Rextester 带有一个架构和一些表,因此您可以看到结果。

    【讨论】:

      【解决方案2】:

      我编写了一个外键脚本,并使用sys 表来获取重建脚本所需的所有详细信息:

      SELECT FK.[name]
            --
            ,FK.[delete_referential_action_desc]
            ,FK.[update_referential_action_desc]
            --
            ,KC.[constraint_column_id]
            ,PS.[name]
            ,P.[name]
            ,PTC.[name]
            --
            ,RTS.[name]
            ,RT.[name]
            ,RTC.[name]
      FROM [sys].[foreign_keys] FK
      INNER JOIN [sys].[objects] P
          ON FK.[parent_object_id] = P.[object_id]
      INNER JOIN [sys].[schemas] PS
          ON P.[schema_id] = PS.[schema_id]
      INNER JOIN [sys].[foreign_key_columns] KC
          ON FK.[object_id] = KC.[constraint_object_id]
      -- parent columns
      INNER JOIN [sys].[columns] PTC
          ON P.[object_id] = PTC.[object_id]
          AND KC.[parent_column_id] = PTC.[column_id]
      -- referenced table schema, name and columns
      INNER JOIN [sys].[objects] RT
          ON KC.[referenced_object_id] = RT.[object_id]
      INNER JOIN [sys].[schemas] RTS
          ON RT.[schema_id] = RTS.[schema_id]
      INNER JOIN [sys].[columns] RTC
          ON RT.[object_id] = RTC.[object_id]
          AND KC.[referenced_column_id] = RTC.[column_id];
      

      这甚至会给我每个表的架构细节。现在,您可以使用这条 T-SQL 语句来做您想做的事。请注意,我将其包装在 CTE 中只是为了使内容更具可读性。此外,我们还有第二个CTE 来处理外键由多列组成的情况。

      WITH DataSource AS
      (
          SELECT FK.[name] AS [FK_Name]
                --
                ,FK.[delete_referential_action_desc]
                ,FK.[update_referential_action_desc]
                --
                ,KC.[constraint_column_id] AS [FK_ColumnPos]
                ,PS.[name] AS [PT_SCHEMA_NAME]
                ,P.[name] AS [PT_NAME]
                ,PTC.[name]  AS [PT_COLUMN_NAME]
                --
                ,RTS.[name] AS [RF_SCHEMA_NAME]
                ,RT.[name] AS [RF_NAME]
                ,RTC.[name] AS [RF_COLUMN_NAME]
          FROM [sys].[foreign_keys] FK
          INNER JOIN [sys].[objects] P
              ON FK.[parent_object_id] = P.[object_id]
          INNER JOIN [sys].[schemas] PS
              ON P.[schema_id] = PS.[schema_id]
          INNER JOIN [sys].[foreign_key_columns] KC
              ON FK.[object_id] = KC.[constraint_object_id]
          -- parent columns
          INNER JOIN [sys].[columns] PTC
              ON P.[object_id] = PTC.[object_id]
              AND KC.[parent_column_id] = PTC.[column_id]
          -- referenced table schema, name and columns
          INNER JOIN [sys].[objects] RT
              ON KC.[referenced_object_id] = RT.[object_id]
          INNER JOIN [sys].[schemas] RTS
              ON RT.[schema_id] = RTS.[schema_id]
          INNER JOIN [sys].[columns] RTC
              ON RT.[object_id] = RTC.[object_id]
              AND KC.[referenced_column_id] = RTC.[column_id]
      ), DataSourcePrecalc AS
      (
          SELECT DISTINCT 
                 [FK_Name]
                ,[delete_referential_action_desc]
                ,[update_referential_action_desc]
                ,[PT_SCHEMA_NAME]
                ,[PT_NAME]
                ,STUFF
                (
                      (
                          SELECT ', [' + DS1.[PT_COLUMN_NAME] + ']' 
                          FROM DataSource DS1
                          WHERE DS1.[FK_Name] = DS.[FK_Name]
                              AND DS1.[PT_NAME] = DS.[PT_NAME]
                          ORDER BY DS1.[FK_ColumnPos]
                          FOR XML PATH(''), TYPE
                      ).value('.', 'NVARCHAR(MAX)')
                      ,1
                      ,2
                      ,''
                ) AS [PT_COLUMNS]
                ,[RF_SCHEMA_NAME]
                ,[RF_NAME]
                ,STUFF
                (
                      (
                          SELECT ', [' + DS2.[RF_COLUMN_NAME] + ']' 
                          FROM DataSource DS2
                          WHERE DS2.[FK_Name] = DS.[FK_Name]
                              AND DS2.[RF_NAME] = DS.[RF_NAME]
                          ORDER BY DS2.[FK_ColumnPos]
                          FOR XML PATH(''), TYPE
                      ).value('.', 'NVARCHAR(MAX)')
                      ,1
                      ,2
                      ,''
                ) AS [RT_COLUMNS]
          FROM DataSource DS
      )
      SELECT 
      '
      ALTER TABLE [' + [PT_SCHEMA_NAME] + '].[' + [PT_NAME] + '] DROP CONSTRAINT [' + [FK_Name] + '];
      
      ALTER TABLE [' + [PT_SCHEMA_NAME] + '].[' + [PT_NAME] + ']  WITH CHECK ADD  CONSTRAINT [' + [FK_Name] + '] FOREIGN KEY(' + [PT_COLUMNS] + ')
      REFERENCES [' + [RF_SCHEMA_NAME] + '].[' + [RF_NAME] + '] (' + [RT_COLUMNS] + ')
      ON UPDATE CASCADE
      ON DELETE CASCADE;
      
      ALTER TABLE [' + [PT_SCHEMA_NAME] + '].[' + [PT_NAME] + '] CHECK CONSTRAINT [' + [FK_Name] + '];
      '
      FROM DataSourcePrecalc;
      

      注意,这里的 CASCADE 值是硬编码的。如果需要,您可以添加一些其他逻辑,使用原始逻辑。这里更重要的是为我们带来所有需要的详细信息的初始查询。有了它,你就可以为所欲为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-04
        • 2012-02-07
        • 1970-01-01
        • 2015-05-21
        • 2015-03-10
        • 1970-01-01
        相关资源
        最近更新 更多