J'exécute un package SSIS qui remplacera les données de quelques tables de FlatFiles aux tables existantes d'une base de données.
Mon paquet tronquera les tables puis insérera les nouvelles données. Lorsque j'exécute mon package SSIS, je reçois une exception à cause des clés étrangères.
Puis-je désactiver les contraintes, lancer mon importation, puis les réactiver?
Pour désactiver les contraintes de clé étrangère:
DECLARE @sql NVARCHAR(MAX) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' NOCHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql @sql;
Pour réactiver:
DECLARE @sql NVARCHAR(MAX) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql @sql;
Cependant, vous ne pourrez pas tronquer les tables, vous devrez les supprimer dans le bon ordre. Si vous devez les tronquer, vous devez supprimer complètement les contraintes et les recréer. Cette opération est simple si vos contraintes de clé étrangère sont toutes simples, à une seule colonne, mais nettement plus complexes si plusieurs colonnes sont impliquées.
Voici quelque chose que vous pouvez essayer. Afin d'en faire une partie de votre package SSIS, vous aurez besoin d'un emplacement pour stocker les définitions FK pendant l'exécution du package SSIS (vous ne pourrez pas effectuer tout cela dans un script). Donc, dans une base de données d’utilitaires, créez une table:
CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));
Ensuite, dans votre base de données, vous pouvez avoir une procédure stockée qui effectue ceci:
DELETE other_database.dbo.PostCommand;
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id))
+ ' ADD CONSTRAINT ' + fk.name + ' FOREIGN KEY ('
+ STUFF((SELECT ',' + c.name
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.parent_column_id = c.column_id
AND fkc.parent_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '')
+ ') REFERENCES ' +
QUOTENAME(OBJECT_SCHEMA_NAME(fk.referenced_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.referenced_object_id))
+ '(' +
STUFF((SELECT ',' + c.name
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.referenced_column_id = c.column_id
AND fkc.referenced_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '') + ');
' FROM sys.foreign_keys AS fk
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;
INSERT other_database.dbo.PostCommand(cmd) SELECT @sql;
IF @@ROWCOUNT = 1
BEGIN
SET @sql = N'';
SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id))
+ ' DROP CONSTRAINT ' + fk.name + ';
' FROM sys.foreign_keys AS fk;
EXEC sp_executesql @sql;
END
Désormais, lorsque votre package SSIS est terminé, il doit appeler une autre procédure stockée, qui:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = cmd FROM other_database.dbo.PostCommand;
EXEC sp_executesql @sql;
Si vous faites tout cela dans le seul but de pouvoir tronquer au lieu de supprimer, je suggère simplement de prendre le hit et d'exécuter une suppression. Utilisez peut-être un modèle de récupération consigné en bloc pour minimiser l’impact du journal. En général, je ne vois pas en quoi cette solution sera beaucoup plus rapide que de simplement utiliser une suppression dans le bon ordre.
En 2014, j'ai publié un article plus élaboré à ce sujet ici:
Utilisez la procédure intégrée sp_msforeachtable .
Pour désactiver toutes les contraintes:
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL";
Pour activer toutes les contraintes:
EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL";
Pour supprimer toutes les tables:
EXEC sp_msforeachtable "DROP TABLE ?";
Une bonne référence est donnée à: http://msdn.Microsoft.com/en-us/magazine/cc163442.aspx Dans la section "Désactivation de toutes les clés étrangères".
En s'inspirant de cela, une approche peut être réalisée en créant une table temporaire et en insérant les contraintes dans cette table, puis en supprimant les contraintes et en les réappliquant à partir de cette table temporaire. Assez dit voici ce que je parle
SET NOCOUNT ON
DECLARE @temptable TABLE(
Id INT PRIMARY KEY IDENTITY(1, 1),
FKConstraintName VARCHAR(255),
FKConstraintTableSchema VARCHAR(255),
FKConstraintTableName VARCHAR(255),
FKConstraintColumnName VARCHAR(255),
PKConstraintName VARCHAR(255),
PKConstraintTableSchema VARCHAR(255),
PKConstraintTableName VARCHAR(255),
PKConstraintColumnName VARCHAR(255)
)
INSERT INTO @temptable(FKConstraintName, FKConstraintTableSchema, FKConstraintTableName, FKConstraintColumnName)
SELECT
KeyColumnUsage.CONSTRAINT_NAME,
KeyColumnUsage.TABLE_SCHEMA,
KeyColumnUsage.TABLE_NAME,
KeyColumnUsage.COLUMN_NAME
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
ON KeyColumnUsage.CONSTRAINT_NAME = TableConstraints.CONSTRAINT_NAME
WHERE
TableConstraints.CONSTRAINT_TYPE = 'FOREIGN KEY'
UPDATE @temptable SET
PKConstraintName = UNIQUE_CONSTRAINT_NAME
FROM
@temptable tt
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ReferentialConstraint
ON tt.FKConstraintName = ReferentialConstraint.CONSTRAINT_NAME
UPDATE @temptable SET
PKConstraintTableSchema = TABLE_SCHEMA,
PKConstraintTableName = TABLE_NAME
FROM @temptable tt
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
ON tt.PKConstraintName = TableConstraints.CONSTRAINT_NAME
UPDATE @temptable SET
PKConstraintColumnName = COLUMN_NAME
FROM @temptable tt
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
ON tt.PKConstraintName = KeyColumnUsage.CONSTRAINT_NAME
--Now to drop constraint:
SELECT
'
ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + ']
DROP CONSTRAINT ' + FKConstraintName + '
GO'
FROM
@temptable
--Finally to add constraint:
SELECT
'
ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + ']
ADD CONSTRAINT ' + FKConstraintName + ' FOREIGN KEY(' + FKConstraintColumnName + ') REFERENCES [' + PKConstraintTableSchema + '].[' + PKConstraintTableName + '](' + PKConstraintColumnName + ')
GO'
FROM
@temptable
GO
Désactiver toutes les contraintes de table
ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName
- Activer toutes les contraintes de table
ALTER TABLE TableName CHECK CONSTRAINT ConstraintName
Tronquer la table ne sera pas possible même si vous désactivez les clés étrangères.Vous pouvez également utiliser la commande Delete pour supprimer tous les enregistrements de la table, mais sachez que vous utilisez la commande delete Pour une table composée de des millions d’enregistrements, votre paquet sera lent .__ et la taille de votre journal des transactions augmentera, ce qui risque de saturer votre précieux espace disque.
Si vous supprimez les contraintes, il se peut que vous remplissiez votre table avec des données impures Si vous essayez de les recréer, elles risquent de ne pas vous permettre, car cela vous donnera des erreurs . Alors assurez-vous Supprimez les contraintes, vous chargez des données qui sont correctement liées les unes aux autres et satisfont les relations de contrainte que vous allez recréer.
alors réfléchissez bien aux avantages et inconvénients de chaque méthode et utilisez-la selon vos besoins.
pas besoin d'exécuter des requêtes à FK sidable sur SQL. Si vous avez un FK des tables A à B, vous devriez:
Vous pouvez également dire à la destination de ne pas vérifier les contraintes
Si vous utilisez un schéma de base de données différent de ".dbo" ou si votre base contient des Pk, composés de plusieurs champs, veuillez ne pas utiliser la solution de Carter Medlin, sinon vous endommageriez votre base !!!
Lorsque vous travaillez avec différents schémas, essayez ceci (n’oubliez pas de faire une sauvegarde de votre base de données auparavant!):
DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+ '['+ t.[name] + '] DISABLE;'+CHAR(13)
from
sys.tables t
where type='u'
select @sql = @sql +
'ALTER INDEX ' + i.[name] + ' ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.key_constraints i
join
sys.tables t on i.parent_object_id=t.object_id
where i.type='PK'
exec dbo.sp_executesql @sql;
go
Après avoir effectué certaines actions sans Fk, vous pouvez revenir en arrière avec
DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.tables t
where type='u'
print @sql
exec dbo.sp_executesql @sql;
exec sp_msforeachtable "ALTER TABLE ? WITH NOCHECK CHECK CONSTRAINT ALL";