2017-10-18 34 views
0

J'ai donc besoin de recréer un tas de clés étrangères. La raison en est que je veux ajouter une cascade à la clé, et pour ce faire, je dois laisser tomber et recréer la clé. Bien sûr, je pourrais le faire par ssms en faisant un clic droit sur la touche-> modifier-> et ajouter en cascade. Mais j'ai 100 clés et je voudrais le faire dans un script. J'ai une idée que je devrais être capable d'invoquer la méthode dans ssms qui écrit la clé d'un nouvel éditeur de requête, mais à la place pousser le script résultant dans une variable. abandonne la clé existante. Mettez à jour la représentation sous forme de chaîne de la clé, puis exécutez SQL dynamique pour le créer.tsql get fk_key spécification

Bien que je ne puisse pas scripter la clé. Est-ce que quelqu'un sait comment faire cela ou existe-t-il un autre moyen?

Répondre

0

Ce article par Aaron Bertrand décrit exactement cela et il va faire le travail pour vous. Il crée dynamiquement les requêtes @create et @drop sql. Vous aurez seulement besoin de changer le script de création afin que vous ajoutez 'on delete cascade' à cette partie de la requête @create:

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

Il chutera et recréer chaque clé étrangère dans toutes les tables de votre base de données.

Assurez-vous de vérifier les requêtes générées avant de les exécuter.

Vous pouvez essayer une version de travail here, le Rextester est déjà livré avec un schéma et quelques tables afin que vous puissiez voir les résultats.

0

J'ai scénarisé une clé étrangère, et d'utiliser les tables sys pour obtenir tous les détails que je dois reconstruire le script:

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]; 

Cela me donnera même les détails du schéma de chaque table. Maintenant, vous pouvez utiliser cette instruction T-SQL afin de faire ce que vous voulez. Remarque, je suis en train de l'emballage dans CTE juste pour rendre les choses plus lisibles. En outre, nous avons la deuxième CTE afin de gérer les situations où la clé étrangère est composée de plusieurs colonnes.

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; 

Notez ici les valeurs CASCADE sont difficiles codded. Vous pouvez ajouter une autre logique si vous voulez, utilisez les originaux. Ce qui est plus important ici, c'est la requête initiale qui nous apporte tous les détails nécessaires. L'avoir, vous pouvez faire ce que vous voulez.