Làm thế nào để cắt một bảng ràng buộc khóa ngoại?


648

Tại sao không phải là TRUNCATE trong mygroupcông việc? Mặc dù tôi có ON DELETE CASCADE SETtôi nhận được:

LRI 1701 (42000): Không thể cắt một bảng được tham chiếu trong một ràng buộc khóa ngoài ( mytest. instance, CONSTRAINT instance_ibfk_1FOREIGN KEY ( GroupID) TÀI LIỆU THAM KHẢO 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;

Câu trả lời:


1001

Bạn không thể TRUNCATEmột bảng có các ràng buộc FK được áp dụng trên nó ( TRUNCATEkhông giống như DELETE).

Để giải quyết vấn đề này, hãy sử dụng một trong những giải pháp này. Cả hai đều có nguy cơ làm hỏng tính toàn vẹn dữ liệu.

Lựa chọn 1:

  1. Xóa các ràng buộc
  2. Biểu diễn TRUNCATE
  3. Xóa thủ công các hàng hiện có tham chiếu đến hư không
  4. Tạo các ràng buộc

Tùy chọn 2: được đề xuất bởi user447951 trong câu trả lời của họ

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

46
@barjonah: thực ra, nó có thể phá vỡ tính toàn vẹn dữ liệu (xem stackoverflow.com/questions/5452760/ mẹo ). Vì vậy, những gì bạn gọi là "ánh sáng" trong thế giới thực được coi là một thực tiễn xấu. PS: cảm ơn vì đã tải xuống
zerkms

1
Đây là một cách rất tốt để tìm các khóa ngoại mồ côi (khôi phục tính toàn vẹn dữ liệu) http://stackoverflow.com/a/12085689/997776
SandorRacz 4/215

vô hiệu hóa khóa ngoại trước khi cắt ngắn cũng là một cách tốt, tôi đã làm điều đó với thành công từ nguồn: stackoverflow.com/questions/8641703/iêu
Dung

2
@Dung vô hiệu hóa kiểm tra khóa nước ngoài chỉ được phép trong giai đoạn phát triển. Nó phá vỡ mọi mối quan hệ hiện có. zerkms đúng 100% về tính toàn vẹn dữ liệu. Bạn không thể vô hiệu hóa kiểm tra khóa ngoại trên cơ sở dữ liệu đang hoạt động trừ khi bạn dự định làm trống hoàn toàn (hoặc ít nhất là tất cả các bảng có liên quan)
NoobishPro

1
@Kam Meat không phải là giải pháp của tôi, tôi khuyên không nên làm theo cách dã man đó.
zerkms

1308

Có bạn có thể:

SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE table1;
TRUNCATE table2;

SET FOREIGN_KEY_CHECKS = 1;

Với các tuyên bố này, bạn có nguy cơ cho phép các hàng vào các bảng không tuân thủ các FOREIGN KEYràng buộc.


30
chúng ta có phải đặt SET FOREIGN_KEY_CHECKS = 1; lại sau đó?
vinc3m1

77
Không, bạn không. Cài đặt chỉ có hiệu lực trong khi kết nối. Ngay sau khi bạn ngắt kết nối, kết nối tiếp theo sẽ được đặt lại thành 1.
Pellmeister

7
Điều này không áp dụng sự kiện 'BẬT XÓA' trong bảng được tham chiếu, vì vậy đây không phải là câu trả lời hoàn chỉnh.
Omer Sabic

5
Nếu sử dụng trong PHPMYADMIN, điều này chỉ hoạt động nếu bạn sử dụng tất cả các giao dịch trong cùng một cửa sổ SQL (cách nhau bởi a ;). Điều này là do mỗi lệnh gọi SQL web mới sẽ đặt lại FOREIGN_KEY_CHECKSthành 1.
Sablefoste

1
Đây là một cách rất tốt để tìm các khóa ngoại mồ côi (khôi phục tính toàn vẹn dữ liệu) trong trường hợp bạn quan tâm http://stackoverflow.com/a/12085689/997776
SandorRacz

173

Tôi chỉ đơn giản sẽ làm điều đó với:

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

5
Thông minh. Khi bạn muốn xóa tất cả các bản ghi, bạn cũng có thể đặt lại mức tăng tự động.
nháy mắt

6
Đây rõ ràng là cách tốt nhất để làm điều đó. Không có nguy cơ mất các ràng buộc, chỉ cần xóa đơn giản. Đáng chú ý là hoạt động DELETEchậm hơn TRUNCATE. Nhưng vì hành động này thường chỉ được thực hiện hiếm khi, điều này không quan trọng.
phil294

Điều này là tốt nếu đó là tất cả những gì bạn muốn làm, nhưng DELETEcó thể rất tàn bạo nếu bạn có quá nhiều hàng - vì nó chạm vào nhật ký, trong khi TRUNCATEchỉ cần xé dữ liệu ra. Thực sự phụ thuộc vào trường hợp sử dụng.
Jeff

1
Khi tôi đang sử dụng câu lệnh xóa, nó báo lỗi 1175: Bạn đang sử dụng chế độ cập nhật an toàn, chỉ cần thêm SET SQL_SAFE_UPDATE = 0; vậy thì tốt rồi
tyan

Khi sử dụng giải pháp này, nó báo cáo error 1175: You are using safe update mode,...thay đổi mệnh đề xóa để DELETE FROM mydb.mytable where id != 0làm cho nó hoàn hảo.
Shihe Zhang

17

bạn có thể làm

DELETE FROM `mytable` WHERE `id` > 0

1
Tôi đã thử nó, lỗi sau xuất hiện: Mã lỗi: 1142. Lệnh DELETE bị từ chối đối với người dùng 'root' @ 'localhost' cho bảng 'mytable'
AAEM

hoặc chỉ XÓA TỪmytable
Miloslav Milo Janoušek

Điều này sẽ không thiết lập lại sự gia tăng tự động.
vivek_23

13

Theo tài liệu mysql , TRUNCATE không thể được sử dụng trên các bảng có mối quan hệ khóa ngoài. Không có AFAIK thay thế hoàn toàn.

Việc bỏ các điều khoản này vẫn không gọi BẬT XÓA và CẬP NHẬT. Giải pháp duy nhất mà ATM tôi có thể nghĩ đến là:

  • xóa tất cả các hàng, thả các khóa ngoại, cắt ngắn, tạo lại các khóa
  • xóa tất cả các hàng, đặt lại auto_increment (nếu được sử dụng)

Có vẻ như TRUNCATE trong MySQL chưa phải là một tính năng hoàn chỉnh (nó cũng không gọi trình kích hoạt). Xem bình luận


7
Một lưu ý về quan điểm của bạn về việc MySQL TRUNCATEchưa hoàn thiện - cắt ngắn không được yêu cầu kích hoạt, v.v. Nếu có, nó sẽ giống như DELETE! Đó là bất khả tri hàng, do đó nó không thể thực hiện các hoạt động liên quan đến hàng (như gọi trình kích hoạt hoặc kiểm tra khóa ngoại). Nó hoạt động theo cùng một cách trong OracleSql Server .
Simon MᶜKenzie

8

Dễ dàng nếu bạn đang sử dụng phpMyAdmin.

Chỉ cần bỏ Enable foreign key checkschọn tùy chọn trong SQLtab và chạyTRUNCATE <TABLE_NAME>

nhập mô tả hình ảnh ở đây


8

Trong khi câu hỏi này được hỏi tôi không biết về nó, nhưng bây giờ nếu bạn sử dụng phpMyAdmin, bạn có thể chỉ cần mở cơ sở dữ liệu và chọn (các) bảng bạn muốn cắt bớt.

  • Ở phía dưới có một thả xuống với nhiều tùy chọn. Mở nó và chọn Emptytùy chọn dưới tiêu đề Delete data or table.
  • Nó tự động đưa bạn đến trang tiếp theo, nơi có một tùy chọn trong hộp kiểm được gọi Enable foreign key checks. Chỉ cần bỏ chọn nó và nhấn Yesnút và (các) bảng đã chọn sẽ bị cắt ngắn.

Có thể bên trong nó chạy truy vấn được đề xuất trong câu trả lời của user447951 , nhưng nó rất thuận tiện để sử dụng từ giao diện phpMyAdmin.


7

Đã thử nghiệm trên cơ sở dữ liệu MYSQL

Giải pháp 1:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;

Giải pháp 2:

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

Điều này làm việc cho tôi. Tôi hy vọng, điều này cũng sẽ giúp bạn. Cảm ơn đã hỏi câu hỏi này.


6

Câu trả lời thực sự là câu trả lời được cung cấp bởi zerkms , như đã nêu trong Phương án 1 :

Tùy chọn 1 : không có nguy cơ làm hỏng tính toàn vẹn dữ liệu:

  1. Xóa các ràng buộc
  2. Thực hiện TRUNCATE
  3. Xóa thủ công các hàng hiện có tham chiếu đến hư không
  4. Tạo các ràng buộc

Phần khó khăn là Loại bỏ các ràng buộc , vì vậy tôi muốn cho bạn biết làm thế nào, trong trường hợp ai đó cần biết cách làm điều đó:

  1. Chạy SHOW CREATE TABLE <Table Name>truy vấn để xem tên FOREIGN KEY của bạn là gì (Khung màu đỏ trong hình bên dưới):

    nhập mô tả hình ảnh ở đây

  2. Chạy đi ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>. Điều này sẽ loại bỏ các ràng buộc khóa ngoại.

  3. Bỏ Chỉ mục liên quan (thông qua trang cấu trúc bảng) và bạn đã hoàn thành.

để tạo lại khóa ngoại:

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

3

Chỉ cần sử dụng CASCADE

TRUNCATE "products" RESTART IDENTITY CASCADE;

Nhưng hãy sẵn sàng để xóa tầng)


3
OP được gắn thẻ MySQL. Mặc dù điều này là hợp lệ trong Postgres, nhưng nó không chính xác trong MySQL.
Peter

1

Nếu công cụ cơ sở dữ liệu cho các bảng khác nhau, bạn sẽ gặp lỗi này, vì vậy hãy thay đổi chúng thành InnoDB

ALTER TABLE my_table ENGINE = InnoDB;

0

Lấy trạng thái kiểm tra khóa ngoại cũ và chế độ sql là cách tốt nhất để cắt / Thả bảng như Mysql Workbench làm trong khi đồng bộ hóa mô hình với cơ sở dữ liệu.

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.