MySQL Yabancı anahtar kısıtlamasında gerekli dizin bırakılamıyor


156

Bir sütun eklemek için mevcut veritabanımı ALTER gerekir. Sonuç olarak, bu yeni sütunu kapsayacak şekilde BENZERSİZ alanını güncellemek istiyorum. Geçerli dizini kaldırmaya çalışıyorum ama hatayı almaya devam ediyorumMySQL Cannot drop index needed in a foreign key constraint

CREATE TABLE mytable_a (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;

CREATE TABLE mytable_b (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;

CREATE TABLE mytable_c (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;


CREATE TABLE `mytable` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `AID` tinyint(5) NOT NULL,
  `BID` tinyint(5) NOT NULL,
  `CID` tinyint(5) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `AID` (`AID`,`BID`,`CID`),
  KEY `BID` (`BID`),
  KEY `CID` (`CID`),
  CONSTRAINT `mytable_ibfk_1` FOREIGN KEY (`AID`) REFERENCES `mytable_a` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `mytable_ibfk_2` FOREIGN KEY (`BID`) REFERENCES `mytable_b` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `mytable_ibfk_3` FOREIGN KEY (`CID`) REFERENCES `mytable_c` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB;




mysql> ALTER TABLE mytable DROP INDEX AID;
ERROR 1553 (HY000): Cannot drop index 'AID': needed in a foreign key constraint

Varsayarsak UNIQUE KEY AIDmytable üzerinde?
Mike Purcell

Yanıtlar:


228

Yabancı anahtarı bırakmalısın. MySQL'deki yabancı anahtarlar otomatik olarak tablo üzerinde bir dizin oluşturur ( Konuyla ilgili bir SO Sorusu vardı).

ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1 ; 

12
Dizini bıraktıktan sonra tekrar eklemek isteyebilirsiniz: ALTER TABLE mytableSIKIŞMA mytable_ibfk_1YABANCI ANAHTARI ( AID) REFERANSLAR mytable_a( ID) ON SİLİNDİR;
laffuste

8
Bu harika, ama FOREIGN KEYkısıtlamam isimsizse ne yapabilirim ?
Pehat

@ Cevabımı aşağıda kontrol edin stackoverflow.com/a/54145440/2305119
thyzz

1
Not: Yabancı anahtar o kadar açık olmayabilir. Bir tablo ve sütunla ilgili tüm yabancı anahtarları bulmak için şu sorguyu kullanabilirsiniz: dba.stackexchange.com/questions/102371/…
charlax

84

Aşama 1

Yabancı anahtarı listele (bunun dizin adından farklı olduğunu unutmayın)

SHOW CREATE TABLE  <Table Name>

Sonuç size yabancı anahtar adını gösterecektir.

Biçim:

CONSTRAINT `FOREIGN_KEY_NAME` FOREIGN KEY (`FOREIGN_KEY_COLUMN`) REFERENCES `FOREIGN_KEY_TABLE` (`id`),

Adım 2

Bırakma (Yabancı / birincil / anahtar) Tuşu

ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign key name>

Aşama 3

Dizini bırakın.


18

Bunu yapabileceğinizi kastediyorsanız:

CREATE TABLE mytable_d (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;


ALTER TABLE mytable
ADD COLUMN DID tinyint(5) NOT NULL,
ADD CONSTRAINT mytable_ibfk_4 
      FOREIGN KEY (DID) 
        REFERENCES mytable_d (ID) ON DELETE CASCADE;

 > OK.

Ama sonra:

ALTER TABLE mytable
DROP KEY AID ;

hata veriyor.


Dizini bırakabilir ve tek bir ALTER TABLEifadede yenisini oluşturabilirsiniz:

ALTER TABLE mytable
DROP KEY AID ,
ADD UNIQUE KEY AID (AID, BID, CID, DID);

8

Yabancı anahtar alanında bir dizin olması gerektiğinden, 'AID' alanında basit bir dizin oluşturabilirsiniz

CREATE INDEX aid_index ON mytable (AID);

ve ancak daha sonra 'AID' benzersiz dizinini bırakın

ALTER TABLE mytable DROP INDEX AID;

7

Yabancı anahtar her zaman bir dizin gerektirir. Bir dizin zorlama olmadan, referans tablosuna eklenen veya güncellenen her anahtar için başvurulan tabloda tam tablo taraması gerekir. Ve bunun kabul edilemez bir performans etkisi olacaktır. Bunun aşağıdaki 2 sonucu vardır:

  • Yabancı anahtar oluştururken, veritabanı bir dizin olup olmadığını kontrol eder. Değilse bir dizin oluşturulacaktır. Varsayılan olarak, sınırlama ile aynı ada sahip olacaktır.
  • Yabancı anahtar için kullanılabilecek yalnızca bir dizin olduğunda, bu anahtar bırakılamaz. Gerçekten düşürmek istemiyorsanız, ya yabancı anahtar kısıtlamasını düşürmeniz ya da önce başka bir dizin oluşturmanız gerekir.

1
diğer cevapların eksik olduğu teorisine sahipsiniz.
Dennis

1
Dolayısıyla: Bileşik benzersiz bir dizininiz varsa (benzersiz bir kısıtlamada birden çok sütun), A ve B için bir dizininiz yoksa benzersiz AB anahtarını kaldıramazsınız. Bu hatayı alırsanız, başka bir tablo A sütununun dizinini veya B'yi seçin ve AB benzersizini güvenle kaldırabilmeniz için bunları eklemeniz gerekir.
Robin De Schepper

@RobinDeSchepper İyi açıklama. Bileşik benzersiz dizinleri kullanırken, alanların sırası benzersiz dizin için önemli değildir, ancak yabancı anahtar için önemli olabilir. A, B üzerindeki benzersiz bir dizin A'daki bir yabancı anahtar tarafından kullanılabilir, ancak B'deki bir yabancı anahtar tarafından kullanılamaz
Stefan Mondelaers

2

Sanırım bu endeksi bırakmak için kolay bir yol.

set FOREIGN_KEY_CHECKS=1;

ALTER TABLE mytable DROP INDEX AID;

set FOREIGN_KEY_CHECKS=0;

2
Kontrolleri etkinleştirme ve devre dışı bırakma konusunda bilgi alışverişinde bulunduğunuzu düşünüyorum. En üstte beklerim FOREIGN_KEY_CHEK=0ve sonunda FOREIGN_KEY_CHEK=1.
romor

0

Benim durumumda yabancı anahtarı düşürdüm ve hala indeksi düşüremedim. Çünkü aynı tarlada bu tablonun yabancı anahtarı olan başka bir tablonun olmasıydı. Yabancı anahtarı diğer masaya bıraktıktan sonra dizinleri bu masaya bırakabilirim.


0

Yabancı anahtar sütunu bırakmak istiyorsanız (cadı bir kısıtlama tutar) önce yabancı anahtarı düşürmeniz, ardından sütunu düşürmeniz gerekir, yabancı anahtarı düşürdüğünüzde, tüm adı geçmeniz gerekmez, sadece Yabancı anahtarı geçmeniz gerekir sütun adı:

$table->dropForeign(['currency_id']);
$table->dropColumn('currency_id');

hakkında daha fazla bilgi:

https://laravel.com/docs/6.x/migrations#foreign-key-constraints

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.