ไม่สามารถเปลี่ยนคอลัมน์ที่ใช้ในข้อ จำกัด คีย์ภายนอก


113

ฉันได้รับข้อผิดพลาดนี้ขณะพยายามแก้ไขตาราง

Error Code: 1833. Cannot change column 'person_id': used in a foreign key constraint 'fk_fav_food_person_id' of table 'table.favorite_food'

นี่คือข้อความสร้างตารางของฉันซึ่งทำงานได้สำเร็จ

CREATE TABLE favorite_food(
    person_id SMALLINT UNSIGNED,
    food VARCHAR(20),
    CONSTRAINT pk_favorite_food PRIMARY KEY(person_id,food),
    CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
    REFERENCES person (person_id)
);

จากนั้นฉันพยายามดำเนินการคำสั่งนี้และฉันได้รับข้อผิดพลาดข้างต้น

ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;

4
ตัวอย่างข้างต้นมาจากหนังสือ "Learning SQL, 2nd edition" ฉันหวังว่าผู้เขียน Alan Beaulieu จะทำการแก้ไข
Dmitry

คำตอบ:


127

ประเภทและคำจำกัดความของฟิลด์คีย์ต่างประเทศและการอ้างอิงต้องเท่ากัน ซึ่งหมายความว่า Foreign Key ของคุณไม่อนุญาตให้เปลี่ยนประเภทของฟิลด์ของคุณ

ทางออกหนึ่งคือ:

LOCK TABLES 
    favorite_food WRITE,
    person WRITE;

ALTER TABLE favorite_food
    DROP FOREIGN KEY fk_fav_food_person_id,
    MODIFY person_id SMALLINT UNSIGNED;

ตอนนี้คุณเปลี่ยน person_id ได้แล้ว

ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;

สร้างคีย์ต่างประเทศใหม่

ALTER TABLE favorite_food
    ADD CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
          REFERENCES person (person_id);

UNLOCK TABLES;

แก้ไข: เพิ่มการล็อกด้านบนขอบคุณสำหรับความคิดเห็น

คุณต้องไม่อนุญาตให้เขียนลงในฐานข้อมูลในขณะที่ดำเนินการนี้มิฉะนั้นคุณจะเสี่ยงต่อปัญหาความสมบูรณ์ของข้อมูล

ฉันได้เพิ่มการล็อกการเขียนไว้ด้านบนแล้ว

การเขียนแบบสอบถามทั้งหมดในเซสชันอื่นที่ไม่ใช่ของคุณเอง ( INSERT, UPDATE, DELETE) จะรอจนกว่าจะหมดเวลาหรือUNLOCK TABLES; ถูกดำเนินการ

http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html

แก้ไข 2: OP ขอคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับบรรทัด "ประเภทและคำจำกัดความของฟิลด์คีย์ต่างประเทศและการอ้างอิงต้องเท่ากันซึ่งหมายความว่าคีย์ต่างประเทศของคุณไม่อนุญาตให้เปลี่ยนประเภทของฟิลด์ของคุณ"

จากคู่มืออ้างอิง MySQL 5.5: FOREIGN KEY Constraints

คอลัมน์ที่ตรงกันในคีย์ภายนอกและคีย์ที่อ้างอิงต้องมีชนิดข้อมูลภายในที่คล้ายกันภายใน InnoDB เพื่อให้สามารถเปรียบเทียบได้โดยไม่ต้องแปลงประเภท ขนาดและเครื่องหมายของชนิดจำนวนเต็มต้องเหมือนกัน ความยาวของประเภทสตริงไม่จำเป็นต้องเหมือนกัน สำหรับคอลัมน์สตริงที่ไม่ใช่ไบนารี (อักขระ) ชุดอักขระและการจัดเรียงจะต้องเหมือนกัน


1
อย่าลืมใช้ธุรกรรมสำหรับสิ่งนี้ มิฉะนั้นฐานข้อมูลของคุณอาจเสียหาย
Francois Bourgeois

5
จุดดีน่าเสียดายที่ MySQL ไม่รองรับการทำธุรกรรมรอบงบ DDL ธุรกรรมที่เปิดจะถูกดำเนินการก่อนที่จะดำเนินการค้นหา DDL โปรดดูdev.mysql.com/doc/refman/5.5/en/implicit-commit.html
Michel Feldheim

2
คำสั่งที่ถูกต้องในการสร้างคีย์ต่างประเทศขึ้นใหม่จะเป็น: ALTER TALE favorite_food ADD CONTRAINT fk_fav_food_person_id FOREIGN KEY (person_id) REFERENCES person (id);
Felizardo

1
ทำไมคุณถึงแก้ไขperson_idทันทีหลังจากทิ้ง Foreign Key? ดูเหมือนว่าคุณไม่ได้เปลี่ยนแปลงอะไรเลยตั้งแต่เป็นไฟล์SMALLINT UNSIGNED.
Dennis Subachev

1
เราไม่รู้ว่ามันคืออะไรเนื่องจากเขาโพสต์โครงสร้างตารางอ้างอิงเท่านั้น Innodb มี int เป็นประเภทภายใน smallint ฯลฯ เป็นทางลัดเท่านั้น
Michel Feldheim

200

คุณสามารถปิดการตรวจสอบคีย์ต่างประเทศ:

SET FOREIGN_KEY_CHECKS = 0;

/* DO WHAT YOU NEED HERE */

SET FOREIGN_KEY_CHECKS = 1;

โปรดอย่าใช้สิ่งนี้ในการผลิตและมีการสำรองข้อมูล


1
ดูเหมือนจะเป็นวิธีการแก้ปัญหาที่ไม่ปลอดภัยมาก อาจทำให้สูญเสียความสมบูรณ์ของข้อมูลได้หรือไม่?
hrust

@Synaps - ใช่ถ้าคุณกำลังลบ / อัปเดต / แทรก การสูญหายของข้อมูลจะไม่เกิดขึ้นหากคุณเพิ่งแก้ไขตารางหรือเริ่มต้นฐานข้อมูลของคุณในทางกลับกันคุณควรตรวจสอบข้อมูลของคุณด้วยตนเอง (เนื่องจากคุณลบข้อ จำกัด )
Rafael Herscovici

2
โซลูชันนี้ยอดเยี่ยมและคุณสามารถใช้ในการผลิตได้หากคุณล็อกการเขียนโฆษณาก่อนที่จะแก้ไขข้อมูลของคุณจากนั้นจึงปลดล็อกเมื่อคุณทำเสร็จแล้ว การใช้ไฟล์ sql เพื่อทำการเปลี่ยนแปลงของคุณในระยะเวลาที่สั้นที่สุดจะดีกว่า
Francisco Zarabozo

ทางออกที่ดีสำหรับการปรับแต่งอย่างรวดเร็ว
Genaut

1
คุณไม่จำเป็นต้องล็อกตามที่SET FOREIGN_KEY_CHECKSกำหนดขอบเขตเซสชัน (เซสชันอื่น ๆ จะยังคงใช้ข้อ จำกัด FK) เหมาะสำหรับการเพิ่ม / ลบAUTO_INCREMENT(ซึ่งไม่ได้เปลี่ยนประเภทข้อมูลคอลัมน์จริง) แต่จะไม่ได้ผล หากคุณพยายามเปลี่ยนประเภทข้อมูลคอลัมน์เป็น "จริง" (เช่นจาก SMALLINT เป็น INT) เนื่องจากคุณจะได้รับความถูกต้อง150 FK constraint incorrectly formedเมื่อ mysql พยายามแทนที่ตารางเก่าด้วยตารางใหม่ ในกรณีนี้ให้ใช้คำตอบที่ยอมรับ
Xenos

-3

เมื่อคุณตั้งค่าคีย์ (หลักหรือต่างประเทศ) คุณกำลังตั้งข้อ จำกัด เกี่ยวกับวิธีการใช้งานซึ่งจะ จำกัด สิ่งที่คุณสามารถทำได้ หากคุณต้องการแก้ไขคอลัมน์จริงๆคุณสามารถสร้างตารางใหม่ได้โดยไม่มีข้อ จำกัด แม้ว่าฉันจะแนะนำให้ทำเช่นนั้นก็ตาม โดยทั่วไปหากคุณมีสถานการณ์ที่คุณต้องการทำบางสิ่งบางอย่าง แต่ถูกปิดกั้นด้วยข้อ จำกัด คุณควรแก้ไขได้ดีที่สุดโดยการเปลี่ยนสิ่งที่คุณต้องการทำแทนที่จะเป็นข้อ จำกัด


13
นี้เป็นเช่นช่วยเหลือคำตอบที่ไร้ประโยชน์!
ajmedway

3
@ajmedway จากนั้นคุณสามารถเขียนคำตอบที่เป็นประโยชน์โดยไม่โทษผู้ใช้รายอื่น
ฉันเป็นคนโง่ที่สุด

2
@IamtheMostStupidPerson มันดีกว่าการลงคะแนนโดยไม่มีความคิดเห็น อย่างน้อยผู้แสดงความคิดเห็นก็สามารถเดาได้ว่าเหตุใดจึงมีการโหวตลดลง คำตอบทั่วไปเช่น "ดีกว่าปลอดภัยกว่าขอโทษ" ไม่มีประโยชน์
Csaba Toth
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.