it-swarm.com.de

Tabelle kann nicht abgeschnitten werden, da von einer FOREIGN KEY-Einschränkung darauf verwiesen wird

Kann ich mit MSSQL2005 eine Tabelle mit einer Fremdschlüsseleinschränkung abschneiden, wenn ich zuerst die untergeordnete Tabelle (die Tabelle mit dem Primärschlüssel der FK-Beziehung) abschneide?

Ich weiß, dass ich entweder kann

  • Verwenden Sie eine DELETE ohne eine where-Klausel und dann RESEED die Identität (oder).
  • Entfernen Sie die FK, schneiden Sie die Tabelle ab und erstellen Sie die FK neu.

Ich dachte, solange ich die untergeordnete Tabelle vor dem übergeordneten Element abschneide, wäre ich in Ordnung, ohne eine der oben genannten Optionen zu tun, aber ich erhalte folgende Fehlermeldung:

Die Tabelle 'TableName' kann nicht abgeschnitten werden, da sie von einer FOREIGN KEY-Einschränkung referenziert wird.

378
ctrlShiftBryan

Richtig; Sie können keine Tabelle abschneiden, die eine FK-Einschränkung enthält.

Normalerweise ist mein Prozess dafür:

  1. Lösche die Einschränkungen
  2. Schneiden Sie die Tabelle ab
  3. Erstellen Sie die Einschränkungen neu.

(Alles natürlich in einer Transaktion.)

Dies gilt natürlich nur, wenn das Kind bereits gekürzt wurde. Ansonsten gehe ich eine andere Route, abhängig davon, wie meine Daten aussehen. (Zu viele Variablen, um hier rein zu kommen.)

Das Originalplakat bestimmte WARUM dies der Fall ist; Siehe diese Antwort für weitere Details.

325
John Rudy
DELETE FROM TABLENAME
DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME',RESEED, 0)

Beachten Sie, dass dies wahrscheinlich nicht das ist, was Sie möchten, wenn Sie Millionen von Datensätzen haben, da dies sehr langsam ist.

300
s15199d

Da TRUNCATE TABLE ein DDL-Befehl ist, kann nicht geprüft werden, ob die Datensätze in der Tabelle von einem Datensatz in der untergeordneten Tabelle referenziert werden.

Aus diesem Grund funktioniert DELETE und TRUNCATE TABLE nicht: Die Datenbank kann sicherstellen, dass sie nicht von einem anderen Datensatz referenziert wird.

167
ctrlShiftBryan

Ohne 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|1])

Als gespeicherte Prozedur

https://github.com/reduardo7/TableTruncate

Beachten Sie, dass dies wahrscheinlich nicht das ist, was Sie wollen, wenn Sie Millionen von Datensätzen haben, da es sehr langsam ist.

80
Eduardo Cuomo

Die oben angegebene Lösung @denver_citizen hat für mich nicht funktioniert, aber ich mochte den Geist davon, also habe ich ein paar Dinge geändert:

  • machte es zu einer gespeicherten Prozedur
  • die Art und Weise geändert, in der die Fremdschlüssel aufgefüllt und neu erstellt werden
  • wenn das Original-Skript alle referenzierten Tabellen abschneidet, kann dies zu einem Fehler bei der Verletzung von Fremdschlüsseln führen, wenn die referenzierte Tabelle über andere Fremdschlüsselreferenzen verfügt. Dieses Skript schneidet nur die als Parameter angegebene Tabelle ab. Es liegt beim Benutzer, diese gespeicherte Prozedur in allen Tabellen in der richtigen Reihenfolge mehrmals aufzurufen

Für die Öffentlichkeit ist hier das aktualisierte Skript:

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
54
Peter Szanto

verwenden Sie den folgenden Befehl, nachdem Sie alle Zeilen in dieser Tabelle gelöscht haben

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

BEARBEITEN: Korrigierte Syntax für SQL Server

18
abdelwahed

sie können diesem Schritt folgen Mit reseeding table können Sie die Daten der Tabelle löschen.

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

wenn ein Fehler auftritt, müssen Sie die Primärtabelle neu setzen.

11
Rajneesh Kumar

Hier ist ein Skript, das ich geschrieben habe, um den Prozess zu automatisieren. Ich hoffe, es hilft.

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'
11
denver_citizen

Im Internet gefunden

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'
9
Freddie Bell

Nun, da ich Beispiele der sehr einfachen -Lösung nicht gefunden habe, die ich verwendet habe, ist dies:

  1. Fremdschlüssel ablegen;
  2. Tabelle abschneiden
  3. Fremdschlüssel neu erstellen

Hier kommt's:

1) Suchen Sie den Fremdschlüsselnamen, der den Fehler verursacht (z. B. FK_PROBLEM_REASON, mit Feld ID, aus Tabelle TABLE_OWNING_CONSTRAINT) 2) Entfernen Sie den Schlüssel aus der Tabelle:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Gewünschte Tabelle abschneiden

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Fügen Sie den Schlüssel erneut zu dieser ersten Tabelle hinzu:

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

Das ist es.

Wenn ich das richtig verstehe, müssen Sie wollen eine saubere Umgebung für die Datenbank einrichten, die Integrationstests umfasst.

Mein Ansatz hier wäre, das gesamte Schema zu löschen und es später neu zu erstellen.

Gründe dafür:

  1. Sie haben wahrscheinlich bereits ein Skript zum Erstellen eines Schemas. Die Wiederverwendung für die Testisolierung ist einfach.
  2. Das Erstellen eines Schemas geht ziemlich schnell.
  3. Mit diesem Ansatz ist es ziemlich einfach, Ihr Skript so einzurichten, dass jedes Gerät ein NEUES Schema (mit einem temporären Namen) erstellt. Anschließend können Sie Testgeräte parallel ausführen, wodurch der langsamste Teil Ihrer Testsuite viel schneller wird .
7
Ken Egozi

Sie können eine Tabelle nicht abschneiden, wenn Sie die Einschränkungen nicht löschen. Eine Deaktivierung funktioniert auch nicht. Du musst alles fallen lassen. Ich habe ein Skript erstellt, das alle Einschränkungen aufhebt und dann neu erstellt.

Achten Sie darauf, es in eine Transaktion einzuwickeln;)

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
5
renanleandrof
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;
4
Victor Jimenez

truncate hat bei mir nicht funktioniert, delete + reseed ist der beste Ausweg ..__ Falls es einige von Ihnen gibt, die eine riesige Anzahl von Tabellen iterieren müssen, um delete + reseed auszuführen, können bei einigen Problemen Probleme auftreten Bei Tabellen, die keine Identitätsspalte haben, prüft der folgende Code, ob eine Identitätsspalte vorhanden ist, bevor ein erneuter Versuch unternommen wird

    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
3
Ji_in_coding

Es ist meine Lösung für dieses Problem. Ich habe es benutzt, um PK zu ändern, aber die Idee war genauso. Hoffe das wird nützlich sein)

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 ['[email protected]_table+'] DROP CONSTRAINT ['[email protected]_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 [' [email protected]_table+ '] WITH NOCHECK ADD  CONSTRAINT [' [email protected]_key_name+ '] FOREIGN KEY(['[email protected]_column_1+'])
        REFERENCES [' [email protected]_table+'] (['[email protected]_column_1+'])')

    EXEC ('ALTER TABLE [' [email protected]_table+ '] CHECK CONSTRAINT [' [email protected]_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'
2
Oleg

Ich schreibe die folgenden Möglichkeiten und versuchte, sie zu parametrisieren, also Sie können Führen Sie sie in einem Query document aus oder Machen Sie mit ihnen leicht ein nützliches SP.

A) Löschen

If Ihre Tabelle hat keine Millionen Datensätze dies funktioniert gut und hat keine Alter-Befehle:

---------------------------------------------------------------
------------------- 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 @[email protected]+'.'[email protected]+'.'[email protected]
DBCC CHECKIDENT (@Query,RESEED, 0)
  • In der obigen Antwort von mir basiert die Methode zur Lösung des in der Frage erwähnten Problems auf @ s15199danswer .

B) Abschneiden

Wenn Ihre Tabelle hat Millionen von Datensätzen oder Sie haben kein Problem mit Befehl Ändern in Ihren Codes, dann verwenden Sie dieses:

--   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 '[email protected]_OfOwnerOfConstraint+' DROP CONSTRAINT '[email protected]_ConstraintName
EXECUTE sp_executesql @Query

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

SET @Query= 'ALTER TABLE '[email protected]_OfOwnerOfConstraint+' ADD CONSTRAINT '[email protected]_ConstraintName+' FOREIGN KEY('[email protected]_ColumnName_In_TableOfOwnerOfConstraint+') REFERENCES '[email protected]_ToTruncate+'('[email protected]_ColumnName_In_TableName_ToTruncate+')'
EXECUTE sp_executesql @Query
  • In der obigen Antwort von mir basiert die Methode zur Lösung des in der Frage erwähnten Problems auf @LauroWolffValenteSobrinhoanswer .

  • Wenn Sie mehr als eine CONSTRAINT haben, sollten Sie deren Codes wie ich an die obige Abfrage anhängen

  • Sie können auch die obige Codebasis @SerjSagananswer ändern, um die Aktivierung der Einschränkung zu deaktivieren

2
RAM

Folgendes funktioniert für mich auch mit FK-Einschränkungen und kombiniert die folgenden Antworten, um nur die angegebenen Tabellen zu löschen:


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, @[email protected])-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, @[email protected]), '')
    END

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

Hinweis:

Ich denke, es hilft immer noch, die Tabellen in der Reihenfolge zu deklarieren, in der sie gelöscht werden sollen (d. H. Zuerst Abhängigkeiten aufheben). Wie in diese Antwort zu sehen ist, könnten Sie anstelle von schleifenspezifischen Namen alle Tabellen durch ersetzen

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

Für MS SQL, zumindest für die neueren Versionen, können Sie die Einschränkungen mit Code wie folgt deaktivieren:

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
2
Serj Sagan

@ denver_citizen's Antwort hat für mich nicht ganz funktioniert, aber ich habe es geändert, um Folgendes zu berücksichtigen:

  1. Zusammengesetzte Schlüssel
  2. Aktionen Löschen und Aktualisieren
  3. Überprüfung des Index beim erneuten Hinzufügen 
  4. Andere Schemen als dbo
  5. Mehrere Tische gleichzeitig
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
        ,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 SCHEMA_NAME(fk.schema_id) = tbl.SchemaName 
                AND OBJECT_NAME(fc.referenced_object_id) = tbl.Name
)
select
    quotename(fk.ConstraintName) AS ConstraintName
    ,quotename(fk.SchemaName) + '.' + quotename(fk.TableName) AS TableName
    ,quotename(fk.SchemaName) + '.' + 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
        ORDER BY fk2.constraint_column_id
        FOR XML PATH(''),TYPE
    ).value('.','VARCHAR(MAX)'),1,1,'') AS ColumnNames
    ,STUFF((
        SELECT ',' + quotename(fk2.ReferencedColumnName)
        FROM foreignKeys fk2 
        WHERE fk2.ConstraintName = fk.ConstraintName
        ORDER BY fk2.constraint_column_id
        FOR XML PATH(''),TYPE
    ).value('.','VARCHAR(MAX)'),1,1,'') AS ReferencedColumnNames
into #FKs
from foreignKeys fk
GROUP BY fk.SchemaName, fk.ConstraintName, fk.TableName, 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 ' + fk.TableName AS script
from #FKs fk

-- 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 + ' ON UPDATE ' + fk.UpdateAction 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;
1
GhotiPhud

Wenn keine dieser Antworten wie in meinem Fall funktioniert hat

  1. Einschränkungen aufheben
  2. Legen Sie alle Werte fest, um Nullen zuzulassen
  3. Tabelle abschneiden
  4. Fügen Sie Einschränkungen hinzu, die gelöscht wurden.

Viel Glück!

1
G Jeny Ramirez

Wenn Sie dies in irgendeiner Art von Häufigkeit tun, selbst wenn es sich um einen Zeitplan handelt, würde ich absolut definitiv nie eine DML-Anweisung verwenden. Die Kosten für das Schreiben in das Transaktionslog sind einfach zu hoch Es ist lächerlich, die gesamte Datenbank in den Wiederherstellungsmodus SIMPLE zu setzen, um eine Tabelle abzuschneiden.

Der beste Weg ist leider der harte oder mühsame Weg. Das ist:

  • Einschränkungen aufheben
  • Tabelle abschneiden
  • Constraints neu erstellen

Mein Prozess dazu umfasst die folgenden Schritte:

  1. Klicken Sie im SSMS mit der rechten Maustaste auf die betreffende Tabelle und wählen Sie View Dependencies.
  2. Beachten Sie die referenzierten Tabellen (falls vorhanden)
  3. Erweitern Sie im Objekt-Explorer den Knoten Keys, und notieren Sie sich die Fremdschlüssel (falls vorhanden).
  4. Starten Sie die Skripterstellung (Ablegen/Abschneiden/Neu Erstellen)

Skripte dieser Art sollten innerhalb eines begin tran- und commit tran-Blocks erstellt werden.

0
pimbrouwers

Löschen und dann Auto-Inkrement zurücksetzen:

delete from tablename;

dann

ALTER TABLE tablename AUTO_INCREMENT = 1;
0
mwafi

Meine Güte - so viele Antworten ... und ich werde riskieren, noch eine weitere einzusetzen ... Ich brauchte etwas, um in regelmäßigen Abständen eine Untermenge von Tabellen in Produktionsdatenbanken zu löschen, und so ziemlich alle bestehenden Antworten hatten ein Problem passte nicht zu meinen Bedenken ...

  • Ich musste mich mit Einschränkungen befassen, die Namen wie ThisTable.to.ThatTable haben.
  • Die Liste der Tabellen kann mehrere Schemas umfassen
  • Die Liste der zu schneidenden Tabellen kann variieren - daher brauche ich eine Eingabe
  • Es gibt Fremdschlüssel mit on delete cascade und anderen Aktionen
  • Wenn ich die Fremdschlüssel nach dem Abschneiden nicht wiederherstellen kann, muss ich einen Rollback ausführen
  • Ich muss den Umfang des Löschens/erneuten Hinzufügen von Fremdschlüsseln nur für die betroffenen Tabellen einschränken
  • Ich brauche zumindest minimale Sicherheitsüberprüfungen, da wir die Kunden dazu bringen, dieses Durcheinander zu schaffen
  • Ich möchte, dass die Kunden ein Was ist, wenn ausführen, bevor sie es wirklich tun
  • Ich kann mir delete table aus verschiedenen Gründen nicht leisten

Ich wollte auch etwas Instandhaltbareres und Verständlicheres als einige der Skripts, die ich studiert habe. Ich weiß nicht ... ich denke das ist subjektiv. Sie mögen meinen Codierstil hassen.

Auf jeden Fall wird durch die Auswahl einiger großer alter nvarchar(max)-Variablen eine Vorverarbeitung ausgeführt: eine, um Fremdschlüssel zu löschen, eine, um die Trigger zum Deaktivieren/Abschneiden von Tabelle/Aktivieren auszuführen, und schließlich eine, um die Fremdschlüssel wiederherzustellen. Dann werden die Ergebnisse entweder gedruckt oder ausgeführt.

Es erwartet, dass es einen benutzerdefinierten Tabellentyp als Eingabeargument gibt. Wir haben so etwas in allen unseren Datenbanken. Dieser Typ wird folgendermaßen definiert:

create type dbo.NamesType as table( Name sysname )

Um es auf ein paar wegwerfende Tabellen in mehreren Schemata mit seltsamen Einschränkungsnamen (und möglicherweise ein paar böswillige Eingaben) zu nennen, ist hier der Kern meines Testgeschirrs:

create schema nop authorization dbo
go
  create schema gak authorization dbo
  go
    create table nop.a(one int primary key)
    create table gak.b(one int constraint [b.to.a] foreign key references nop.a)
    go
      --> do the damage...
      declare @t dbo.NamesType
      insert @t values ('nop.a'),('gak.b') --,(';drop database'),('no.bobby.tables')
      execute dbo.TruncateTables @t --, 0
    go
    drop table gak.b
    drop table nop.a
  go
  drop schema gak
go
drop schema nop

... was druckt:

alter table gak.b drop constraint [b.to.a];
alter table nop.a disable trigger all;
truncate table nop.a;
alter table nop.a enable trigger all;
alter table gak.b disable trigger all;
truncate table gak.b;
alter table gak.b enable trigger all;
alter table gak.b add constraint [b.to.a] foreign key ( one ) references nop.a( one );

Und zum Schluss noch der Garnball. Ich hoffe es tut jemand etwas Gutes ;-)

create procedure dbo.TruncateTables
  @tableNames dbo.NamesType readonly, --> Note: create type dbo.NamesType as table( Name sysname )
  @printOnly bit = 1 --> by default, it only prints...you have to explicly set to 0 to get it to do the damage
as 
begin

  set nocount on

  declare 
    @dropFKsSql nvarchar( max ) = N'',
    @addFKsSql nvarchar( max ) = N'',
    @truncateSql nvarchar( max ) = N'',
    @cr nvarchar( 2 ) = nchar( 13 ) + nchar( 10 ),
    @numberOfInputs int,
    @numberOfEligible int

  declare
    @truncatableTables table( object_id int not null )

  insert @truncatableTables
  select t.object_id 
  from
    @tableNames n 
    inner join
    sys.tables t
    on
      object_id( n.Name ) = t.object_id

  select @numberOfInputs = count(*) from @tableNames
  select @numberOfEligible = count(*) from @truncatableTables
  if ( @numberOfEligible < @numberOfInputs )
  begin
    raiserror( 'At least one of the inputs is not a table in this database', 16, 1 )
    return 1
  end

  select 
    @truncateSql += 
      N'alter table ' + schema_name(t.schema_id) + N'.' + t.name + N' disable trigger all;' + @cr +
      N'truncate table ' + schema_name(t.schema_id) + N'.' + t.name + N';' + @cr +
      N'alter table ' + schema_name(t.schema_id) + N'.' + t.name + N' enable trigger all;' + @cr 
  from 
    sys.tables t
  where 
    t.object_id in ( select object_id from @truncatableTables )

  select 
    @dropFKsSql +=  
      N'alter table '+ schema_name(from_table.schema_id) + N'.' + from_table.name + 
      N' drop constraint [' + fk.name + N']'+
      N';' + @cr,
    @addFKsSql +=
      N'alter table '+ schema_name(from_table.schema_id) + N'.' + from_table.name + 
      N' add constraint [' + fk.name + N'] foreign key ( ' + fk_cols.from_columns + N' ) references ' + 
      schema_name(to_table.schema_id) + N'.' + to_table.name + N'( ' + fk_cols.to_columns + N' )' + 
      case (fk.delete_referential_action) 
      when 1 then N' on delete cascade'  
      when 2 then N' on delete set null'
      when 3 then N' on delete set default'
      else N'' 
      end + 
      case (fk.update_referential_action) 
      when 1 then N' on update cascade'  
      when 2 then N' on update set null'
      when 3 then N' on update set default'
      else N'' 
      end + 
      N';' + @cr
  from 
    sys.foreign_keys fk
    inner join
    sys.objects from_table
    on
      fk.parent_object_id = from_table.object_id
    inner join
    sys.objects to_table
    on
      fk.referenced_object_id = to_table.object_id
    inner join
    (
      select
        o.constraint_object_id,
        stuff( (
          select N',' + col_name(fkc.parent_object_id, fkc.parent_column_id)
          from sys.foreign_key_columns fkc
          where fkc.constraint_object_id = o.constraint_object_id
          order by fkc.constraint_column_id  --> has to be same order in to_columns (below)
          for xml path( '' )
        ), 1, 1, N'' ) as from_columns, 
        stuff( (
          select N',' + col_name(fkc.referenced_object_id, fkc.referenced_column_id)
          from sys.foreign_key_columns fkc
          where fkc.constraint_object_id = o.constraint_object_id
          order by fkc.constraint_column_id --> has to be in same order as from_colums (above)
          for xml path( '' )
        ), 1, 1, N'' ) as to_columns
      from 
        sys.foreign_key_columns o
      where 
        o.constraint_column_id = 1 --> just need a representative row
      group by 
        constraint_object_id
    ) as fk_cols
    on
      fk.object_id = fk_cols.constraint_object_id
    where
      fk.referenced_object_id in ( select object_id from @truncatableTables ) --> limits scope

  print @dropFKsSql
  print @truncateSql
  print @addFKsSql

  if ( @printOnly = 0 )
  begin 
    begin transaction  --> won't have this luxury in Azure
      execute sp_executesql @statement = @dropFKsSql
      execute sp_executesql @statement = @truncateSql
      execute sp_executesql @statement = @addFKsSql
      print 'Got this far, and it didn''t blow up!'
    commit transaction
  end

end

In Azure können Sie truncate table nicht in einer Transaktion (grrrr ....) ausführen. In einer solchen Umgebung muss ich proaktiv sicherstellen, dass in Fremdschlüsseln Datensätze vorhanden sind, die nicht an der Kürzung teilnehmen. Nicht hoffnungslos kompliziert, aber für mich noch nicht notwendig.

0
Clay

In SSMS hatte ich Diagram mit dem Schlüssel geöffnet. Nach dem Löschen des Schlüssels und dem Abschneiden der Datei habe ich die Aktualisierung vorgenommen, mich dann wieder auf das Diagramm konzentriert und ein Update erstellt, indem ich ein Kontrollkästchen löschte und ein Identitätsfeld wiederherstellte. Beim Speichern des Diagramms wurde ein Dialogfeld "Speichern" geöffnet. Ein Dialogfeld "Änderungen wurden an der Datenbank vorgenommen, während Sie gerade arbeiteten". Klicken Sie auf "Ja", um den Schlüssel wiederherzustellen, und stellen Sie ihn aus der zwischengespeicherten Kopie im Diagramm wieder her. 

0
user2584621