我在这里找不到一些表格。
我有这张桌子:
CREATE TABLE `smenuitem` (
`nome` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`url` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`tipo` CHAR(4) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`ordemmenu` INT(10) NULL DEFAULT NULL,
`codparent` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmodulo`, `codmenuitem`, `codmenuitem2`),
CONSTRAINT `FK_smenuitem_smodulos` FOREIGN KEY (`codmodulo`) REFERENCES `smodulos` (`codmodulo`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
还有第二个:
CREATE TABLE `smenuitememp` (
`codempresa` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmenuitem`, `codempresa`, `codmodulo`)
)
COLLATE='utf8_unicode_ci'
我的问题是我需要在codmenuitem之间制作一个FK 我有这个sql命令导致错误:
ALTER TABLE `smenuitememp` ADD CONSTRAINT `FK_smenuitememp_smenuitem` FOREIGN KEY (`codmenuitem`) REFERENCES `smenuitem` (`codmenuitem`);
当我尝试执行它时会返回此错误:
有人有想法吗?
更新......我正试图解决问题,并得到了一个新问题...... T_T
CREATE TABLE `smenuitem` (
`nome` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`url` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`tipo` CHAR(4) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`ordemmenu` INT(10) NULL DEFAULT NULL,
`codparent` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmodulo`, `codmenuitem`),
INDEX `codmenuitem` (`codmenuitem`),
CONSTRAINT `FK_smenuitem_smodulos` FOREIGN KEY (`codmodulo`) REFERENCES `smodulos` (`codmodulo`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
我解决了在主表创建索引的问题。但我不知道为什么没有这个索引我遇到了麻烦。如果有人能问我,我会赞成!
答案 0 :(得分:2)
外键列必须引用包含主键最左前缀或父表中唯一键的列。
换句话说,以下示例适用于InnoDB:
CREATE TABLE Foo ( a INT, b INT, c INT, PRIMARY KEY (a,b,c) );
CREATE TABLE Bar ( x INT, y INT );
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(b,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,b); -- RIGHT
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(b); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(a); -- RIGHT
你得到一个错误,因为你试图做相当于(x)引用的Foo(b) 您的列codmenuitem是父级主键中三列中的第二列。
如果smenuitememp.codemenuitem
引用smenuitem.codmodulo
,它将起作用,因为该列是父表主键中最左边的列。
重新提出你的后续问题:
请记住外键的工作方式。每次在子表中插入或更新行时,都需要在父表中查找一行以验证该值是否存在于引用的列中。如果列没有编入索引,则必须进行表扫描以实现此查找,并且假设父表增长,这将非常昂贵。
如果您尝试根据多列索引的中间列查找行,则索引对您没有帮助。通过类比,就像在电话簿中搜索具有某个中间名的所有人一样。
标准ANSI SQL要求引用的列是PRIMARY KEY或UNIQUE KEY的一部分,并且它要求外键列匹配 all 父级中的主要或唯一约束的列。
但InnoDB更宽容。它仍然需要对父表中引用的列进行索引,以便查找可以高效,和引用的列是索引中最左边的列。但是一个非独特的指数是可以的;它允许外键引用它。
这可能导致奇怪的情况,如子行,引用父对象中的多行,但预计您将处理此类异常。
我觉得有必要强调最后一点。如果您为父级中的非唯一索引列定义外键,则将 获取异常数据。这可能会导致您的查询在您进行连接时多次报告行。你不应该使用InnoDB的这种行为;您应该只将外键定义为唯一的父列。