Jak obciąć tabelę ograniczoną kluczem obcym?

648

Dlaczego nie robi TRUNCATE na mygrouppracę? Mimo że ON DELETE CASCADE SETdostaję:

BŁĄD 1701 (42000): Nie można obciąć tabeli, do której odwołuje się ograniczenie klucza obcego ( mytest. instance, ODNIESIENIA instance_ibfk_1KLUCZA ZAGRANICZNEGO ( 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;
użytkownik391986
źródło

Odpowiedzi:

1000

Nie można TRUNCATEtabeli z zastosowanymi ograniczeniami FK ( TRUNCATEto nie to samo coDELETE ).

Aby obejść ten problem, użyj jednego z tych rozwiązań. Oba wiążą się z ryzykiem uszkodzenia integralności danych.

Opcja 1:

  1. Usuń ograniczenia
  2. Wykonać TRUNCATE
  3. Usuń ręcznie wiersze, które mają teraz odniesienia do nikąd
  4. Utwórz ograniczenia

Opcja 2: sugerowana przez użytkownika447951 w odpowiedzi

SET FOREIGN_KEY_CHECKS = 0; 
TRUNCATE table $table_name; 
SET FOREIGN_KEY_CHECKS = 1;
zerkms
źródło
46
@barjonah: w rzeczywistości może to złamać integralność danych (patrz stackoverflow.com/questions/5452760/... ). Tak więc to, co nazywasz „światłem” w prawdziwym świecie, jest uważane za złą praktykę. PS: dziękuję za opinię
Zerkms
1
Oto bardzo dobry sposób na znalezienie osieroconych kluczy obcych (przywrócenie integralności danych) http://stackoverflow.com/a/12085689/997776
SandorRacz
wyłączyć klucz obcy przed obcięciem jest również dobrym sposobem, zrobiłem to z sukcesem ze źródła: stackoverflow.com/questions/8641703/…
Dung
2
@Dung wyłącza sprawdzanie kluczy obcych jest dozwolone tylko w okresie programowania. Zrywa wszelkie istniejące relacje. zerkms ma 100% racji co do integralności danych. Nie możesz wyłączyć sprawdzania klucza obcego w działającej bazie danych, chyba że planujesz całkowicie ją opróżnić (lub przynajmniej wszystkie powiązane tabele)
NoobishPro
1
@Kamlesh to nie jest moje rozwiązanie, radziłem nie robić tego w barbarzyński sposób.
zerkms
1308

Tak, możesz:

SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE table1;
TRUNCATE table2;

SET FOREIGN_KEY_CHECKS = 1;

Dzięki tym instrukcjom ryzykujesz wpuszczeniem wierszy do tabel, które nie są zgodne z FOREIGN KEYograniczeniami.

użytkownik447951
źródło
30
czy musimy ustawić SET FOREIGN_KEY_CHECKS = 1; znowu potem?
vinc3m1
77
Nie, ty nie. Ustawienie obowiązuje tylko podczas połączenia. Gdy tylko rozłączysz się, przy następnym połączeniu zostanie ponownie ustawione na 1.
The Pellmeister
7
Nie dotyczy to zdarzenia „ON DELETE” w tabeli, do której się odwołuje, więc nie jest to pełna odpowiedź.
Omer Sabic
5
Jeśli używasz w PHPMYADMIN, działa to tylko wtedy, gdy używasz wszystkich transakcji w tym samym oknie SQL (oddzielonych znakiem a ;). Wynika to z faktu, że każde nowe wywołanie SQL WWW resetuje FOREIGN_KEY_CHECKSdo 1.
Sablefoste
1
Oto bardzo dobry sposób na znalezienie osieroconych kluczy obcych (przywrócenie integralności danych) w przypadku zainteresowania http://stackoverflow.com/a/12085689/997776
SandorRacz
173

Po prostu zrobiłbym to z:

DELETE FROM mytest.instance;
ALTER TABLE mytest.instance AUTO_INCREMENT = 1;
George Garchagudashvili
źródło
5
Mądry. Jeśli mimo wszystko chcesz usunąć wszystkie rekordy, równie dobrze możesz zresetować automatyczny przyrost.
winkbrace
6
To oczywiście najlepszy sposób, aby to zrobić. Bez ryzyka utraty ograniczeń, wystarczy zwykłe usunięcie. Warto zauważyć, że DELETEdziała wolniej niż TRUNCATE. Ale ponieważ ta czynność jest zwykle wykonywana rzadko, nie ma to znaczenia.
phil294
Jest to dobre, jeśli to wszystko, co chcesz zrobić, ale DELETEmoże być absolutnie brutalne, jeśli masz zbyt wiele wierszy - ponieważ uderza w dzienniki, a TRUNCATEpo prostu usuwa dane. Naprawdę zależy od przypadku użycia.
Jeff
1
kiedy używam instrukcji delete, zgłasza błąd 1175: Używasz bezpiecznego trybu aktualizacji, po prostu dodaj SET SQL_SAFE_UPDATES = 0; wtedy jest w porządku
tyan 20.04.16
Podczas korzystania z tego rozwiązania zgłasza error 1175: You are using safe update mode,...zmianę klauzuli usuwania, aby DELETE FROM mydb.mytable where id != 0było idealne.
Shihe Zhang,
17

możesz to zrobić

DELETE FROM `mytable` WHERE `id` > 0
Ali Sadran
źródło
1
Próbowałem, ale pojawił się następujący błąd: Kod błędu: 1142. Polecenie DELETE odmówiono użytkownikowi „root” @ „localhost” dla tabeli „mytable”
AAEM
lub po prostu USUŃ Zmytable
Miloslav Milo Janoušek
To nie zresetuje automatycznego przyrostu.
vivek_23,
13

Zgodnie z dokumentacją mysql , TRUNCATE nie może być stosowany w tabelach z relacjami klucza obcego. Nie ma pełnej alternatywnej AFAIK.

Usunięcie ograniczenia nadal nie wywołuje opcji ON DELETE i ON UPDATE. Jedyne rozwiązanie, jakie mogę wymyślić ATM, to:

  • usuń wszystkie wiersze, upuść klucze obce, obetnij, ponownie utwórz klucze
  • usuń wszystkie wiersze, zresetuj auto_increment (jeśli jest używany)

Wydaje się, że TRUNCATE w MySQL nie jest jeszcze pełną funkcją (nie wywołuje też wyzwalaczy). Zobacz komentarz

Omer Sabic
źródło
7
Uwaga na temat tego, że MySQL TRUNCATEjest niekompletny - obcinanie nie powinno wywoływać wyzwalaczy itp. Gdyby tak było, byłoby to tak samo jak DELETE! Jest niezależny od wiersza, dlatego nie może wykonywać operacji związanych z wierszami (takich jak wywoływanie wyzwalaczy lub sprawdzanie kluczy obcych). Działa w ten sam sposób w Oracle i Sql Server .
Simon MᶜKenzie
8

Łatwe, jeśli używasz phpMyAdmin.

Po prostu odznacz Enable foreign key checksopcję w SQLzakładce i uruchomTRUNCATE <TABLE_NAME>

wprowadź opis zdjęcia tutaj

Ajmal Salim
źródło
8

Podczas gdy zadawano to pytanie, nie wiedziałem o tym, ale teraz, jeśli używasz phpMyAdmin, możesz po prostu otworzyć bazę danych i wybrać tabele, które chcesz obciąć.

  • Na dole znajduje się lista rozwijana z wieloma opcjami. Otwórz i wybierz Emptyopcję pod nagłówkiem Delete data or table.
  • Nastąpi automatyczne przejście do następnej strony, na której znajduje się opcja w polu wyboru o nazwie Enable foreign key checks. Po prostu usuń zaznaczenie i naciśnij Yesprzycisk, a wybrane tabele zostaną obcięte.

Może wewnętrznie uruchamia zapytanie sugerowane w odpowiedzi user447951 , ale jest bardzo wygodne w użyciu z interfejsu phpMyAdmin.

Rolen Koh
źródło
7

Testowane na bazie danych MYSQL

Rozwiązanie 1:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;

Rozwiązanie 2:

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

To działa dla mnie. Mam nadzieję, że ci to pomoże. Dzięki, że zadałeś to pytanie.

Kamlesh
źródło
6

Odpowiedź jest rzeczywiście udzielona przez Zerkms , jak stwierdzono w Opcji 1 :

Opcja 1 : która nie stwarza ryzyka uszkodzenia integralności danych:

  1. Usuń ograniczenia
  2. Wykonaj TRUNCATE
  3. Usuń ręcznie wiersze, które mają teraz odniesienia do nikąd
  4. Utwórz ograniczenia

Trudna część polega na usuwaniu ograniczeń , więc chcę powiedzieć, jak to zrobić, na wypadek, gdyby ktoś musiał wiedzieć, jak to zrobić:

  1. Uruchom SHOW CREATE TABLE <Table Name>zapytanie, aby zobaczyć, jak nazywa się KLUCZ ZAGRANICZNY (czerwona ramka na obrazku poniżej):

    wprowadź opis zdjęcia tutaj

  2. Uruchom ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>. Spowoduje to usunięcie ograniczenia klucza obcego.

  3. Upuść powiązany Indeks (przez stronę struktury tabeli) i gotowe.

aby ponownie utworzyć klucze obce:

ALTER TABLE <Table Name>
ADD FOREIGN KEY (<Field Name>) REFERENCES <Foreign Table Name>(<Field Name>);
Pmpr
źródło
3

Wystarczy użyć CASCADE

TRUNCATE "products" RESTART IDENTITY CASCADE;

Ale bądź gotowy na usuwanie kaskadowe)

Alexus1024
źródło
3
OP oznaczył MySQL. Chociaż jest to poprawne w Postgresie, jest nieprawidłowe w MySQL.
Peter
1

Jeśli silnik bazy danych dla tabel różni się, pojawi się ten błąd, więc zmień je na InnoDB

ALTER TABLE my_table ENGINE = InnoDB;
sajad abbasi
źródło
0

Uzyskiwanie starego stanu sprawdzania klucza obcego i trybu sql to najlepszy sposób na obcinanie / upuszczanie tabeli, tak jak robią to Mysql Workbench podczas synchronizacji modelu z bazą danych.

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;
Vijay Arun
źródło