简体   繁体   中英

Why is MySQL not properly naming my foreign key?

Please consider the following SQL code that I run in MySQL 8.0.22 (in an InnoDB database):

CREATE TABLE `person` (
  `person_id` smallint unsigned NOT NULL AUTO_INCREMENT, 
  `name` varchar(128) NOT NULL,
  PRIMARY KEY (`person_id`)
);

CREATE TABLE `pet` (
  `pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  PRIMARY KEY (`pet_id`)
);

ALTER TABLE `pet`
  ADD COLUMN `owner_id` smallint unsigned;

ALTER TABLE `pet`
  ADD CONSTRAINT `fk_pet_person`
  FOREIGN KEY `idx_fk_pet_person` (`owner_id`)
  REFERENCES `person` (`person_id`);

SHOW CREATE TABLE pet;

The output of SHOW CREATE TABLE pet is:

CREATE TABLE `pet` (
  `pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `owner_id` smallint unsigned DEFAULT NULL,
  PRIMARY KEY (`pet_id`),
  KEY `fk_pet_person` (`owner_id`),
  CONSTRAINT `fk_pet_person` FOREIGN KEY (`owner_id`) REFERENCES `person` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

In the output above, why is the KEY named fk_pet_person when I specified its name as idx_fk_pet_person in my ALTER TABLE command? How can I get it to be named so?

You are confusing the FOREIGN KEY and the INDEX that makes it work. Pay attention - there is NO expression name (which looks like an index definition but is not) in the constraint definition displayed in your code.

When there is no suitable index for the constraint to work, then this index is auto-created, and the constraint name is used as the index name. If a suitable index exists, then auto-creation does not occur.

If you want the index to have a defined name then you must create this index in a separate ALTER TABLE (sub)statement before the constraint creation:

ALTER TABLE `pet`
  ADD KEY `idx_fk_pet_person` (`owner_id`),
  ADD CONSTRAINT `fk_pet_person`
  FOREIGN KEY (`owner_id`)
  REFERENCES `person` (`person_id`);

or

ALTER TABLE `pet`
  ADD KEY `idx_fk_pet_person` (`owner_id`);

ALTER TABLE `pet`
  ADD CONSTRAINT `fk_pet_person`
  FOREIGN KEY (`owner_id`)
  REFERENCES `person` (`person_id`);

DEMO

MySQL documentation specifies this syntax for creating a foreign key:

[CONSTRAINT [symbol]] FOREIGN KEY
    [index_name] (col_name, ...)
    REFERENCES tbl_name (col_name,...)
    [ON DELETE reference_option]
    [ON UPDATE reference_option]

reference_option:
    RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT

There are two reasons why my code does not set the [index_name] and instead the index name is automatically made the same as the constraint name. Both are evident from this paragraph taken from the MySQL 8.0 Reference Manual, section 13.1.20.5 FOREIGN KEY Constraints :

Prior to MySQL 8.0.16, if the CONSTRAINT symbol clause was not defined, or a symbol was not included following the CONSTRAINT keyword, both InnoDB and NDB storage engines would use the FOREIGN_KEY index_name if defined. In MySQL 8.0.16 and higher, the FOREIGN_KEY index_name is ignored.

The first reason is that I am running the code in MySQL 8.0.22.

The second reason is that I should have omitted the constraint name.

The workarounds in @akina's answer indeed enable me to specify a name for the foreign key (index) that is different from the constraint's name.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM