วิธีตัดทอนตาราง foreign foreign ที่มีข้อ จำกัด


648

ทำไมไม่ตัดในmygroupการทำงาน? แม้ว่าฉันจะON DELETE CASCADE SETได้รับ:

ข้อผิดพลาด 1701 (42000): ไม่สามารถตัดทอนตารางอ้างอิงในข้อ จำกัด ที่สำคัญต่างประเทศ ( mytest. instanceข้อ จำกัดinstance_ibfk_1ต่างประเทศ (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;

คำตอบ:


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

ปิดการใช้งาน foreign key ก่อนที่จะถูกตัดทอนเป็นวิธีที่ดีฉันทำได้ด้วยความสำเร็จจากแหล่งที่มา: stackoverflow.com/questions/8641703/…
Dung

2
@Dung ปิดการใช้งานการตรวจสอบกุญแจต่างประเทศได้รับอนุญาตในช่วงการพัฒนาเท่านั้น มันทำลายความสัมพันธ์ที่มีอยู่ 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
The Pellmeister

7
นี่ไม่ได้ใช้เหตุการณ์ 'ON DELETE' ในตารางอ้างอิงดังนั้นนี่ไม่ใช่คำตอบที่สมบูรณ์
โอเมอร์ซาบิ

5
หากใช้ใน PHPMYADMIN จะใช้งานได้ก็ต่อเมื่อคุณใช้ธุรกรรมทั้งหมดในหน้าต่าง SQL เดียวกัน (คั่นด้วย a ;) นี่เป็นเพราะการเรียก 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เพียงดึงข้อมูลออก ขึ้นอยู่กับกรณีการใช้งานจริง ๆ
Jeff

1
เมื่อฉันใช้คำสั่งลบมันรายงานข้อผิดพลาด 1175: คุณกำลังใช้โหมดการอัพเดทที่ปลอดภัยเพียงเพิ่ม SET SQL_SAFE_UPDATES = 0; แล้วก็ปรับ
TYAN

เมื่อใช้โซลูชันนี้จะรายงานerror 1175: You are using safe update mode,...การเปลี่ยนแปลงคำสั่งลบเพื่อให้DELETE FROM mydb.mytable where id != 0สมบูรณ์
Shihe Zhang

17

คุณทำได้

DELETE FROM `mytable` WHERE `id` > 0

1
ฉันพยายามมัน bur ข้อผิดพลาดต่อไปนี้ปรากฏขึ้น: รหัสข้อผิดพลาด: 1142. คำสั่ง DELETE ปฏิเสธที่จะให้ผู้ใช้ 'root' @ 'localhost' สำหรับตาราง 'mytable'
AAEM

หรือเพียงแค่ลบจากmytable
Miloslav Milo Janoušek

สิ่งนี้จะไม่รีเซ็ตการเพิ่มอัตโนมัติ
vivek_23

13

ตามเอกสารของ mysql , TRUNCATE ไม่สามารถใช้กับตารางที่มีความสัมพันธ์กับ foreign key ไม่มี AFAIK ทางเลือกที่สมบูรณ์

การทิ้งความขัดแย้งยังคงไม่เรียกใช้ ON DELETE และ ON UPDATE ทางออกเดียวที่ฉันสามารถคิด ATM ก็คือ:

  • ลบทุกแถววางกุญแจต่างประเทศตัดทอนสร้างคีย์ใหม่
  • ลบทุกแถวรีเซ็ต auto_increment (หากใช้)

ดูเหมือนว่า TRUNCATE ใน MySQL ยังไม่สมบูรณ์ (ยังไม่เรียกใช้ทริกเกอร์) ดูความคิดเห็น


7
หมายเหตุในประเด็นของคุณเกี่ยวกับของ MySQL TRUNCATEเป็นที่ไม่สมบูรณ์ - ตัดไม่ควรที่จะเรียกทริกเกอร์ ฯลฯ หากมันได้มันก็จะเป็นเช่นเดียวDELETE! มันเป็นผู้ไม่เชื่อเรื่องพระเจ้าแถวจึงไม่สามารถทำการดำเนินการที่เกี่ยวข้องกับแถว (เช่นการเรียกทริกเกอร์หรือตรวจสอบกุญแจต่างประเทศ) มันทำงานในลักษณะเดียวกันในออราเคิลและโปรแกรม Sql Server
Simon MᶜKenzie


8

ในขณะที่คำถามนี้ถูกถามฉันไม่ทราบเกี่ยวกับมัน แต่ตอนนี้ถ้าคุณใช้ phpMyAdmin คุณสามารถเปิดฐานข้อมูลและเลือกตารางที่คุณต้องการตัดทอน

  • ที่ด้านล่างมีรายการแบบหล่นลงพร้อมตัวเลือกมากมาย เปิดและเลือกตัวเลือกภายใต้หัวข้อEmptyDelete 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>แบบสอบถามเพื่อดูสิ่งที่อยู่ของคุณต่างประเทศ 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
OP ติดแท็ก 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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.