Nie można obciąć tabeli, ponieważ odwołuje się do niej ograniczenie OBCEGO KLUCZA?

459

Czy używając MSSQL2005, mogę obciąć tabelę z ograniczeniem klucza obcego, jeśli najpierw obetnę tabelę potomną (tabelę z kluczem podstawowym relacji FK)?

Wiem, że mogę

  • Użyj DELETEklauzuli „bez”, a następnie RESEEDtożsamości (lub)
  • Usuń FK, skróć tabelę i ponownie utwórz FK.

Myślałem, że tak długo, jak przycinam stolik dziecięcy przed rodzicem, będę w porządku bez robienia żadnej z powyższych opcji, ale pojawia się ten błąd:

Nie można obciąć tabeli „TableName”, ponieważ odwołuje się do niej klucz OBCY.

ctrlShiftBryan
źródło

Odpowiedzi:

378

Poprawny; nie można obciąć tabeli, która ma ograniczenie FK.

Zazwyczaj mój proces to:

  1. Usuń ograniczenia
  2. Obetnij stół
  3. Odtwórz ograniczenia.

(Oczywiście w ramach transakcji.)

Oczywiście dotyczy to tylko sytuacji, gdy dziecko zostało już obcięte. W przeciwnym razie wybiorę inną trasę, całkowicie zależną od tego, jak wyglądają moje dane. (Zbyt wiele zmiennych, aby się tutaj dostać.)

Oryginalny plakat ustalił, DLACZEGO tak jest; zobacz tę odpowiedź, aby uzyskać więcej informacji.

John Rudy
źródło
73
„USUŃ Z” nie resetuje kolumn z automatyczną inkrementacją. Obcięcie ma. Nie są funkcjonalnie równoważne.
robross0606,
35
Obcinanie jest często dokładnie tym, co chcesz zrobić, jeśli usuwasz ogromne ilości danych. Obcinać milion wierszy? Miliard? 1 ms ... więc, @ M07, nie mów „usuń z podejścia jest czystsze”, ponieważ nie jest to zbyt dokładne.
ctb
1
Po usunięciu dużych danych użytkownik musi zmniejszyć tabele i pliki dziennika, aby odzyskać miejsce na dysku.
Muhammad Yousaf Sulahria
2
Przycisk Magic Shrink (lub skrypt) nie jest zalecany w 99% przypadków.
Tom Stickel
1
A jak byś to zrobił? Przykładowe prośby?
jeromej
356
DELETE FROM TABLENAME
DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME',RESEED, 0)

Pamiętaj, że nie jest to prawdopodobnie to, czego potrzebujesz, jeśli masz ponad milion rekordów, ponieważ jest to bardzo powolne.

s15199d
źródło
To był użyteczny, szybszy sposób niż wyłączenie i włączenie ograniczenia.
sensei
Działa to tylko w przypadku tabeli z mniejszą ilością danych. Zgadzam się z @Pure
Dhanuka777
1
Jest to świetne, gdy skończysz testowanie schematu
ohmusama,
3
Nie sugerowałbym pójścia tą drogą, ponieważ możesz również otrzymać ten błąd: instrukcja DELETE była w konflikcie z ograniczeniem REFERENCE
sksallaj
Nie działało dla mnie. Wciąż otrzymuję instrukcję DELETE sprzeczną z ograniczeniem REFERENCE.
emirhosseini
192

Ponieważ TRUNCATE TABLEjest to polecenie DDL , nie może sprawdzić, czy rekordy w tabeli są przywoływane przez rekord w tabeli potomnej.

Dlatego DELETEdziała, a TRUNCATE TABLEnie: ponieważ baza danych jest w stanie upewnić się, że nie odwołuje się do niej inny rekord.

ctrlShiftBryan
źródło
92

Bez 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)

Jako procedura składowana

https://github.com/reduardo7/TableTruncate

Pamiętaj, że nie jest to prawdopodobnie to, czego potrzebujesz, jeśli masz ponad milion rekordów, ponieważ jest to bardzo powolne.

Eduardo Cuomo
źródło
3
użycie reseed nowej wartości = 1 po usunięciu spowoduje, że wszystko zacznie się od ID 2, zamiast 1. Od Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) Jeśli nie zostały żadne wiersze wstawiony do tabeli od momentu jej utworzenia lub wszystkie wiersze zostały usunięte przy użyciu instrukcji TRUNCATE TABLE, pierwszy wiersz wstawiony po uruchomieniu DBCC CHECKIDENT używa nowej_reseed_value jako tożsamości. W przeciwnym razie następny wstawiony wiersz używa nowej_wartości_seseed + bieżącej wartości przyrostu.
Zoran P.
@ZoranP. zobacz wariant Procedura składowana
Eduardo Cuomo
4
DBCC CHECKIDENT ([TableName], RESEED, 0) not 1
Tico Fortes
1
@TicoFortes Post zaktualizowane. Zobacz wariant Procedura składowana
Eduardo Cuomo,
1
To nie jest dobre podejście. Jak skomentował 700 innych wersji tej samej odpowiedzi na to pytanie. O ile baza danych jest w trybie prostego odzyskiwania, aby ograniczyć rejestrowanie transakcji.
pimbrouwers
68

Powyższe rozwiązanie @denver_citizen nie działało dla mnie, ale podobał mi się jego duch, więc zmodyfikowałem kilka rzeczy:

  • uczyniło to procedurą składowaną
  • zmieniono sposób zapełniania i odtwarzania kluczy obcych
  • oryginalny skrypt obcina wszystkie tabele, do których istnieją odniesienia, może to powodować błąd naruszenia klucza obcego, gdy tabela, do której istnieją odwołania, ma inne odwołania do klucza obcego. Ten skrypt obcina tylko tabelę określoną jako parametr. Użytkownik musi wielokrotnie wywoływać tę procedurę przechowywaną we wszystkich tabelach we właściwej kolejności

Z korzyścią dla społeczeństwa tutaj jest zaktualizowany skrypt:

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
Peter Szanto
źródło
11
Ta odpowiedź zasługuje na więcej głosów! W rzeczywistości chętnie kupiłbym ci piwo, gdybym mógł, Peter :)
nsimeonov
To była dla mnie ogromna pomoc w szybkim wyczyszczeniu niektórych dużych tabel z ich danych do testowania. Dziękujemy za pracę nad tym nad jakością.
Craig Selbert,
4
Dziękuję za ten fragment kodu. Ale uważaj, powinieneś dodać dodatkową logikę, aby sprawdzić wyłączone FK. W przeciwnym razie włączysz obecnie wyłączone ograniczenia.
Andre Figueiredo
2
Stworzyłem wersję z sugestiami @AndreFigueiredo. Zamieszczam go na Gitlab: gitlab.com/ranolfi/truncate-referenced-table . Dołącz kod do swojej odpowiedzi.
Marc.2377,
1
Jest to świetne, ale pamiętaj, że nie będzie działać, jeśli tabele nie są w domyślnym schemacie (dbo).
Sidewinder94
19

użyj następującego polecenia po usunięciu wszystkich wierszy w tej tabeli przy użyciu instrukcji delete

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

EDYCJA: Poprawiona składnia dla SQL Server

abdelwahed
źródło
9
TRUNCATEpozwala uniknąć dziennika i jest znacznie szybszy niż w DELETEprzypadku dużych tabel. Jako takie nie jest to prawdziwe równoważne rozwiązanie.
siride
1
Czym różni się ta odpowiedź od tej , którą podano rok wcześniej?
Ofer Zelig
17

No cóż, skoro nie mogę znaleźć przykłady z bardzo prostego rozwiązania użyłem, który jest:

  1. Upuść klucz obcy;
  2. Obetnij stół
  3. Odtwórz klucz obcy

Oto jest:

1) Znajdź nazwę klucza obcego, który powoduje awarię (na przykład: FK_PROBLEM_REASON, z polem ID, z tabeli TABLE_OWNING_CONSTRAINT) 2) Usuń ten klucz z tabeli:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Obetnij poszukiwany stół

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Ponownie dodaj klucz do pierwszej tabeli:

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

Otóż ​​to.

Lauro Wolff Valente Sobrinho
źródło
To nie działa, jeśli masz wiele tabel z odniesieniami do kluczy obcych. Trzeba będzie usunąć wiele ograniczeń klucza obcego w całej bazie danych.
jbright 27.04.16
13

Oto skrypt, który napisałem w celu zautomatyzowania procesu. Mam nadzieję, że to pomoże.

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'
denver_citizen
źródło
2
Bądź ostrożny. Dodałbym również działania referencyjne na klawiszach do twojego skryptu, inaczej stracisz ustawienia kaskady.
alphadogg
1
to nie działa dla mnie, ale podobał mi się jego duch, więc zmodyfikowałem kilka rzeczy: zmieniłem sposób, w jaki zapełniane są klucze obce, i odtworzyłem oryginalny skrypt obcinający wszystkie tabele, do których można się odwoływać tabela nie może zostać obcięta, ponieważ zawiera również odwołania do kluczy obcych. W tej wersji tylko tabela określona jako parametr zostanie obcięta, wszystkie odnośne tabele powinny zostać obcięte ręcznie przed wywołaniem tego skryptu Opublikowałem zaktualizowane rozwiązanie w tym wątku tutaj stackoverflow.com/a/13249209/157591
Peter Szanto
1
@alphadogg Czy jest jakiś sposób na znalezienie tych działań referencyjnych? Grzebię w Internecie i nie mogę ich znaleźć. Mogę to zadać jako pytanie formalne, jeśli wolisz.
Michael - Where's Clay Shirky
1
Uwaga dla przyszłych gości: jest w sys.foreign_keystabeli. ( Odniesienie )
Michael - Where's Clay Shirky
@Michael: Możesz także użyć INFORMACJE_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg
13

możesz wykonać ten krok, reseeding tableMożesz usunąć dane z tabeli.

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

jeśli wystąpi jakiś błąd, musisz ponownie ustawić tabelę podstawową.

Rajneesh Kumar
źródło
1
Należy pamiętać, że nawet jeśli działa to dobrze, dziennik transakcji wzrośnie o liczbę rekordów w tabeli w porównaniu do „obcinania tabeli”, która umieszcza tylko jeden rekord w dzienniku transakcji. Nie jest to wielka sprawa dla większości tabel, ale jeśli są miliony + wierszy, może to stanowić problem.
David
8

Jeśli dobrze rozumiem, czego chcesz zrobić, to mieć czyste środowisko do skonfigurowania DB z testami integracji.

Moje podejście tutaj polegałoby na usunięciu całego schematu i odtworzeniu go później.

Powody:

  1. Prawdopodobnie masz już skrypt „utwórz schemat”. Ponowne użycie go do izolacji testowej jest łatwe.
  2. Tworzenie schematu jest dość szybkie.
  3. Dzięki takiemu podejściu konfiguracja skryptu jest dość łatwa, aby każde urządzenie tworzyło NOWY schemat (z tymczasową nazwą), a następnie można rozpocząć równoległe uruchamianie urządzeń testowych, dzięki czemu najwolniejsza część zestawu testów jest znacznie szybsza .
Ken Egozi
źródło
1
Chciałbym „obciąć” cały schemat, a nie upuszczać go. Chciałbym to zrobić w metodzie Instalatora testów integracji. Wywołanie skryptu tworzenia DB z testów integracyjnych nie jest ... pierwszym rozwiązaniem, do którego pójdę.
ripper234
8
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;
Victor Jimenez
źródło
8
To pytanie dotyczy MS SQL Server, który nie ma ustawienia
FOREIGN_KEY_CHECKS
1
Myślę, że to zadziałałoby z MySQL, ale nie z MS SQL Server
Cocowalla
7

Znalezione w innym miejscu w sieci

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'
Freddie Bell
źródło
3
Powinien być prawdopodobnie „ZMIENIĆ TABELĘ”? Z KONTROLĄ SPRAWDŹ KONTRAKT WSZYSTKO ”.
Andriy M
20
-1: Właśnie potwierdziłem, że to wcale nie działa z poleceniem skracania zadanym przez pytanie. Zobacz stackoverflow.com/questions/3843806/…
Lynn Crumbling
7

Nie można obciąć tabeli, jeśli nie usuniesz ograniczeń. Wyłączenie również nie działa. musisz upuścić wszystko. Stworzyłem skrypt, który usuwa wszystkie ograniczenia, a następnie je ponownie tworzę.

Pamiętaj o zawinięciu w transakcję;)

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
renanleandrof
źródło
6

Odpowiedzi @denver_citizen i @Peter Szanto dla mnie nie działały, ale zmodyfikowałem je, aby uwzględnić:

  1. Klucze kompozytowe
  2. Działania dotyczące usuwania i aktualizacji
  3. Sprawdzanie indeksu podczas ponownego dodawania
  4. Schematy inne niż dbo
  5. Wiele stolików jednocześnie
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;
GhotiPhud
źródło
4

obcinanie nie działało dla mnie, najlepszym rozwiązaniem jest usunięcie + ponowne uruchomienie. W przypadku niektórych z was, którzy muszą iterować ogromną liczbę tabel, aby wykonać usuwanie + ponowne uruchomienie, możesz napotkać problemy z niektórymi tabelami, które nie mają kolumny tożsamości, poniższy kod sprawdza, czy kolumna tożsamości istnieje przed podjęciem próby do ponownego posadzenia

    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
Ji_in_coding
źródło
4

Piszę następujące sposoby i próbowali je parametryzowane, więc można prowadzić je w Query documentLub Złóż przydatnym SPz nich łatwo .

A) Usuń

Jeśli twoja tabela nie ma milionów rekordów, działa to dobrze i nie ma żadnych poleceń 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)
  • W powyższej odpowiedzi moja metoda rozwiązania wspomnianego problemu w pytaniu oparta jest na odpowiedzi @ s15199d .

B) Obetnij

Jeśli twoja tabela ma miliony rekordów lub nie masz żadnych problemów z poleceniem Alter w swoich kodach, użyj tego:

--   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
  • W powyższej odpowiedzi moja metoda rozwiązania wspomnianego problemu w pytaniu oparta jest na odpowiedzi @LauroWolffValenteSobrinho .

  • Jeśli masz więcej niż jeden OGRANICZENIE, powinieneś dołączyć jego kody, takie jak ja, do powyższego zapytania

  • Możesz także zmienić powyższą odpowiedź na kod bazowy @SerjSagan, aby wyłączyć ograniczenie włączenia

Baran
źródło
3

To moje rozwiązanie tego problemu. Użyłem go do zmiany PK, ale pomysł jest taki sam. Mam nadzieję, że to się przyda)

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'
Oleg
źródło
3

Dla MS SQLprzynajmniej nowsze wersje, można po prostu wyłączyć ograniczenia co z kodem jak poniżej:

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
Serj Sagan
źródło
Myślę, że ustaliliśmy powyżej, że to nie działa? Może tak jest w przypadku nowszych wersji?
Coops
2
Fwiw, to nie działa w wersji PO (2005), a także nie działa w jego następcy (MSSQL2008).
CB
3

Poniższe działa dla mnie nawet z ograniczeniami FK i łączy następujące odpowiedzi, aby usunąć tylko określone tabele :


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;

Uwaga:

Myślę, że nadal pomaga zadeklarować tabele w kolejności, w której chcesz je usunąć (tj. Najpierw zabić zależności). Jak widać w tej odpowiedzi , zamiast nazw specyficznych dla pętli można zastąpić wszystkie tabele

EXEC sp_MSForEachTable 'DELETE FROM ?; DBCC CHECKIDENT (''?'',RESEED, 0);';
drzaus
źródło
Naprawdę nie próbowałem innych skryptów, ponieważ wszyscy stwierdzili, że nie działają, gdy masz klucze zagraniczne. Więc spróbowałem tego i ten zrobił dla mnie lewę.
Vivendi,
1
DELETE to nie to samo co TRUNCATE. Spowoduje to wypełnienie dzienników transakcji.
Dan Bechard
@ Dan, prawdopodobnie dobry punkt; tak jak wspomniałem, po prostu połączyłem inne odpowiedzi tutaj ...
drzaus
@drzaus Będzie działał dobrze dla małych / średnich tabel, ale miałem produkcyjny serwer SQL, który przeszedł w tryb offline z powodu polecenia usuwania wypełniającego dziennik transakcji, który zapełnił dysk twardy. Przynajmniej upewnij się, że dzienniki transakcji mają maksymalny rozmiar, zanim spróbujesz to zrobić na dużym stole.
Dan Bechard
2

Jeśli żadna z tych odpowiedzi nie działała tak jak w moim przypadku, wykonaj następujące czynności:

  1. Usuń ograniczenia
  2. Ustaw wszystkie wartości, aby zezwolić na wartości null
  3. Obetnij stół
  4. Dodaj ograniczenia, które zostały usunięte.

Powodzenia!

G Jeny Ramirez
źródło
jakaś próbka sql na ten temat?
Kiquenet,
2

Usuń, a następnie zresetuj auto-przyrost:

delete from tablename;

następnie

ALTER TABLE tablename AUTO_INCREMENT = 1;
mwafi
źródło
Dzięki, działało to dobrze.
Pan Polywhirl
1

Jedynym sposobem jest upuszczenie kluczy obcych przed wykonaniem obcięcia. Po obcięciu danych należy ponownie utworzyć indeksy.

Poniższy skrypt generuje wymagany SQL do usunięcia wszystkich ograniczeń klucza obcego.

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

Następnie poniższy skrypt generuje wymagany kod SQL do ponownego utworzenia kluczy obcych.

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

Uruchom wygenerowany skrypt, aby usunąć wszystkie klucze obce, skróć tabele, a następnie uruchom wygenerowany skrypt, aby odtworzyć wszystkie klucze obce.

Zapytania są pobierane stąd .

Ehsan Mirsaeedi
źródło
0

W SSMS miałem otwarty schemat pokazujący klucz. Po usunięciu klucza i obcięciu pliku odświeżyłem się, po czym ponownie skupiłem się na diagramie i utworzyłem aktualizację, czyszcząc, a następnie przywracając pole tożsamości. Zapisanie diagramu wywołało okno dialogowe Zapisz, a następnie okno dialogowe „Zmiany dokonano w bazie danych podczas pracy”. Kliknięcie przycisku Tak przywróciło klucz, przywracając go z zatrzaśniętej kopii na schemacie.

użytkownik2584621
źródło
0

Jeśli robisz to z jakiejkolwiek częstotliwości, na przykład nawet według harmonogramu, absolutnie, jednoznacznie nigdy nie użyłbym instrukcji DML. Koszt zapisania do dziennika transakcji jest po prostu zbyt wysoki, a ustawienie całej bazy danych w SIMPLEtryb odzyskiwania w celu obcięcia jednej tabeli jest absurdalne.

Najlepszym sposobem jest niestety trudny lub pracochłonny sposób. Ta istota:

  • Usuń ograniczenia
  • Obetnij stół
  • Ponownie utwórz ograniczenia

Mój proces tego wymaga następujących kroków:

  1. W SSMS kliknij prawym przyciskiem myszy tabelę i wybierz Wyświetl zależności
  2. Zwróć uwagę na tabele, o których mowa (jeśli istnieją)
  3. Po powrocie do eksploratora obiektów rozwiń węzeł Klucze i zwróć uwagę na klucze obce (jeśli istnieją)
  4. Zacznij pisać skrypty (upuść / skróć / ponownie utwórz)

Skrypty tego rodzaju powinny być wykonywane w blokach begin trani commit tran.

pimbrouwers
źródło
-3

Właśnie odkryłem, że możesz używać tabeli TRUNCATE na tabeli nadrzędnej z ograniczeniami klucza obcego na obiekcie podrzędnym, o ile najpierw wyłączysz ograniczenia na tabeli podrzędnej . Na przykład

Klucz obcy CONSTRAINT child_par_ref w tabeli potomnej, referencje 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;
PWF
źródło
1
To nie jest poprawna składnia SQL Server dla ALTER TABLE. Nie ma {ENABLE | WYŁĄCZ} OGRANICZENIE. Zobacz: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz
-3

Najprostszy sposób:
1 - Wpisz w phpmyadmin
2 - Kliknij nazwę tabeli w lewej kolumnie
3 - Kliknij Operacja (górne menu)
4 - Kliknij „Opróżnij tabelę (TRUNCATE)
5 - Wyłącz pole” Włącz sprawdzanie klucza obcego ”
6 - Gotowe !

Link do samouczka graficznego
Samouczek: http://www.imageno.com/wz6gv1wuqajrpic.html
(przepraszam, nie mam wystarczającej reputacji, aby przesyłać zdjęcia tutaj: P)

Marco
źródło
2
OP stwierdził MSSQL. Udzieliłeś odpowiedzi wyłącznie na MySQL.
zreformowano
-4

Możesz spróbować DELETE FROM <your table >;.

Serwer wyświetli nazwę ograniczenia i tabeli, a po usunięciu tej tabeli możesz usunąć to, czego potrzebujesz.

Rene
źródło
6
Przeczytaj jego drugie zdanie na pytanie. Wie, że może to zrobić, ale nie tego chce
renanleandrof
-7
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE table1;
TRUNCATE table2;
SET FOREIGN_KEY_CHECKS=1;

referencja - obciąć ograniczoną tabelę klucza obcego

Pracuje dla mnie w MYSQL

Jack Sparrow
źródło
1
Czy nie jest w tym coś innego niż określona wersja? Czy zaleca się korzystanie z niego, czy unikanie go całkowicie?
Andy Ibanez
1
@AndyIbanez MySQL to zupełnie inny produkt niż MSSQL, a nie inna wersja MSSQL.
Dan Bechard
1
prawidłowa odpowiedź Nie wiem, dlaczego wszyscy dają przeczenia
sunil