Як урізати таблицю з обмеженим зовнішнім ключем?


648

Чому не TRUNCATE на mygroupроботі? Незважаючи на те, що я маю ON DELETE CASCADE SET:

ПОМИЛКА 1701 (42000): Неможливо урізати таблицю, на яку посилається обмеження іноземного ключа ( mytest. instance, КОНТРОЛЬНИЙ instance_ibfk_1ІНТЕРНЕТ КЛЮЧ ( 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;

Відповіді:


1000

Ви не можете TRUNCATEвикористовувати таблицю, на якій застосовано обмеження FK ( TRUNCATEне те саме, що DELETE).

Щоб вирішити це, використовуйте будь-яке з цих рішень. Обидва є ризиком пошкодження цілісності даних.

Варіант 1:

  1. Усуньте обмеження
  2. Виконайте TRUNCATE
  3. Видаліть вручну рядки, на які ніде немає посилань
  4. Створюйте обмеження

Варіант 2: запропонований user447951 в своїй відповіді

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/…
гній

2
@ Відключення перевірки зовнішніх ключів дозволено лише в період розробки. Це розриває будь-які існуючі відносини. zerkms має 100% право щодо цілісності даних. Ви не можете відключити перевірку зовнішніх ключів на робочій базі даних, якщо ви не плануєте її повністю випорожнити (або принаймні всі пов'язані таблиці)
NoobishPro

1
@Kamlesh це не моє рішення, я радив не робити це варварським шляхом.
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
Це не стосується події "УВІДКЛЮЧИТИ" у посилальній таблиці, тому це не є повною відповіддю.
Омер Сабіч

5
Якщо використовується в PHPMYADMIN, це працює лише в тому випадку, якщо ви використовуєте всі транзакції в одному вікні SQL (розділені а ;). Це тому, що кожен свіжий виклик веб-SQL скидає значення FOREIGN_KEY_CHECKS1.
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; тоді це добре
tyan

Під час використання цього рішення він повідомляє про error 1175: You are using safe update mode,...застереження про зміни, щоб 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 не існує.

Скасування контракту все ще не викликає ВІДКЛЮЧЕННЯ та НА ОНОВЛЕННЯ. Єдине рішення, про яке я можу придумати банкомат, це:

  • видалити всі рядки, скинути іноземні ключі, усікати, відтворити ключі
  • видалити всі рядки, скинути auto_increment (якщо використовується)

Здається, TRUNCATE в MySQL ще не є повною функцією (вона також не викликає тригери). Дивіться коментар


7
Зауваження щодо вашої точки зору того, що MySQL TRUNCATEє неповним - усікання не повинно викликати тригери тощо. Якби це було, це було б точно так само, як DELETE! Це рядок-агностик, отже, він не може виконувати пов'язані з рядками операції (наприклад, викликати тригери або вивчити сторонні ключі). Він працює аналогічно в Oracle і Sql Server .
Simon MᶜKenzie

8

Легко, якщо ви використовуєте phpMyAdmin.

Просто зніміть Enable foreign key checksпрапорець у SQLвкладці та запустітьTRUNCATE <TABLE_NAME>

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


8

Хоча це запитання було задано, я про це не знав, але тепер, якщо ви використовуєте phpMyAdmin, ви можете просто відкрити базу даних і вибрати таблицю, яку ви хочете усікати.

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

Можливо, він внутрішньо запускає запит, запропонований у відповіді user447951 , але це дуже зручно використовувати з інтерфейсу phpMyAdmin.


7

Тестовано на базі даних 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>запит, щоб побачити, що з вашим ім'ям ІНОЗЕМНИЙ КЛЮЧ (Червона рамка внизу зображення):

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

  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

Просто використовуйте CASCADE

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.