Yabancı anahtar kısıtlamasında kullanılan sütun değiştirilemez


111

Masamı değiştirmeye çalışırken bu hatayı aldım.

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

İşte başarıyla çalışan CREATE TABLE STATEMENT.

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)
);

Sonra bu ifadeyi çalıştırmayı denedim ve yukarıdaki hatayı aldım.

ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;

4
Yukarıdaki örnek "SQL Öğrenimi, 2. baskı" kitabındandır. Umarım yazar Alan Beaulieu düzeltmeler yapar.
Dmitry

Yanıtlar:


126

Yabancı anahtar alanı ve referansın türü ve tanımı eşit olmalıdır. Bu, yabancı anahtarınızın alanınızın türünü değiştirmeye izin vermediği anlamına gelir.

Çözümlerden biri şudur:

LOCK TABLES 
    favorite_food WRITE,
    person WRITE;

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

Artık person_id kimliğinizi değiştirebilirsiniz

ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;

yabancı anahtarı yeniden oluştur

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

UNLOCK TABLES;

DÜZENLEME: Yorumlar sayesinde yukarıya kilitler eklendi

Bunu yaparken veritabanına yazmaya izin vermemelisiniz, aksi takdirde veri bütünlüğü sorunları yaşarsınız.

Yukarıya bir yazma kilidi ekledim

Kendi oturumunuz dışındaki herhangi bir oturumdaki tüm yazma sorguları ( INSERT, UPDATE, DELETE) zaman aşımına kadar bekleyecektir veya UNLOCK TABLES; Idam edildi

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

DÜZENLEME 2: OP, "Yabancı anahtar alanının türü ve tanımı ile referansın eşit olması gerekir. Bu, yabancı anahtarınızın alanınızın türünü değiştirmeye izin vermediği anlamına gelir." Satırının daha ayrıntılı bir açıklamasını istedi.

Gönderen YABANCI ANAHTAR Kısıtlar: 5.5 Referans Kılavuzu MySQL

Yabancı anahtardaki ve başvurulan anahtardaki karşılık gelen sütunlar, InnoDB içinde benzer dahili veri türlerine sahip olmalıdır, böylece tür dönüşümü olmadan karşılaştırılabilirler. Tam sayı türlerinin boyutu ve işareti aynı olmalıdır. Dize türlerinin uzunluğunun aynı olması gerekmez. İkili olmayan (karakter) dizgi sütunları için, karakter seti ve harmanlama aynı olmalıdır.


1
Bunun için bir işlem kullanmayı unutmayın. Aksi takdirde veritabanınız bozulabilir.
Francois Bourgeois

5
İyi bir nokta, ne yazık ki MySQL, DDL ifadeleri etrafındaki işlemleri desteklemiyor. Açık işlemler, bir DDL sorgusu yürütülmeden önce gerçekleştirilir bkz. Dev.mysql.com/doc/refman/5.5/en/implicit-commit.html
Michel Feldheim

2
Bir yabancı anahtarı yeniden oluşturmak için doğru ifade şöyle olacaktır: ALTER TALE favourite_food KONTRAINT EKLE fk_fav_food_person_id YABANCI ANAHTAR (kişi_kimliği) REFERENCES kişi (id);
Felizardo

1
person_idYabancı anahtarı bıraktıktan hemen sonra neden değişiklik yapıyorsunuz ? Görünüşe göre zaten bir olduğu için hiçbir şeyi değiştirmemişsin SMALLINT UNSIGNED.
Dennis Subachev

1
Sadece referans tablosu yapısını gönderdiği için ne olduğunu bilmiyoruz. Innodb, dahili tür olarak int'e sahiptir, smallint vb. Yalnızca kısayollardır
Michel Feldheim

198

Yabancı anahtar kontrollerini kapatabilirsiniz:

SET FOREIGN_KEY_CHECKS = 0;

/* DO WHAT YOU NEED HERE */

SET FOREIGN_KEY_CHECKS = 1;

Lütfen bunu üretimde KULLANMADIĞINIZDAN ve bir yedeğiniz olduğundan emin olun.


1
Çok güvensiz bir çözüm gibi görünüyor. Veri bütünlüğü kaybına neden olabilir mi?
hrust

@Synaps - siliyorsanız / güncelliyorsanız / ekliyorsanız evet olabilir. Sadece bir tabloyu değiştiriyorsanız veya veri
tabanınızı yerleştiriyorsanız

2
Bu çözüm harikadır ve verilerinizi değiştirmeden önce yazma kilitleri verirseniz ve işiniz bittiğinde kilidi açarsanız bunu üretimde kullanabilirsiniz. Değişikliklerinizi mümkün olan en kısa sürede yapmak için bir sql dosyası kullanmak daha da iyi olacaktır.
Francisco Zarabozo

Hızlı düzenlemeler için iyi çözüm
Genaut

1
SET FOREIGN_KEY_CHECKSOturum kapsamlı olduğu gibi bir kilide ihtiyacınız yoktur (diğer oturumlarda hala FK kısıtlaması uygulanacaktır). Eklemek / kaldırmak için mükemmeldir AUTO_INCREMENT(bu, gerçek sütun veri türünü değiştirmez), ancak sütun veri türünü "gerçek" için değiştirmeye çalışırsanız (örneğin, SMALLINT'den INT'ye) çalışmaz , 150 FK constraint incorrectly formedçünkü mysql eski tabloyu yenisiyle değiştirmeye çalışır. Böyle bir durumda kabul edilen cevabı kullanın.
Xenos

-3

Anahtarları (birincil veya yabancı) belirlediğinizde, bunların nasıl kullanılacağına dair kısıtlamalar koyarsınız ve bu da onlarla neler yapabileceğinizi sınırlar. Sütunu gerçekten değiştirmek istiyorsanız, buna karşı tavsiye etmeme rağmen tabloyu kısıtlamalar olmadan yeniden oluşturabilirsiniz. Genel olarak konuşursak, bir şey yapmak istediğiniz bir durum varsa, ancak bu bir kısıtlama tarafından engellenmişse, en iyi çözüm, kısıtlama yerine yapmak istediğiniz şeyi değiştirerek çözülür.


12
Bu BÖYLE , yararsız, yararsız bir cevap!
ajmedway

3
@ajmedway O halde diğer kullanıcıları suçlamadan faydalı bir cevap yazabilirsiniz
Ben En Aptal

2
@IamtheMostStupidPerson Yorum yapmadan olumsuz oy vermekten çok daha iyi. En azından yorumcu neden olumsuz oy kullandığını tahmin edebilir. "Güvende ol özür dilerim" gibi genel yanıtlar işe yaramaz.
Csaba Toth
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.