Как урезать таблицу с внешним ключом?


648

Почему не TRUNCATE на mygroupработе? Даже если у меня есть, ON DELETE CASCADE SETя получаю:

ОШИБКА 1701 (42000): Невозможно обрезать таблицу, на которую ссылается ограничение внешнего ключа ( mytest. instance, CONSTRAINT instance_ibfk_1FOREIGN KEY ( GroupID) ССЫЛКИ mytest. mygroup( ID))

drop database mytest;
create database mytest;
use mytest;

CREATE TABLE mygroup (
   ID    INT NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE=InnoDB;

CREATE TABLE instance (
   ID           INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
   GroupID      INT NOT NULL,
   DateTime     DATETIME DEFAULT NULL,

   FOREIGN KEY  (GroupID) REFERENCES mygroup(ID) ON DELETE CASCADE,
   UNIQUE(GroupID)
) ENGINE=InnoDB;

Ответы:


1001

Вы не можете TRUNCATEиспользовать таблицу, к которой применены ограничения FK ( TRUNCATEэто не то же самое, что DELETE).

Чтобы обойти это, используйте любое из этих решений. Оба представляют риски нарушения целостности данных.

Опция 1:

  1. Удалить ограничения
  2. выполнять TRUNCATE
  3. Удалите вручную строки, которые теперь имеют ссылки в никуда
  4. Создать ограничения

Вариант 2: предложенный пользователем 447951 в своем ответе

SET FOREIGN_KEY_CHECKS = 0; 
TRUNCATE table $table_name; 
SET FOREIGN_KEY_CHECKS = 1;

46
@barjonah: на самом деле, это может нарушить целостность данных (см. stackoverflow.com/questions/5452760/… ). Итак, то, что вы называете «светом» в реальном мире, считается плохой практикой. PS: спасибо за downvote
zerkms

1
Вот очень хороший способ найти потерянные внешние ключи (восстановить целостность данных) http://stackoverflow.com/a/12085689/997776
SandorRacz

отключить внешний ключ перед усечением - это тоже хороший способ, я сделал это с успехом из источника: stackoverflow.com/questions/8641703/…
Dung

2
@Dung отключение проверки внешнего ключа допускается только в период разработки. Это нарушает любые существующие отношения. zerkms на 100% прав насчет целостности данных. Вы не можете отключить проверку внешнего ключа в рабочей базе данных, если не планируете полностью очистить ее (или, по крайней мере, все связанные таблицы)
NoobishPro

1
@ Камлеш, это не мое решение, я посоветовал не делать это таким варварским способом.
zerkms

1308

Да, ты можешь:

SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE table1;
TRUNCATE table2;

SET FOREIGN_KEY_CHECKS = 1;

Используя эти операторы, вы рискуете пустить в таблицы строки, которые не соответствуют FOREIGN KEYограничениям.


30
мы должны установить SET FOREIGN_KEY_CHECKS = 1; снова потом?
vinc3m1

77
Нет, ты не Настройка действительна только при подключении. Как только вы отключитесь, следующее соединение вернется к 1.
Pellmeister

7
Это не относится к событию «ON DELETE» в указанной таблице, поэтому это не полный ответ.
Омер Сабич

5
При использовании в PHPMYADMIN это работает, только если вы используете все транзакции в одном и том же окне SQL (разделенные символом a ;). Это связано с тем, что каждый новый веб-вызов SQL сбрасывается FOREIGN_KEY_CHECKSдо 1.
Sablefoste

1
Вот очень хороший способ найти потерянные внешние ключи (восстановить целостность данных) в случае, если вы заинтересованы http://stackoverflow.com/a/12085689/997776
SandorRacz

173

Я бы просто сделал это с:

DELETE FROM mytest.instance;
ALTER TABLE mytest.instance AUTO_INCREMENT = 1;

5
Умный. Если вы все равно хотите удалить все записи, вы также можете сбросить автоприращение.
winkbrace

6
Это, очевидно, лучший способ сделать это. Нет риска потери ограничений, просто удалить. Стоит отметить, что DELETEработает медленнее, чем TRUNCATE. Но так как это действие обычно выполняется очень редко, это не имеет значения.
phil294

Это хорошо, если это все, что вы хотите сделать, но DELETEможет быть абсолютно жестоким, если у вас слишком много строк - поскольку он попадает в журналы, тогда как TRUNCATEпросто вырывает данные. Действительно зависит от варианта использования.
Джефф

1
когда я использую оператор delete, он сообщает об ошибке 1175: вы используете безопасный режим обновления, просто добавьте SET SQL_SAFE_UPDATES = 0; тогда все в порядке
Тян

При использовании этого решения оно сообщает об error 1175: You are using safe update mode,...изменении предложения delete, чтобы DELETE FROM mydb.mytable where id != 0сделать его идеальным.
Шихе Чжан

17

ты можешь сделать

DELETE FROM `mytable` WHERE `id` > 0

1
Я попытался, но появилась следующая ошибка: Код ошибки: 1142. Команда DELETE запрещена пользователю 'root' @ 'localhost' для таблицы 'mytable'
AAEM

или просто УДАЛИТЬ ОТmytable
Милослав Мило Яноушек

Это не сбрасывает автоприращение.
vivek_23

13

Согласно документации mysql , TRUNCATE не может использоваться в таблицах с отношениями внешнего ключа. Там нет полной альтернативы AFAIK.

Удаление контринта все равно не вызывает ON DELETE и ON UPDATE. Единственное решение, которое я могу найти в банкомате, это либо:

  • удалить все строки, удалить внешние ключи, обрезать, воссоздать ключи
  • удалить все строки, сбросить auto_increment (если используется)

Казалось бы, TRUNCATE в MySQL еще не является полной функцией (он также не вызывает триггеры). Смотрите комментарий


7
Замечание по поводу того, что MySQL TRUNCATEявляется неполным - truncate не должен вызывать триггеры и т. Д. Если бы это произошло, это было бы так же, как DELETE! Он не зависит от строки, поэтому не может выполнять операции со строками (например, запуск триггеров или проверка внешних ключей). Аналогичным образом работает в Oracle и Sql Server .
Саймон МакКензи

8

Легко, если вы используете phpMyAdmin.

Просто снимите флажок Enable foreign key checksпод SQLвкладкой и запуститеTRUNCATE <TABLE_NAME>

введите описание изображения здесь


8

Пока задавался этот вопрос, я не знал об этом, но теперь, если вы используете phpMyAdmin, вы можете просто открыть базу данных и выбрать таблицы, которые вы хотите обрезать.

  • Внизу есть выпадающий список с множеством вариантов. Откройте его и выберите Emptyопцию под заголовком Delete data or table.
  • Он автоматически переместит вас на следующую страницу, где есть опция в флажке Enable foreign key checks. Просто отмените Yesвыбор и нажмите кнопку, и выбранные таблицы будут обрезаны.

Возможно, он внутренне выполняет запрос, предложенный в ответе пользователя 447951 , но его очень удобно использовать из интерфейса phpMyAdmin.


8

Проверено на базе данных MYSQL

Решение 1:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;

Решение 2:

DELETE FROM table1;
ALTER TABLE table1 AUTO_INCREMENT = 1;
TRUNCATE table1;

Это работает для меня. Надеюсь, это вам тоже поможет. Спасибо, что задали этот вопрос.


6

Ответ, действительно, предоставлен zerkms , как указано в варианте 1 :

Вариант 1 : который не рискует нарушить целостность данных:

  1. Удалить ограничения
  2. Выполнить TRUNCATE
  3. Удалите вручную строки, которые теперь имеют ссылки в никуда
  4. Создать ограничения

Самое сложное - это удалить ограничения , поэтому я хочу рассказать вам, как, если кому-то нужно знать, как это сделать:

  1. Запустите SHOW CREATE TABLE <Table Name>query, чтобы увидеть, как называется ваш FOREIGN KEY (красная рамка на изображении ниже):

    введите описание изображения здесь

  2. Беги ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>. Это снимет ограничение внешнего ключа.

  3. Удалите связанный индекс (через страницу структуры таблицы), и все готово.

воссоздать внешние ключи:

ALTER TABLE <Table Name>
ADD FOREIGN KEY (<Field Name>) REFERENCES <Foreign Table Name>(<Field Name>);

3

Просто используйте КАСКАД

TRUNCATE "products" RESTART IDENTITY CASCADE;

Но будьте готовы к каскадному удалению)


3
ОП пометил MySQL. Хотя это действует в Postgres, это неверно в MySQL.
Питер

1

Если ядро ​​базы данных для таблиц отличается, вы получите эту ошибку, поэтому замените их на InnoDB

ALTER TABLE my_table ENGINE = InnoDB;

0

Получение старого состояния проверки внешнего ключа и режима sql - лучший способ усекать / отбрасывать таблицу, как это делает Mysql Workbench при синхронизации модели с базой данных.

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;`
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

DROP TABLE TABLE_NAME;
TRUNCATE TABLE_NAME;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.