[英]Why is MySQL not properly naming my foreign key?
請考慮我在 MySQL 8.0.22(在 InnoDB 數據庫中)中運行的以下 SQL 代碼:
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;
SHOW CREATE TABLE pet
的 output 是:
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
在上面的idx_fk_pet_person
中,我在ALTER TABLE
命令中將其名稱指定為 idx_fk_pet_person 時,為什么 KEY 名為fk_pet_person
? 我怎樣才能讓它如此命名?
您混淆了 FOREIGN KEY 和使其工作的 INDEX。 請注意 - 代碼中顯示的約束定義中沒有表達式名稱(看起來像索引定義但不是)。
當沒有合適的索引讓約束起作用時,則自動創建該索引,並將約束名稱用作索引名稱。 如果存在合適的索引,則不會發生自動創建。
如果您希望索引具有定義的名稱,則必須在創建約束之前在單獨的ALTER TABLE
(子) 語句中創建此索引:
ALTER TABLE `pet`
ADD KEY `idx_fk_pet_person` (`owner_id`),
ADD CONSTRAINT `fk_pet_person`
FOREIGN KEY (`owner_id`)
REFERENCES `person` (`person_id`);
或者
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`);
MySQL 文檔指定了創建外鍵的語法:
[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
我的代碼沒有設置[index_name]
的原因有兩個,而是索引名稱自動與約束名稱相同。 從 MySQL 8.0 參考手冊第13.1.20.5 節外鍵約束的這段中可以看出兩者:
在 MySQL 8.0.16 之前,如果未定義 CONSTRAINT 符號子句,或者未在 CONSTRAINT 關鍵字之后包含符號,則 InnoDB 和 NDB 存儲引擎都將使用 FOREIGN_KEY index_name(如果已定義)。 在 MySQL 8.0.16 及更高版本中,忽略 FOREIGN_KEY index_name。
第一個原因是我在 MySQL 8.0.22 中運行代碼。
第二個原因是我應該省略約束名稱。
@akina 的答案中的解決方法確實使我能夠為與約束名稱不同的外鍵(索引)指定一個名稱。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.