Неможливо урізати таблицю, оскільки на неї посилається обмеження "ІНОЗЕМНИЙ КЛЮЧ"?


459

Чи можна за допомогою MSSQL2005 усікати таблицю з обмеженням зовнішнього ключа, якщо спочатку обрізати дочірню таблицю (таблицю з первинним ключем відношення FK)?

Я знаю, що я можу і те, і інше

  • Використовуйте DELETEзастереження "без", а потім RESEEDособу (або)
  • Вийміть FK, обріжте таблицю та відтворіть FK.

Я думав, що, поки я обрізав дочірню таблицю перед батьком, я буду добре, не виконуючи жодного з наведених вище варіантів, але я отримую цю помилку:

Неможливо урізати таблицю "Таблиця імені", оскільки на неї посилається обмеження "ЗАМЕЧНИЙ КЛЮЧ".

Відповіді:


378

Правильно; не можна усікати таблицю, яка має обмеження на FK.

Зазвичай мій процес для цього:

  1. Скасуйте обмеження
  2. Обріжте стіл
  3. Відтворити обмеження.

(Звичайно, все угоди).

Звичайно, це стосується лише тих випадків, коли дитину вже обрізали. Інакше я йду іншим маршрутом, повністю залежним від того, як виглядають мої дані. (Занадто багато змінних, щоб потрапити сюди.)

Оригінальний плакат визначив ЧОМУ це справа; див. цю відповідь для отримання більш детальної інформації.


73
"ВИДАЛИТИ ВІД" не скидає стовпці з автоматичним збільшенням. Урізання робить. Вони функціонально не рівноцінні.
robross0606

35
Скорочення часто є саме тим, що ви хочете зробити, якщо ви видаляєте величезну кількість даних. Обрізання мільйона рядів? Мільярд? 1 мс ... так, @ M07, будь ласка, не кажіть "видалити з підходу чистіше", оскільки це просто не віддалено точно.
ctb

1
Після видалення великих даних користувачеві доводиться стискати таблиці та файли журналів, а також відновлювати місце на диску.
Мухаммед Юсаф Сулахрія

2
Чарівну кнопку зменшення (або сценарій) не рекомендується 99% часу.
Том Стікель

1
І як би ти це зробив? Приклад запитів?
jeromej

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

Зауважте, що це, мабуть, не хотілося б, якщо у вас є мільйони + записів, оскільки це дуже повільно.


Це було корисним, швидшим способом, ніж відключення та уможливлення обмеження.
сенсей

Це буде працювати лише для таблиці з меншою кількістю даних. Погодьтеся з @Pure
Dhanuka777

1
Це чудово, коли ви закінчили тестування схеми
охмусама

3
Я б не пропонував пройти цей маршрут, оскільки, можливо, ви також отримаєте цю помилку: Оператор DELETE суперечить обмеженню REFERENCE
sksallaj

Не працювали для мене. Оператор DELETE все ще суперечить обмеженню СПРАВКИ.
emirhosseini

192

Оскільки TRUNCATE TABLEце команда DDL , вона не може перевірити, чи посилаються на записи в таблиці запис із дочірньої таблиці.

Ось чому це DELETEпрацює, а TRUNCATE TABLEні: адже база даних може переконатися, що на неї не посилається інша запис.


92

Без 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)

Як збережена процедура

https://github.com/reduardo7/TableTruncate

Зауважте, що це, мабуть, не хотілося б, якщо у вас є мільйони + записів, оскільки це дуже повільно.


3
використання повторного перевстановлення нового значення = 1 після DELETE FROM починатиметься з ідентифікатора 2, а не з 1. З Technet ( technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx ) Якщо жодних рядків не було вставляється в таблицю з моменту її створення або всі рядки були видалені за допомогою оператора TRUNCATE TABLE, перший рядок, вставлений після запуску DBCC CHECKIDENT, використовує new_reseed_value як ідентичність. В іншому випадку наступний вставлений рядок використовує new_reseed_value + поточне значення приросту.
Зоран П.

@ZoranP. дивіться варіант "Збережена процедура": github.com/reduardo7/TableTruncate
Eduardo Cuomo

4
DBCC CHECKIDENT ([Таблиця], RESEED, 0) не 1
Tico Fortes

1
@TicoFortes Повідомлення оновлено. Дивіться варіант зберіганої процедури
Едуардо Куомо

1
Це не гарний підхід. Як коментує 700 інших версій цієї самої відповіді на це питання. БІЛЬШЕ, що ваша база даних знаходиться в простому режимі відновлення, щоб обмежити журнал транзакцій.
pimbrouwers

68

Наведене вище рішення @denver_citizen не працювало для мене, але мені сподобався дух, тому я змінив кілька речей:

  • зробив це збереженою процедурою
  • змінив спосіб заповнення та відтворення іноземних ключів
  • оригінальний скрипт обрізає всі посилаються таблиці, це може спричинити помилку порушення зовнішніх ключів, коли у таблиці, що посилається, є інші посилання на зовнішній ключ. Цей скрипт обрізає лише таблицю, вказану як параметр. Користувач повинен викликати цю збережену процедуру кілька разів у всіх таблицях у правильному порядку

На користь громадськості ось оновлений сценарій:

CREATE PROCEDURE [dbo].[truncate_non_empty_table]

  @TableToTruncate                 VARCHAR(64)

AS 

BEGIN

SET NOCOUNT ON

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

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

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

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

-- Drop Temporary tables

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

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


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

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

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


IF @Recycle = 0
   BEGIN

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

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

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

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

    SET @i = @i + 1

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

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

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

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

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

    SET @i = @i + 1


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

             END     


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

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

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

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

    SET @i = @i + 1

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


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

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


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

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

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

    SET @i = @i + 1


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

          END

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


END

11
Ця відповідь заслуговує на більше голосів! Насправді я б з радістю придбав тобі пиво, якби міг, Петро :)
nsimeonov

Це мені сьогодні допомогло швидко очистити кілька великих таблиць своїх даних для тестування. Дякую за якісну роботу над цим.
Крейг Сельберт

4
Дякую за цей фрагмент коду. Але будьте уважні, вам слід додати додаткову логіку для перевірки відключених FK. В іншому випадку ви ввімкнете обмежені в даний час обмеження.
Andre Figueiredo

2
Я зробив версію з пропозиціями @AndreFigueiredo. Я розміщую його на Gitlab: gitlab.com/ranolfi/truncate-referenced-table . Не соромтеся включити код до своєї відповіді.
Марк.2377,

1
Це чудово, але зауважте, що він не працюватиме, якщо ваші таблиці не є у схемі за замовчуванням (dbo).
Sidewinder94

19

використовувати наступну команду після видалення всіх рядків у цій таблиці, використовуючи оператор delete

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

EDIT: виправлений синтаксис для SQL Server


9
TRUNCATEуникає журналу і значно швидше, ніж DELETEдля великих таблиць. Це не є справжнім рівноцінним рішенням.
Сіріде

1
Чим ця відповідь відрізняється від тієї , яку давали рік тому?
Офер Зеліг

17

Ну, так як я не знайшов прикладів цього дуже просте рішення , я використовував, що:

  1. Скиньте зовнішній ключ;
  2. Обрізання таблиці
  3. Відтворити зовнішній ключ

Ось це іде:

1) Знайдіть ім'я іноземного ключа, що викликає збій (наприклад: FK_PROBLEM_REASON, з полем ID, з таблиці TABLE_OWNING_CONSTRAINT) 2) Видаліть цю клавішу з таблиці:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) Обрізати потрібний стіл

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) Повторно додайте ключ до першої таблиці:

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

Це воно.


Це не працює, якщо у вас є кілька таблиць із посиланнями іноземних ключів. Вам доведеться видалити безліч зовнішніх ключових обмежень у всій базі даних.
jbright

13

Ось сценарій, який я написав для автоматизації процесу. Я сподіваюся, що це допомагає.

SET NOCOUNT ON

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

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

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

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

-- Drop Temporary tables
DROP TABLE #FKs

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


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

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

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

IF @Recycle = 0
   BEGIN

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

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

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

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

    SET @i = @i + 1

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

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

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

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

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

    SET @i = @i + 1

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

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

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

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

    SET @i = @i + 1

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

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

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

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

    SET @i = @i + 1

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

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

2
Будь обережний. Я також додав би референтні дії на клавіші до вашого сценарію, інакше ви втратите налаштування каскаду.
альфадогг

1
це не працює для мене, але мені сподобався дух цього, тому я змінив декілька речей: зробив це збережена процедура, змінила спосіб заповнення іноземних ключів і відтворила оригінальний скрипт обрізає всі посилаються таблиці, це може бути неправильним, коли посилання таблицю не можна обрізати, оскільки вона також містить посилання на іноземні ключі. У цій версії тільки таблиця вказана в якості параметра буде усічена, всі посилання таблиці повинні бути усічені вручну перед викликом цього сценарію я відправив оновлений tolution на цю тему тут stackoverflow.com/a/13249209/157591
Пітер Санто

1
@alphadogg Чи є спосіб знайти ці референтні дії? Я блукав по Інтернету, і не можу їх знайти. Я можу поставити це як формальне запитання, якщо ви хочете.
Майкл - Де Глина Ширкий

1
Примітка майбутнім відвідувачам: це в sys.foreign_keysтаблиці. ( Довідка )
Майкл - Де Клей Ширкий

@Michael: Ви також можете використовувати INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ( msdn.microsoft.com/en-us/library/ms179987.aspx )
alphadogg

13

Ви можете виконати цей крок, За reseeding tableдопомогою даних можна видалити дані таблиці.

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

якщо виникла помилка, вам доведеться перезавантажити первинну таблицю.


1
Майте на увазі, що, незважаючи на те, що це працює добре, журнал транзакцій збільшиться на кількість записів у таблиці порівняно з «усіченою таблицею», яка містить лише один запис у журналі транзакцій. Це не велика справа для більшості таблиць, але якщо є мільйони + рядки, це може бути проблемою.
Девід

8

Якщо я правильно розумію, що ви хочете зробити, це створити чисте середовище для створення БД, що включає тести інтеграції.

Мій підхід тут полягав би в тому, щоб скинути всю схему і відтворити її згодом.

Причини:

  1. Напевно, у вас вже є сценарій "створити схему". Повторне використання його для тестової ізоляції легко.
  2. Створення схеми досить швидко.
  3. При такому підході налаштувати свій сценарій досить просто, щоб кожен пристрій створив НОВУ схему (з тимчасовою назвою), а потім можна почати паралельно запускати тестові світильники, що робить найповільнішу частину тестового набору набагато швидшою .

1
Я хотів би «усікати» всю схему, а не кидати її. Я хотів би зробити це в методі Setup інтеграційних тестів. Виклик сценарію створення БД з тестів інтеграції - це не перше рішення, до якого я піду.
ripper234

8
SET FOREIGN_KEY_CHECKS = 0; 

truncate table "yourTableName";

SET FOREIGN_KEY_CHECKS = 1;

8
Це питання стосується MS SQL Server, у якого немає налаштування
FOREIGN_KEY_CHECKS

1
Я думаю, що це спрацювало б із MySQL, але не з MS SQL Server
Cocowalla,

7

Знайдено в інших місцях Інтернету

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

3
Мабуть, мабуть, "АЛЬТЕР ТАБЛИКА? З ПЕРЕВІРИТЕ ПЕРЕВІРИТИСЯ ВСІМ '.
Андрій М

20
-1: Щойно підтверджено, що це зовсім не працює з командою скорочення, як задається питанням. Дивіться stackoverflow.com/questions/3843806/…
Лінн Кришиться

7

Ви не можете скоротити таблицю, якщо не скасуєте обмежень. Відключення також не працює. вам потрібно кинути все. Я створив сценарій, який скасовує всі обмеження, а потім відтворює.

Обов’язково загорніть його в транзакцію;)

SET NOCOUNT ON
GO

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

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

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

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

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

--DROP CONSTRAINT:

DECLARE @dynSQL varchar(MAX);

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

OPEN cur

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

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



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

    truncate table your_table

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

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

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

OPEN cur2

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

    print @dynSQL

    FETCH cur2 into @dynSQL
END
CLOSE cur2
DEALLOCATE cur2

6

Відповіді @denver_citizen та @Peter Szanto для мене не дуже спрацювали, але я змінив їх на облік:

  1. Композитні ключі
  2. Дії видалення та оновлення
  3. Перевірка індексу при повторному додаванні
  4. Схеми, крім dbo
  5. Кілька таблиць одночасно
DECLARE @Debug bit = 0;

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


BEGIN TRANSACTION TruncateTrans;

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



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



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

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

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


DECLARE @script nvarchar(MAX);

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

OPEN curScripts

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

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


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


COMMIT TRANSACTION TruncateTrans;

4

усікання не працювало для мене, видалення + повторна перевірка - найкращий вихід. Якщо там є хтось із вас, кому потрібно повторити величезну кількість таблиць, щоб виконати видалення + повторне повторення, ви можете зіткнутися з проблемами з деякими таблицями, у яких немає стовпця ідентичності, наступний код перевіряє, чи існує стовпець ідентифікації перед спробою перезавантажувати

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

4

Я писав наступні способи і намагався їх параметризувати, щоб ви могли запустити їх у « Query documentАбо зробити корисне SPз ними легко» .

А) Видалити

Якщо у вашій таблиці немає мільйонів записів, це працює добре і не має жодних команд 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)
  • У моєму вище відповіді спосіб вирішення зазначеної проблеми у питанні заснований на @ s15199d відповіді .

Б) Обрізати

Якщо вашій таблиці є мільйони записів або у вас не виникає жодних проблем із командою Alter у кодах, скористайтеся цією:

--   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
  • Наведений вище відповідь мій спосіб вирішення зазначеної проблеми у питанні заснований на відповіді @LauroWolffValenteSobrinho .

  • Якщо у вас є більше CONSTRAINT, ви повинні додати його коди, як я, до вищезазначеного запиту

  • Також ви можете змінити вищевказану кодову відповідь @SerjSagan, щоб відключити обмеження включення


3

Це моє вирішення цього питання. Я використовував це для зміни ПК, але ідея та ж. Сподіваюся, це стане в нагоді)

PRINT 'Script starts'

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

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

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

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

OPEN @CURSOR

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

WHILE @@FETCH_STATUS = 0
BEGIN

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

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

PRINT 'Altering primary table begin'

TRUNCATE TABLE table_name

PRINT 'Altering finished'

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

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

OPEN @CURSOR

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

WHILE @@FETCH_STATUS = 0
BEGIN

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

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

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

3

Бо MS SQLпринаймні новіші версії ви можете просто відключити обмеження з таким кодом:

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
Fwiw, це не працює у версії ОП (2005), а також не працює у його наступнику (MSSQL2008).
КБ

3

Наведене нижче працює для мене навіть із обмеженнями FK, і поєднує в собі наступні відповіді, щоб лише скинути вказані таблиці :


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;

Примітка:

Я думаю, що це все ще допомагає оголошувати таблиці в тому порядку, в якому ви хочете їх видалити (тобто вперше знищуйте залежності). Як видно з цієї відповіді , замість певних імен ви можете замінити всі таблиці

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

Насправді не намагалися виконувати інші сценарії, оскільки всі заявляли, що вони не працюють, коли у вас є іноземні ключі. Тому я спробував цей, і цей зробив для мене трюк.
Vivendi

1
DELETE не те саме, що TRUNCATE. Це заповнить ваші журнали транзакцій.
Ден Бешард

@Dan, напевно, хороший момент; як я вже згадував, я просто поєднав інші відповіді тут ...
drzaus

@drzaus Це буде добре працювати для малих / середніх таблиць, але у мене був вихід SQL-сервера виробництва в автономний режим завдяки команді delete, що заповнює журнал транзакцій, який заповнив жорсткий диск. Принаймні, переконайтеся, що журнали транзакцій мають максимальний розмір, перш ніж намагатися це зробити на великій таблиці.
Ден Бешард

2

Якщо жодна з цих відповідей не спрацювала так, як у моєму випадку, зробіть це:

  1. Обмеження для скидання
  2. Встановіть усі значення, щоб дозволити нулі
  3. Обрізання таблиці
  4. Додайте обмеження, які були скасовані.

Удачі!


будь-який зразок sql про це?
Кікенет

2

Видалити, потім скиньте автоматичне збільшення:

delete from tablename;

тоді

ALTER TABLE tablename AUTO_INCREMENT = 1;

Дякую, це спрацювало добре.
Містер Polywhirl

1

Єдиний спосіб - скинути сторонні ключі перед тим, як робити усічний. А після обрізання даних потрібно знову створити індекси.

Наступний сценарій генерує необхідний SQL для скасування всіх обмежень зовнішніх ключів.

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

Далі наступний скрипт генерує необхідний SQL для повторного створення зовнішніх ключів.

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

Запустіть створений скрипт, щоб скинути всі сторонні ключі, урізати таблиці, а потім запустіть створений сценарій, щоб відновити всі зовнішні ключі.

Запити взяті звідси .


0

У SSMS у мене була відкрита діаграма із зазначенням ключа. Після видалення ключа та обрізання файлу я оновився, потім зосередився на діаграмі та створив оновлення, очистивши та відновивши вікно посвідчення особи. Збереження діаграми виводило діалогове вікно «Зберегти», ніж діалогове вікно «Зміни були внесені в базу даних, коли ви працюєте», натиснувши Так, відновив ключ, відновивши його із замкнутої копії діаграми.


0

Якщо ви робите це з будь-якою частотою, чортів навіть за графіком, я б абсолютно, однозначно ніколи не використовував оператор DML. Вартість запису в журнал транзакцій просто висока і встановлення всієї бази данихSIMPLE режим відновлення для обрізання однієї таблиці є смішним.

Найкращий спосіб, на жаль, важкий чи трудомісткий спосіб. Це буття:

  • Обмеження для скидання
  • Обрізання таблиці
  • Заново створіть обмеження

Мій процес для цього включає наступні кроки:

  1. У SSMS клацніть правою кнопкою миші відповідну таблицю та виберіть Перегляд залежностей
  2. Візьміть до уваги наведені таблиці (якщо такі є)
  3. Повернувшись в провідник об’єктів, розгорніть вузол Keys і врахуйте зовнішні ключі (якщо такі є)
  4. Почати сценарій (падіння / скорочення / відновлення)

Сценарії подібного характеру слід робити в межах begin tranі commit tranблоку.


-3

Я щойно встановив, що ви можете використовувати таблицю TRUNCATE на батьківській таблиці з обмеженнями зовнішніх ключів для дитини, доки ви спочатку ВІДМОВИТИ обмеження на дочірній таблиці. Напр

Зовнішній ключ CONSTRAINT child_par_ref на таблиці дитини, посилання PARENT_TABLE

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

1
Це недійсний синтаксис SQL Server для ALTER TABLE. Немає {ENABLE | DISABLE} ЗАМИСЛЕННЯ. Дивіться: msdn.microsoft.com/en-us/library/ms190273.aspx
jason_ruz

-3

Найпростіший спосіб:
1 - Введіть phpmyadmin
2 - Клацніть на назві таблиці в лівій колонці
3 - Клацніть в операції (верхнє меню)
4 - Клацніть «Очистити таблицю (TRUNCATE)
5» - Відключити поле «Увімкнути перевірку зовнішніх ключів»
6 - Готово !

Посилання на підручник із зображеннями
Підручник: http://www.imageno.com/wz6gv1wuqajrpic.html
(вибачте, у мене недостатньо репутації для завантаження зображень сюди: P)


2
OP заявив MSSQL. Ви відповіли ексклюзивно на MySQL.
реформовано

-4

Ви можете спробувати DELETE FROM <your table >;.

Сервер покаже вам ім'я обмеження та таблицю, а при видаленні цієї таблиці ви можете видалити те, що вам потрібно.


6
Прочитайте його другу фразу з питання. Він знає, що може це зробити, але це не те, чого він хоче
renanleandrof

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

довідка - усічена таблиця з обмеженням зовнішнього ключа

Працює для мене в MYSQL


1
Окрім вказаної версії, чи є щось із цим не так? Чи рекомендували б його використовувати чи взагалі уникати?
Andy Ibanez

1
@AndyIbanez MySQL - це зовсім інший продукт від MSSQL, а не інша версія MSSQL.
Ден Бешард

1
її правильна відповідь Я не знаю, чому всі дають негатив
суніль
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.