Impossible de tronquer la table car elle est référencée par une contrainte FOREIGN KEY?


459

À l'aide de MSSQL2005, puis-je tronquer une table avec une contrainte de clé étrangère si je tronque d'abord la table enfant (la table avec la clé primaire de la relation FK)?

Je sais que je peux

  • Utiliser un DELETE clause sans une où, puis RESEEDl'identité (ou)
  • Retirez le FK, tronquez la table et recréez le FK.

Je pensais que tant que je tronquerais la table enfant avant le parent, je serais d'accord sans faire l'une des options ci-dessus, mais j'obtiens cette erreur:

Impossible de tronquer la table 'TableName' car elle est référencée par une contrainte FOREIGN KEY.

Réponses:


379

Correct; vous ne pouvez pas tronquer une table qui a une contrainte FK dessus.

En règle générale, mon processus est le suivant:

  1. Supprimer les contraintes
  2. Trunc la table
  3. Recréez les contraintes.

(Le tout dans une transaction, bien sûr.)

Bien sûr, cela ne s'applique que si l' enfant a déjà été tronqué. Sinon, je choisis un itinéraire différent, entièrement dépendant de l'apparence de mes données. (Trop de variables pour entrer ici.)

L'affiche originale a déterminé POURQUOI c'est le cas; voir cette réponse pour plus de détails.


73
Un "DELETE FROM" ne réinitialise pas les colonnes à incrémentation automatique. Un tronqué le fait. Ils ne sont pas fonctionnellement équivalents.
robross0606

35
Tronquer est souvent exactement ce que vous voulez faire si vous supprimez d'énormes quantités de données. Tronquer un million de lignes? Un milliard? 1 ms ... donc, @ M07, veuillez ne pas dire "supprimer de l'approche est plus propre", car ce n'est tout simplement pas précis à distance.
ctb

1
Après avoir supprimé des données volumineuses, l'utilisateur doit également réduire les tables et les fichiers journaux pour récupérer l'espace disque.
Muhammad Yousaf Sulahria du

2
Le bouton (ou script) Magic Shrink n'est pas conseillé dans 99% des cas.
Tom Stickel

1
Et comment feriez-vous cela? Exemples de demandes?
jeromej

357
DELETE FROM TABLENAME
DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME',RESEED, 0)

Notez que ce n'est probablement pas ce que vous voudriez si vous avez des millions + d'enregistrements, car c'est très lent.


C'était utile, plus rapide que de désactiver et d'activer la contrainte.
sensei

Cela ne fonctionnera que pour les tables avec moins de données. D'accord avec @Pure
Dhanuka777

1
C'est génial lorsque vous avez terminé de tester un schéma
ohmusama

3
Je ne suggérerais pas de suivre cette voie, car vous pourriez également obtenir cette erreur: l'instruction DELETE est en conflit avec la contrainte REFERENCE
sksallaj

N'a pas travaillé pour moi. Toujours obtenir L'instruction DELETE est en conflit avec la contrainte REFERENCE.
emirhosseini

192

Étant donné qu'il TRUNCATE TABLEs'agit d'une commande DDL , il ne peut pas vérifier si les enregistrements de la table sont référencés par un enregistrement de la table enfant.

C'est pourquoi cela DELETEfonctionne et TRUNCATE TABLEne fonctionne pas: car la base de données est en mesure de s'assurer qu'elle n'est pas référencée par un autre enregistrement.


92

Sans pour autant ALTER TABLE

-- Delete all records
DELETE FROM [TableName]
-- Set current ID to "1"
-- If table already contains data, use "0"
-- If table is empty and never insert data, use "1"
-- Use SP https://github.com/reduardo7/TableTruncate
DBCC CHECKIDENT ([TableName], RESEED, 0)

En tant que procédure stockée

https://github.com/reduardo7/TableTruncate

Notez que ce n'est probablement pas ce que vous voudriez si vous avez des millions + d'enregistrements, car c'est très lent.


3
en utilisant reseed nouvelle valeur = 1 après DELETE FROM démarrerait tout à partir de l'ID 2, au lieu de 1. From Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) Si aucune ligne n'a été inséré dans la table depuis sa création ou toutes les lignes ont été supprimées à l'aide de l'instruction TRUNCATE TABLE, la première ligne insérée après avoir exécuté DBCC CHECKIDENT utilise new_reseed_value comme identité. Sinon, la ligne suivante insérée utilise new_reseed_value + la valeur d'incrément actuelle.
Zoran P.

@ZoranP. veuillez voir la variante de procédure stockée: github.com/reduardo7/TableTruncate
Eduardo Cuomo

4
DBCC CHECKIDENT ([TableName], RESEED, 0) not 1
Tico Fortes

1
@TicoFortes Post mis à jour. Veuillez voir la variante de procédure stockée
Eduardo Cuomo

1
Ce n'est pas une bonne approche. Comme l'ont commenté les 700 autres versions de cette même réponse à cette question. À MOINS que votre base de données ne soit en mode de récupération simple, pour limiter la journalisation des transactions.
pimbrouwers

68

La solution @denver_citizen fournie ci-dessus n'a pas fonctionné pour moi, mais j'ai aimé l'esprit de celle-ci, j'ai donc modifié quelques éléments:

  • en a fait une procédure stockée
  • changé la façon dont les clés étrangères sont remplies et recréées
  • le script d'origine tronque toutes les tables référencées, cela peut provoquer une erreur de violation de clé étrangère lorsque la table référencée a d'autres références de clé étrangère. Ce script tronque uniquement la table spécifiée en tant que paramètre. Il appartient à l'utilisateur d'appeler cette procédure stockée plusieurs fois sur toutes les tables dans le bon ordre.

Pour le bénéfice du public, voici le script mis à jour:

CREATE PROCEDURE [dbo].[truncate_non_empty_table]

  @TableToTruncate                 VARCHAR(64)

AS 

BEGIN

SET NOCOUNT ON

-- GLOBAL VARIABLES
DECLARE @i int
DECLARE @Debug bit
DECLARE @Recycle bit
DECLARE @Verbose bit
DECLARE @TableName varchar(80)
DECLARE @ColumnName varchar(80)
DECLARE @ReferencedTableName varchar(80)
DECLARE @ReferencedColumnName varchar(80)
DECLARE @ConstraintName varchar(250)

DECLARE @CreateStatement varchar(max)
DECLARE @DropStatement varchar(max)   
DECLARE @TruncateStatement varchar(max)
DECLARE @CreateStatementTemp varchar(max)
DECLARE @DropStatementTemp varchar(max)
DECLARE @TruncateStatementTemp varchar(max)
DECLARE @Statement varchar(max)

        -- 1 = Will not execute statements 
 SET @Debug = 0
        -- 0 = Will not create or truncate storage table
        -- 1 = Will create or truncate storage table
 SET @Recycle = 0
        -- 1 = Will print a message on every step
 set @Verbose = 1

 SET @i = 1
    SET @CreateStatement = 'ALTER TABLE [dbo].[<tablename>]  WITH NOCHECK ADD  CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])'
    SET @DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]'
    SET @TruncateStatement = 'TRUNCATE TABLE [<tablename>]'

-- Drop Temporary tables

IF OBJECT_ID('tempdb..#FKs') IS NOT NULL
    DROP TABLE #FKs

-- GET FKs
SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID,
       OBJECT_NAME(constraint_object_id) as ConstraintName,
       OBJECT_NAME(parent_object_id) as TableName,
       clm1.name as ColumnName, 
       OBJECT_NAME(referenced_object_id) as ReferencedTableName,
       clm2.name as ReferencedColumnName
  INTO #FKs
  FROM sys.foreign_key_columns fk
       JOIN sys.columns clm1 
         ON fk.parent_column_id = clm1.column_id 
            AND fk.parent_object_id = clm1.object_id
       JOIN sys.columns clm2
         ON fk.referenced_column_id = clm2.column_id 
            AND fk.referenced_object_id= clm2.object_id
 --WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated')
 WHERE OBJECT_NAME(referenced_object_id) = @TableToTruncate
 ORDER BY OBJECT_NAME(parent_object_id)


-- Prepare Storage Table
IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage')
   BEGIN
        IF @Verbose = 1
     PRINT '1. Creating Process Specific Tables...'

  -- CREATE STORAGE TABLE IF IT DOES NOT EXISTS
  CREATE TABLE [Internal_FK_Definition_Storage] 
  (
   ID int not null identity(1,1) primary key,
   FK_Name varchar(250) not null,
   FK_CreationStatement varchar(max) not null,
   FK_DestructionStatement varchar(max) not null,
   Table_TruncationStatement varchar(max) not null
  ) 
   END 
ELSE
   BEGIN
        IF @Recycle = 0
            BEGIN
                IF @Verbose = 1
       PRINT '1. Truncating Process Specific Tables...'

    -- TRUNCATE TABLE IF IT ALREADY EXISTS
    TRUNCATE TABLE [Internal_FK_Definition_Storage]    
      END
      ELSE
         PRINT '1. Process specific table will be recycled from previous execution...'
   END


IF @Recycle = 0
   BEGIN

  IF @Verbose = 1
     PRINT '2. Backing up Foreign Key Definitions...'

  -- Fetch and persist FKs             
  WHILE (@i <= (SELECT MAX(ID) FROM #FKs))
   BEGIN
    SET @ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = @i)
    SET @TableName = (SELECT TableName FROM #FKs WHERE ID = @i)
    SET @ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = @i)
    SET @ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = @i)
    SET @ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = @i)

    SET @DropStatementTemp = REPLACE(REPLACE(@DropStatement,'<tablename>',@TableName),'<constraintname>',@ConstraintName)
    SET @CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@CreateStatement,'<tablename>',@TableName),'<column>',@ColumnName),'<constraintname>',@ConstraintName),'<reftable>',@ReferencedTableName),'<refcolumn>',@ReferencedColumnName)
    SET @TruncateStatementTemp = REPLACE(@TruncateStatement,'<tablename>',@TableName) 

    INSERT INTO [Internal_FK_Definition_Storage]
                        SELECT @ConstraintName, @CreateStatementTemp, @DropStatementTemp, @TruncateStatementTemp

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Backing up [' + @ConstraintName + '] from [' + @TableName + ']'

    END   
    END   
    ELSE 
       PRINT '2. Backup up was recycled from previous execution...'

       IF @Verbose = 1
     PRINT '3. Dropping Foreign Keys...'

    -- DROP FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1


    IF @Verbose = 1
       PRINT '  > Dropping [' + @ConstraintName + ']'

             END     


    IF @Verbose = 1
       PRINT '4. Truncating Tables...'

    -- TRUNCATE TABLES
-- SzP: commented out as the tables to be truncated might also contain tables that has foreign keys
-- to resolve this the stored procedure should be called recursively, but I dont have the time to do it...          
 /*
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN

    SET @Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > ' + @Statement
          END
*/          


    IF @Verbose = 1
       PRINT '  > TRUNCATE TABLE [' + @TableToTruncate + ']'

    IF @Debug = 1 
        PRINT 'TRUNCATE TABLE [' + @TableToTruncate + ']'
    ELSE
        EXEC('TRUNCATE TABLE [' + @TableToTruncate + ']')


    IF @Verbose = 1
       PRINT '5. Re-creating Foreign Keys...'

    -- CREATE FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1


    IF @Verbose = 1
       PRINT '  > Re-creating [' + @ConstraintName + ']'

          END

    IF @Verbose = 1
       PRINT '6. Process Completed'


END

11
Cette réponse mérite plus de votes! En fait, je serais ravi de vous acheter une bière si je le pouvais, Peter :)
nsimeonov

Cela m'a été d'une grande aide aujourd'hui pour effacer rapidement certains grands tableaux de leurs données pour les tests, merci pour le travail de qualité sur ce point.
Craig Selbert

4
Merci pour ce morceau de code. Mais attention, vous devez ajouter une logique supplémentaire pour vérifier les FK désactivés. Sinon, vous activerez les contraintes actuellement désactivées.
Andre Figueiredo

2
J'ai fait une version avec les suggestions de @AndreFigueiredo. Je le mets sur Gitlab: gitlab.com/ranolfi/truncate-referenced-table . N'hésitez pas à incorporer le code à votre réponse.
Marc.2377

1
C'est très bien, mais notez que cela ne fonctionnera pas si vos tables ne sont pas dans le schéma par défaut (dbo).
Sidewinder94

19

utilisez la commande suivante après la suppression de toutes les lignes de cette table à l'aide de l'instruction delete

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

EDIT: syntaxe corrigée pour SQL Server


9
TRUNCATEévite le journal et est considérablement plus rapide que DELETEpour les grandes tables. En tant que tel, ce n'est pas une véritable solution équivalente.
siride

1
En quoi cette réponse est-elle différente de celle qui a été donnée un an auparavant?
Ofer Zelig

17

Eh bien, puisque je n'ai pas trouvé d' exemples de la solution très simple que j'ai utilisée, qui est:

  1. Déposer la clé étrangère;
  2. Tronquer la table
  3. Recréer une clé étrangère

Ça y est:

1) Trouvez le nom de la clé étrangère qui est à l'origine de l'échec (par exemple: FK_PROBLEM_REASON, avec champ ID, de la table TABLE_OWNING_CONSTRAINT) 2) Supprimez cette clé de la table:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Tronquer la table souhaitée

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Ajoutez de nouveau la clé à cette première table:

ALTER TABLE TABLE_OWNING_CONSTRAINT ADD CONSTRAINT FK_PROBLEM_REASON FOREIGN KEY(ID) REFERENCES TABLE_TO_TRUNCATE (ID)

C'est ça.


Cela ne fonctionne pas si vous avez plusieurs tables avec des références de clé étrangère. Vous devrez supprimer un grand nombre de restrictions de clés étrangères dans toute la base de données.
jbright

13

Voici un script que j'ai écrit afin d'automatiser le processus. J'espère que ça aide.

SET NOCOUNT ON

-- GLOBAL VARIABLES
DECLARE @i int
DECLARE @Debug bit
DECLARE @Recycle bit
DECLARE @Verbose bit
DECLARE @TableName varchar(80)
DECLARE @ColumnName varchar(80)
DECLARE @ReferencedTableName varchar(80)
DECLARE @ReferencedColumnName varchar(80)
DECLARE @ConstraintName varchar(250)

DECLARE @CreateStatement varchar(max)
DECLARE @DropStatement varchar(max)   
DECLARE @TruncateStatement varchar(max)
DECLARE @CreateStatementTemp varchar(max)
DECLARE @DropStatementTemp varchar(max)
DECLARE @TruncateStatementTemp varchar(max)
DECLARE @Statement varchar(max)

        -- 1 = Will not execute statements 
 SET @Debug = 0
        -- 0 = Will not create or truncate storage table
        -- 1 = Will create or truncate storage table
 SET @Recycle = 0
        -- 1 = Will print a message on every step
 set @Verbose = 1

 SET @i = 1
    SET @CreateStatement = 'ALTER TABLE [dbo].[<tablename>]  WITH NOCHECK ADD  CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])'
    SET @DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]'
    SET @TruncateStatement = 'TRUNCATE TABLE [<tablename>]'

-- Drop Temporary tables
DROP TABLE #FKs

-- GET FKs
SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID,
       OBJECT_NAME(constraint_object_id) as ConstraintName,
       OBJECT_NAME(parent_object_id) as TableName,
       clm1.name as ColumnName, 
       OBJECT_NAME(referenced_object_id) as ReferencedTableName,
       clm2.name as ReferencedColumnName
  INTO #FKs
  FROM sys.foreign_key_columns fk
       JOIN sys.columns clm1 
         ON fk.parent_column_id = clm1.column_id 
            AND fk.parent_object_id = clm1.object_id
       JOIN sys.columns clm2
         ON fk.referenced_column_id = clm2.column_id 
            AND fk.referenced_object_id= clm2.object_id
 WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated')
 ORDER BY OBJECT_NAME(parent_object_id)


-- Prepare Storage Table
IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage')
   BEGIN
        IF @Verbose = 1
     PRINT '1. Creating Process Specific Tables...'

  -- CREATE STORAGE TABLE IF IT DOES NOT EXISTS
  CREATE TABLE [Internal_FK_Definition_Storage] 
  (
   ID int not null identity(1,1) primary key,
   FK_Name varchar(250) not null,
   FK_CreationStatement varchar(max) not null,
   FK_DestructionStatement varchar(max) not null,
   Table_TruncationStatement varchar(max) not null
  ) 
   END 
ELSE
   BEGIN
        IF @Recycle = 0
            BEGIN
                IF @Verbose = 1
       PRINT '1. Truncating Process Specific Tables...'

    -- TRUNCATE TABLE IF IT ALREADY EXISTS
    TRUNCATE TABLE [Internal_FK_Definition_Storage]    
      END
      ELSE
         PRINT '1. Process specific table will be recycled from previous execution...'
   END

IF @Recycle = 0
   BEGIN

  IF @Verbose = 1
     PRINT '2. Backing up Foreign Key Definitions...'

  -- Fetch and persist FKs             
  WHILE (@i <= (SELECT MAX(ID) FROM #FKs))
   BEGIN
    SET @ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = @i)
    SET @TableName = (SELECT TableName FROM #FKs WHERE ID = @i)
    SET @ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = @i)
    SET @ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = @i)
    SET @ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = @i)

    SET @DropStatementTemp = REPLACE(REPLACE(@DropStatement,'<tablename>',@TableName),'<constraintname>',@ConstraintName)
    SET @CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@CreateStatement,'<tablename>',@TableName),'<column>',@ColumnName),'<constraintname>',@ConstraintName),'<reftable>',@ReferencedTableName),'<refcolumn>',@ReferencedColumnName)
    SET @TruncateStatementTemp = REPLACE(@TruncateStatement,'<tablename>',@TableName) 

    INSERT INTO [Internal_FK_Definition_Storage]
                        SELECT @ConstraintName, @CreateStatementTemp, @DropStatementTemp, @TruncateStatementTemp

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Backing up [' + @ConstraintName + '] from [' + @TableName + ']'

   END
    END   
    ELSE 
       PRINT '2. Backup up was recycled from previous execution...'

       IF @Verbose = 1
     PRINT '3. Dropping Foreign Keys...'

    -- DROP FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Dropping [' + @ConstraintName + ']'
             END     

    IF @Verbose = 1
       PRINT '4. Truncating Tables...'

    -- TRUNCATE TABLES
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
    SET @Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > ' + @Statement
          END

    IF @Verbose = 1
       PRINT '5. Re-creating Foreign Keys...'

    -- CREATE FOREING KEYS
    SET @i = 1
    WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
          BEGIN
             SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i)
    SET @Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i)

    IF @Debug = 1 
       PRINT @Statement
    ELSE
       EXEC(@Statement)

    SET @i = @i + 1

    IF @Verbose = 1
       PRINT '  > Re-creating [' + @ConstraintName + ']'
          END

    IF @Verbose = 1
       PRINT '6. Process Completed'

2
Faites attention. J'ajouterais également des actions référentielles sur les clés de votre script ou vous perdrez les paramètres de cascade.
alphadogg

1
cela ne fonctionne pas pour moi, mais j'aimais l'esprit de celui-ci, j'ai donc modifié quelques choses: en a fait une procédure stockée a changé la façon dont les clés étrangères sont remplies et recréé le script d'origine tronque toutes les tables référencées, cela peut être faux lorsque le référencé La table ne peut pas être tronquée car elle contient également des références de clé étrangère. Dans cette version, seule la table spécifiée en tant que paramètre sera tronquée, toutes les tables référencées doivent être tronquées manuellement avant d'appeler ce script J'ai posté la résolution mise à jour sur ce fil ici stackoverflow.com/a/13249209/157591
Peter Szanto

1
@alphadogg Existe-t-il un moyen de trouver ces actions référentielles? J'ai fouillé sur Internet et je n'arrive pas à les trouver. Je peux le poster comme une question formelle, si vous préférez.
Michael - Où est Clay Shirky

1
Note aux futurs visiteurs: c'est dans le sys.foreign_keystableau. ( Référence )
Michael - Où est Clay Shirky

@Michael: Vous pouvez également utiliser INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg

13

vous pouvez suivre cette étape, en reseeding tablesupprimant les données de la table.

delete from table_name
dbcc checkident('table_name',reseed,0)

si une erreur survient, vous devez réamorcer la table principale.


1
Gardez à l'esprit que même si cela fonctionne bien, le journal des transactions augmentera du nombre d'enregistrements dans la table par rapport à la «table tronquée», ce qui ne mettra qu'un seul enregistrement dans le journal des transactions. Ce n'est pas grave pour la plupart des tables, mais s'il y a des millions de lignes +, cela pourrait être un problème.
David

9
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;

8
Cette question concerne MS SQL Server, qui n'a pas de paramètre
FOREIGN_KEY_CHECKS

1
Je pense que cela fonctionnerait à partir de MySQL, mais pas de MS SQL Server
Cocowalla

8

Si je comprends bien, ce que vous voulez faire est d'avoir un environnement propre à configurer pour la base de données impliquant des tests d'intégration.

Mon approche ici serait de supprimer tout le schéma et de le recréer plus tard.

Les raisons:

  1. Vous avez probablement déjà un script "créer un schéma". La réutiliser pour tester l'isolement est facile.
  2. La création d'un schéma est assez rapide.
  3. Avec cette approche, il est assez facile de configurer votre script pour que chaque appareil crée un NOUVEAU schéma (avec un nom temporaire), puis vous pouvez commencer à exécuter des appareils de test en parallèle, ce qui rend la partie la plus lente de votre suite de tests beaucoup plus rapide. .

1
Je voudrais «tronquer» tout le schéma, pas le laisser tomber. Je voudrais le faire dans la méthode d'installation des tests d'intégration. Appeler le script de création de base de données à partir de tests d'intégration n'est ... pas la première solution à laquelle j'irai.
ripper234

7

Trouvé ailleurs sur le web

EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'
-- EXEC sp_MSForEachTable 'DELETE FROM ?' -- Uncomment to execute
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL'

3
Devrait probablement être «ALTER TABLE? AVEC CHECK CHECK CONTRAINT ALL '.
Andriy M,

20
-1: Je viens de confirmer que cela ne fonctionne pas du tout avec la commande tronquer comme demandé par la question. Voir stackoverflow.com/questions/3843806/…
Lynn Crumbling

7

Vous ne pouvez pas tronquer une table si vous ne supprimez pas les contraintes. Une désactivation ne fonctionne pas non plus. vous devez tout laisser tomber. j'ai fait un script qui supprime toutes les contraintes et recrée ensuite.

Assurez-vous de l'envelopper dans une transaction;)

SET NOCOUNT ON
GO

DECLARE @table TABLE(
RowId INT PRIMARY KEY IDENTITY(1, 1),
ForeignKeyConstraintName NVARCHAR(200),
ForeignKeyConstraintTableSchema NVARCHAR(200),
ForeignKeyConstraintTableName NVARCHAR(200),
ForeignKeyConstraintColumnName NVARCHAR(200),
PrimaryKeyConstraintName NVARCHAR(200),
PrimaryKeyConstraintTableSchema NVARCHAR(200),
PrimaryKeyConstraintTableName NVARCHAR(200),
PrimaryKeyConstraintColumnName NVARCHAR(200)
)

INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT
U.CONSTRAINT_NAME,
U.TABLE_SCHEMA,
U.TABLE_NAME,
U.COLUMN_NAME
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
C.CONSTRAINT_TYPE = 'FOREIGN KEY'

UPDATE @table SET
PrimaryKeyConstraintName = UNIQUE_CONSTRAINT_NAME
FROM
@table T
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME

UPDATE @table SET
PrimaryKeyConstraintTableSchema = TABLE_SCHEMA,
PrimaryKeyConstraintTableName = TABLE_NAME
FROM @table T
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME

UPDATE @table SET
PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM @table T
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME

--DROP CONSTRAINT:

DECLARE @dynSQL varchar(MAX);

DECLARE cur CURSOR FOR
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
DROP CONSTRAINT ' + ForeignKeyConstraintName + '
'
FROM
@table

OPEN cur

FETCH cur into @dynSQL
WHILE @@FETCH_STATUS = 0 
BEGIN
    exec(@dynSQL)
    print @dynSQL

    FETCH cur into @dynSQL
END
CLOSE cur
DEALLOCATE cur
---------------------



   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!

    truncate table your_table

   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!
   --HERE GOES YOUR TRUNCATES!!!!!

---------------------
--ADD CONSTRAINT:

DECLARE cur2 CURSOR FOR
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ')
'
FROM
@table

OPEN cur2

FETCH cur2 into @dynSQL
WHILE @@FETCH_STATUS = 0 
BEGIN
    exec(@dynSQL)

    print @dynSQL

    FETCH cur2 into @dynSQL
END
CLOSE cur2
DEALLOCATE cur2

6

Les réponses de @denver_citizen et @Peter Szanto n'ont pas vraiment fonctionné pour moi, mais je les ai modifiées pour tenir compte:

  1. Clés composites
  2. Actions de suppression et de mise à jour
  3. Vérification de l'index lors de l'ajout
  4. Schémas autres que dbo
  5. Plusieurs tables à la fois
DECLARE @Debug bit = 0;

-- List of tables to truncate
select
    SchemaName, Name
into #tables
from (values 
    ('schema', 'table')
    ,('schema2', 'table2')
) as X(SchemaName, Name)


BEGIN TRANSACTION TruncateTrans;

with foreignKeys AS (
     SELECT 
        SCHEMA_NAME(fk.schema_id) as SchemaName
        ,fk.Name as ConstraintName
        ,OBJECT_NAME(fk.parent_object_id) as TableName
        ,SCHEMA_NAME(t.SCHEMA_ID) as ReferencedSchemaName
        ,OBJECT_NAME(fk.referenced_object_id) as ReferencedTableName
        ,fc.constraint_column_id
        ,COL_NAME(fk.parent_object_id, fc.parent_column_id) AS ColumnName
        ,COL_NAME(fk.referenced_object_id, fc.referenced_column_id) as ReferencedColumnName
        ,fk.delete_referential_action_desc
        ,fk.update_referential_action_desc
    FROM sys.foreign_keys AS fk
        JOIN sys.foreign_key_columns AS fc
            ON fk.object_id = fc.constraint_object_id
        JOIN #tables tbl 
            ON OBJECT_NAME(fc.referenced_object_id) = tbl.Name
        JOIN sys.tables t on OBJECT_NAME(t.object_id) = tbl.Name 
            and SCHEMA_NAME(t.schema_id) = tbl.SchemaName
            and t.OBJECT_ID = fc.referenced_object_id
)



select
    quotename(fk.ConstraintName) AS ConstraintName
    ,quotename(fk.SchemaName) + '.' + quotename(fk.TableName) AS TableName
    ,quotename(fk.ReferencedSchemaName) + '.' + quotename(fk.ReferencedTableName) AS ReferencedTableName
    ,replace(fk.delete_referential_action_desc, '_', ' ') AS DeleteAction
    ,replace(fk.update_referential_action_desc, '_', ' ') AS UpdateAction
    ,STUFF((
        SELECT ',' + quotename(fk2.ColumnName)
        FROM foreignKeys fk2 
        WHERE fk2.ConstraintName = fk.ConstraintName and fk2.SchemaName = fk.SchemaName
        ORDER BY fk2.constraint_column_id
        FOR XML PATH('')
    ),1,1,'') AS ColumnNames
    ,STUFF((
        SELECT ',' + quotename(fk2.ReferencedColumnName)
        FROM foreignKeys fk2 
        WHERE fk2.ConstraintName = fk.ConstraintName and fk2.SchemaName = fk.SchemaName
        ORDER BY fk2.constraint_column_id
        FOR XML PATH('')
    ),1,1,'') AS ReferencedColumnNames
into #FKs
from foreignKeys fk
GROUP BY fk.SchemaName, fk.ConstraintName, fk.TableName, fk.ReferencedSchemaName, fk.ReferencedTableName, fk.delete_referential_action_desc, fk.update_referential_action_desc



-- Drop FKs
select 
    identity(int,1,1) as ID,
    'ALTER TABLE ' + fk.TableName + ' DROP CONSTRAINT ' + fk.ConstraintName AS script
into #scripts
from #FKs fk

-- Truncate 
insert into #scripts
select distinct 
    'TRUNCATE TABLE ' + quotename(tbl.SchemaName) + '.' + quotename(tbl.Name) AS script
from #tables tbl

-- Recreate
insert into #scripts
select 
    'ALTER TABLE ' + fk.TableName + 
    ' WITH CHECK ADD CONSTRAINT ' + fk.ConstraintName + 
    ' FOREIGN KEY ('+ fk.ColumnNames +')' + 
    ' REFERENCES ' + fk.ReferencedTableName +' ('+ fk.ReferencedColumnNames +')' +
    ' ON DELETE ' + fk.DeleteAction COLLATE Latin1_General_CI_AS_KS_WS + ' ON UPDATE ' + fk.UpdateAction COLLATE Latin1_General_CI_AS_KS_WS AS script
from #FKs fk


DECLARE @script nvarchar(MAX);

DECLARE curScripts CURSOR FOR 
    select script
    from #scripts
    order by ID

OPEN curScripts

WHILE 1=1 BEGIN
    FETCH NEXT FROM curScripts INTO @script
    IF @@FETCH_STATUS != 0 BREAK;

    print @script;
    IF @Debug = 0
        EXEC (@script);
END
CLOSE curScripts
DEALLOCATE curScripts


drop table #scripts
drop table #FKs
drop table #tables


COMMIT TRANSACTION TruncateTrans;

4

tronquer n'a pas fonctionné pour moi, supprimer + réamorcer est la meilleure solution. Dans le cas où certains d'entre vous auraient besoin d'itérer sur un grand nombre de tables pour effectuer la suppression + le réamorçage, vous pourriez rencontrer des problèmes avec certaines tables qui n'ont pas de colonne d'identité, le code suivant vérifie si la colonne d'identité existe avant d'essayer réensemencer

    EXEC ('DELETE FROM [schemaName].[tableName]')
    IF EXISTS (Select * from sys.identity_columns where object_name(object_id) = 'tableName')
    BEGIN
        EXEC ('DBCC CHECKIDENT ([schemaName.tableName], RESEED, 0)')
    END

4

J'écris les façons suivantes et j'ai essayé de les paramétrer, afin que vous puissiez les exécuter dans un Query documentou en faire un utilitaire SPfacilement avec eux .

A) Supprimer

Si votre table n'a pas des millions d'enregistrements, cela fonctionne bien et n'a pas de commandes Alter :

---------------------------------------------------------------
------------------- Just Fill Parameters Value ----------------
---------------------------------------------------------------
DECLARE @DbName AS NVARCHAR(30) = 'MyDb'         --< Db Name
DECLARE @Schema AS NVARCHAR(30) = 'dbo'          --< Schema
DECLARE @TableName AS NVARCHAR(30) = 'Book'      --< Table Name
------------------ /Just Fill Parameters Value ----------------

DECLARE @Query AS NVARCHAR(500) = 'Delete FROM ' + @TableName

EXECUTE sp_executesql @Query
SET @Query=@DbName+'.'+@Schema+'.'+@TableName
DBCC CHECKIDENT (@Query,RESEED, 0)
  • Dans ma réponse ci-dessus, la méthode de résolution du problème mentionné dans la question est basée sur la réponse @ s15199d .

B) Tronquer

Si votre table a des millions d'enregistrements ou si vous n'avez aucun problème avec la commande Alter dans vos codes, utilisez celui-ci:

--   Book                               Student
--
--   |  BookId  | Field1 |              | StudentId |  BookId  |
--   ---------------------              ------------------------ 
--   |    1     |    A   |              |     2     |    1     |  
--   |    2     |    B   |              |     1     |    1     |
--   |    3     |    C   |              |     2     |    3     |  

---------------------------------------------------------------
------------------- Just Fill Parameters Value ----------------
---------------------------------------------------------------
DECLARE @DbName AS NVARCHAR(30) = 'MyDb'
DECLARE @Schema AS NVARCHAR(30) = 'dbo'
DECLARE @TableName_ToTruncate AS NVARCHAR(30) = 'Book'

DECLARE @TableName_OfOwnerOfConstraint AS NVARCHAR(30) = 'Student' --< Decelations About FK_Book_Constraint
DECLARE @Ref_ColumnName_In_TableName_ToTruncate AS NVARCHAR(30) = 'BookId' --< Decelations About FK_Book_Constraint
DECLARE @FK_ColumnName_In_TableOfOwnerOfConstraint AS NVARCHAR(30) = 'Fk_BookId' --< Decelations About FK_Book_Constraint
DECLARE @FK_ConstraintName AS NVARCHAR(30) = 'FK_Book_Constraint'                --< Decelations About FK_Book_Constraint
------------------ /Just Fill Parameters Value ----------------

DECLARE @Query AS NVARCHAR(2000)

SET @Query= 'ALTER TABLE '+@TableName_OfOwnerOfConstraint+' DROP CONSTRAINT '+@FK_ConstraintName
EXECUTE sp_executesql @Query

SET @Query= 'Truncate Table '+ @TableName_ToTruncate
EXECUTE sp_executesql @Query

SET @Query= 'ALTER TABLE '+@TableName_OfOwnerOfConstraint+' ADD CONSTRAINT '+@FK_ConstraintName+' FOREIGN KEY('+@FK_ColumnName_In_TableOfOwnerOfConstraint+') REFERENCES '+@TableName_ToTruncate+'('+@Ref_ColumnName_In_TableName_ToTruncate+')'
EXECUTE sp_executesql @Query
  • Dans ma réponse ci-dessus, la méthode de résolution du problème mentionné dans la question est basée sur la réponse @LauroWolffValenteSobrinho .

  • Si vous avez plusieurs CONTRAINTES, vous devez ajouter ses codes comme moi à la requête ci-dessus

  • Vous pouvez également modifier la base de code ci - dessus @SerjSagan réponse à désactiver une contrainte activer la


3

C'est ma solution à ce problème. Je l'ai utilisé pour modifier PK, mais je pense la même chose. J'espère que cela vous sera utile)

PRINT 'Script starts'

DECLARE @foreign_key_name varchar(255)
DECLARE @keycnt int
DECLARE @foreign_table varchar(255)
DECLARE @foreign_column_1 varchar(255)
DECLARE @foreign_column_2 varchar(255)
DECLARE @primary_table varchar(255)
DECLARE @primary_column_1 varchar(255)
DECLARE @primary_column_2 varchar(255)
DECLARE @TablN varchar(255)

-->> Type the primary table name
SET @TablN = ''
---------------------------------------------------------------------------------------    ------------------------------
--Here will be created the temporary table with all reference FKs
---------------------------------------------------------------------------------------------------------------------
PRINT 'Creating the temporary table'
select cast(f.name  as varchar(255)) as foreign_key_name
    , r.keycnt
    , cast(c.name as  varchar(255)) as foreign_table
    , cast(fc.name as varchar(255)) as  foreign_column_1
    , cast(fc2.name as varchar(255)) as foreign_column_2
    , cast(p.name as varchar(255)) as primary_table
    , cast(rc.name as varchar(255))  as primary_column_1
    , cast(rc2.name as varchar(255)) as  primary_column_2
    into #ConTab
    from sysobjects f
    inner join sysobjects c on  f.parent_obj = c.id 
    inner join sysreferences r on f.id =  r.constid
    inner join sysobjects p on r.rkeyid = p.id
    inner  join syscolumns rc on r.rkeyid = rc.id and r.rkey1 = rc.colid
    inner  join syscolumns fc on r.fkeyid = fc.id and r.fkey1 = fc.colid
    left join  syscolumns rc2 on r.rkeyid = rc2.id and r.rkey2 = rc.colid
    left join  syscolumns fc2 on r.fkeyid = fc2.id and r.fkey2 = fc.colid
    where f.type =  'F' and p.name = @TablN
 ORDER BY cast(p.name as varchar(255))
---------------------------------------------------------------------------------------------------------------------
--Cursor, below, will drop all reference FKs
---------------------------------------------------------------------------------------------------------------------
DECLARE @CURSOR CURSOR
/*Fill in cursor*/

PRINT 'Cursor 1 starting. All refernce FK will be droped'

SET @CURSOR  = CURSOR SCROLL
FOR
select foreign_key_name
    , keycnt
    , foreign_table
    , foreign_column_1
    , foreign_column_2
    , primary_table
    , primary_column_1
    , primary_column_2
    from #ConTab

OPEN @CURSOR

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table,         @foreign_column_1, @foreign_column_2, 
                        @primary_table, @primary_column_1, @primary_column_2

WHILE @@FETCH_STATUS = 0
BEGIN

    EXEC ('ALTER TABLE ['+@foreign_table+'] DROP CONSTRAINT ['+@foreign_key_name+']')

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, 
                         @primary_table, @primary_column_1, @primary_column_2
END
CLOSE @CURSOR
PRINT 'Cursor 1 finished work'
---------------------------------------------------------------------------------------------------------------------
--Here you should provide the chainging script for the primary table
---------------------------------------------------------------------------------------------------------------------

PRINT 'Altering primary table begin'

TRUNCATE TABLE table_name

PRINT 'Altering finished'

---------------------------------------------------------------------------------------------------------------------
--Cursor, below, will add again all reference FKs
--------------------------------------------------------------------------------------------------------------------

PRINT 'Cursor 2 starting. All refernce FK will added'
SET @CURSOR  = CURSOR SCROLL
FOR
select foreign_key_name
    , keycnt
    , foreign_table
    , foreign_column_1
    , foreign_column_2
    , primary_table
    , primary_column_1
    , primary_column_2
    from #ConTab

OPEN @CURSOR

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, 
                         @primary_table, @primary_column_1, @primary_column_2

WHILE @@FETCH_STATUS = 0
BEGIN

    EXEC ('ALTER TABLE [' +@foreign_table+ '] WITH NOCHECK ADD  CONSTRAINT [' +@foreign_key_name+ '] FOREIGN KEY(['+@foreign_column_1+'])
        REFERENCES [' +@primary_table+'] (['+@primary_column_1+'])')

    EXEC ('ALTER TABLE [' +@foreign_table+ '] CHECK CONSTRAINT [' +@foreign_key_name+']')

FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, 
                         @primary_table, @primary_column_1, @primary_column_2
END
CLOSE @CURSOR
PRINT 'Cursor 2 finished work'
---------------------------------------------------------------------------------------------------------------------
PRINT 'Temporary table droping'
drop table #ConTab
PRINT 'Finish'

3

Pour MS SQL, au moins les versions les plus récentes, vous pouvez simplement désactiver les contraintes avec du code comme celui-ci:

ALTER TABLE Orders
NOCHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id]
GO

TRUNCATE TABLE Customers
GO

ALTER TABLE Orders
WITH CHECK CHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id]
GO

Je pense que nous avons établi ci-dessus que cela ne fonctionne pas? Peut-être que c'est le cas pour les versions plus récentes?
Coops

2
Fwiw, cela ne fonctionne pas dans la version de l'OP (2005), et ne fonctionne pas non plus dans son successeur (MSSQL2008).
CB

3

Ce qui suit fonctionne pour moi même avec des contraintes FK et combine les réponses suivantes pour supprimer uniquement les tables spécifiées :


USE [YourDB];

DECLARE @TransactionName varchar(20) = 'stopdropandroll';

BEGIN TRAN @TransactionName;
set xact_abort on; /* automatic rollback https://stackoverflow.com/a/1749788/1037948 */
    -- ===== DO WORK // =====

    -- dynamic sql placeholder
    DECLARE @SQL varchar(300);

    -- LOOP: https://stackoverflow.com/a/10031803/1037948
    -- list of things to loop
    DECLARE @delim char = ';';
    DECLARE @foreach varchar(MAX) = 'Table;Names;Separated;By;Delimiter' + @delim + 'AnotherName' + @delim + 'Still Another';
    DECLARE @token varchar(MAX);
    WHILE len(@foreach) > 0
    BEGIN
        -- set current loop token
        SET @token = left(@foreach, charindex(@delim, @foreach+@delim)-1)
        -- ======= DO WORK // ===========

        -- dynamic sql (parentheses are required): https://stackoverflow.com/a/989111/1037948
        SET @SQL = 'DELETE FROM [' + @token + ']; DBCC CHECKIDENT (''' + @token + ''',RESEED, 0);'; -- https://stackoverflow.com/a/11784890
        PRINT @SQL;
        EXEC (@SQL);

        -- ======= // END WORK ===========
        -- continue loop, chopping off token
        SET @foreach = stuff(@foreach, 1, charindex(@delim, @foreach+@delim), '')
    END

    -- ===== // END WORK =====
-- review and commit
SELECT @@TRANCOUNT as TransactionsPerformed, @@ROWCOUNT as LastRowsChanged;
COMMIT TRAN @TransactionName;

Remarque:

Je pense qu'il est toujours utile de déclarer les tables dans l'ordre dans lequel vous souhaitez les supprimer (c'est-à-dire tuer les dépendances en premier). Comme vu dans cette réponse , plutôt que de boucler des noms spécifiques, vous pouvez remplacer toutes les tables par

EXEC sp_MSForEachTable 'DELETE FROM ?; DBCC CHECKIDENT (''?'',RESEED, 0);';

N'a pas vraiment essayé d'autres scripts car tout le monde a déclaré qu'ils ne fonctionnent pas lorsque vous avez des clés étrangères. J'ai donc essayé celui-ci et celui-ci a fait l'affaire pour moi.
Vivendi

1
DELETE n'est pas le même que TRUNCATE. Cela remplira vos journaux de transactions.
Dan Bechard

@Dan, probablement un bon point; comme je l'ai mentionné, je viens de combiner les autres réponses ici ...
drzaus

@drzaus Cela fonctionnera bien pour les tables petites / moyennes, mais j'ai eu un serveur de production SQL hors ligne en raison d'une commande de suppression remplissant le journal des transactions, qui a rempli le disque dur. À tout le moins, assurez-vous que vos journaux de transactions ont une taille maximale avant de tenter cela sur une grande table.
Dan Bechard

2

Si aucune de ces réponses n'a fonctionné comme dans mon cas, procédez comme suit:

  1. Contraintes de chute
  2. Définissez toutes les valeurs pour autoriser les valeurs NULL
  3. Tronquer la table
  4. Ajoutez des contraintes qui ont été supprimées.

Bonne chance!


un échantillon sql à ce sujet?
Kiquenet

2

Supprimer puis réinitialiser l'incrémentation automatique:

delete from tablename;

puis

ALTER TABLE tablename AUTO_INCREMENT = 1;

Merci, cela a bien fonctionné.
M. Polywhirl

1

La seule façon est de supprimer les clés étrangères avant de tronquer. Et après avoir tronqué les données, vous devez recréer les index.

Le script suivant génère le SQL requis pour supprimer toutes les contraintes de clé étrangère.

DECLARE @drop NVARCHAR(MAX) = N'';

SELECT @drop += N'
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
    + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS ct
  ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs 
  ON ct.[schema_id] = cs.[schema_id];

SELECT @drop

Ensuite, le script suivant génère le SQL requis pour recréer des clés étrangères.

DECLARE @create NVARCHAR(MAX) = N'';

SELECT @create += N'
ALTER TABLE ' 
   + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
   + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
   + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
   -- get all the columns in the constraint table
    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(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'')
  + ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
  + '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
   -- get all the referenced columns
    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(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ');'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
  ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs 
  ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
  ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs 
  ON ct.[schema_id] = cs.[schema_id]
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0;

SELECT @create

Exécutez le script généré pour supprimer toutes les clés étrangères, tronquer les tables, puis exécutez le script généré pour recréer toutes les clés étrangères.

Les requêtes sont prises à partir d' ici .


0

Dans SSMS, j'avais un diagramme ouvert montrant la clé. Après avoir supprimé la clé et tronqué le fichier, j'ai actualisé puis me suis concentré sur le diagramme et créé une mise à jour en effaçant puis en restaurant une boîte d'identité. L'enregistrement du diagramme a fait apparaître une boîte de dialogue Enregistrer, puis une boîte de dialogue "Des modifications ont été apportées dans la base de données pendant que vous travailliez", en cliquant sur Oui, vous avez restauré la clé, en la restaurant à partir de la copie verrouillée dans le diagramme.


0

Si vous faites cela à une fréquence quelconque, même sur un calendrier, je n'utiliserais absolument, sans équivoque, aucune instruction DML. Le coût d'écriture dans le journal des transactions est trop élevé et la configuration deSIMPLE mode de récupération pour tronquer une table est ridicule.

La meilleure façon, c'est malheureusement la voie difficile ou laborieuse. Cet être:

  • Contraintes de chute
  • Tronquer la table
  • Recréer des contraintes

Mon processus pour ce faire implique les étapes suivantes:

  1. Dans SSMS, cliquez avec le bouton droit sur le tableau en question et sélectionnez Afficher les dépendances
  2. Prenez note des tableaux référencés (le cas échéant)
  3. De retour dans l'explorateur d'objets, développez le nœud Clés et notez les clés étrangères (le cas échéant)
  4. Lancer le script (supprimer / tronquer / recréer)

Les scripts de cette nature doivent être exécutés dans un bloc begin tranet commit tran.


-3

Je viens de découvrir que vous pouvez utiliser la table TRUNCATE sur une table parent avec des contraintes de clé étrangère sur un enfant tant que vous désactivez les contraintes sur le table enfant en premier. Par exemple

Clé étrangère CONSTRAINT child_par_ref sur la table enfant, référence PARENT_TABLE

ALTER TABLE CHILD_TABLE DISABLE CONSTRAINT child_par_ref;
TRUNCATE TABLE CHILD_TABLE;
TRUNCATE TABLE PARENT_TABLE;
ALTER TABLE CHILD_TABLE ENABLE CONSTRAINT child_par_ref;

1
Il ne s'agit pas d'une syntaxe SQL Server valide pour ALTER TABLE. Il n'y a pas {ENABLE | DESACTIVER} CONTRAINTE. Voir: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz

-3

La manière la plus simple:
1 - Entrez dans phpmyadmin
2 - Cliquez sur le nom de la table dans la colonne de gauche
3 - Cliquez sur Operation (menu supérieur)
4 - Cliquez sur "Vider la table (TRUNCATE)
5 - Désactivez la case" Activer les vérifications des clés étrangères "
6 - Terminé !

Lien vers le tutoriel d'image
Tutoriel: http://www.imageno.com/wz6gv1wuqajrpic.html
(désolé, je n'ai pas assez de réputation pour télécharger des images ici: P)


2
OP a déclaré MSSQL. Vous avez donné une réponse exclusive à MySQL.
reformé le

-4

Tu pourrais essayer DELETE FROM <your table >;.

Le serveur vous montrera le nom de la restriction et de la table, et en supprimant cette table, vous pouvez supprimer ce dont vous avez besoin.


6
Lisez sa deuxième phrase sur la question. Il sait qu'il peut le faire, mais ce n'est pas ce qu'il veut
renanleandrof

-7
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE table1;
TRUNCATE table2;
SET FOREIGN_KEY_CHECKS=1;

référence - tronquer la table contrainte de clé étrangère

Travailler pour moi dans MYSQL


1
Autre que la version spécifiée, y a-t-il autre chose qui ne va pas avec cela? Serait-il recommandé de l'utiliser ou de l'éviter complètement?
Andy Ibanez

1
@AndyIbanez MySQL est un produit complètement différent de MSSQL, pas une version différente de MSSQL.
Dan Bechard

1
sa bonne réponse, je ne sais pas pourquoi tout le monde donne négatif
sunil
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.