Mysql和FK的问题
我在这里的一些桌子上遇到了麻烦。
我有这张表:
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
我解决了在主表创建索引的问题。但我不知道为什么没有这个索引我就会遇到麻烦。如果有人能问我,我将不胜感激!
i'm having trouble with some tables here.
i have this table:
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
And an second one:
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'
My problem it's i need to make an FK between codmenuitem
i have this sql command that are resulting on an error:
ALTER TABLE `smenuitememp` ADD CONSTRAINT `FK_smenuitememp_smenuitem` FOREIGN KEY (`codmenuitem`) REFERENCES `smenuitem` (`codmenuitem`);
When i try to execute it's return this error:
Someone has an idea?
Update... i was trying to solve the problem, and got an new question... 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
I solved the problem creating an index at the main table. But i don't know why i was having trouble without this index. If someone could ask me i would apreciate!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
外键列必须引用包含主键最左侧前缀或父表中的唯一键的列。
换句话说,以下示例在 InnoDB 中有效:
您收到错误,因为您尝试执行 (x) 引用 Foo(b) 的等效操作。
您的列 codmenuitem 是父级主键中三列中的第二列。
如果
smenuitem.codemenuitem
引用smenuitem.codmodulo
就会起作用,因为该列是父表主键中最左边的列。关于您的后续问题:
请记住外键的工作方式。每次在子表中插入或更新行时,都需要在父表中查找行以验证引用列中是否存在该值。如果该列没有索引,则必须执行表扫描才能实现此查找,假设您的父表增长,这将非常昂贵。
如果您尝试根据多列索引的中间列查找行,则索引对您没有帮助。打个比方,这就像在电话簿中搜索所有具有特定中间名的人一样。
标准 ANSI SQL 要求引用的列是 PRIMARY KEY 或 UNIQUE KEY 的一部分,并且要求外键列与父级中主约束或唯一约束的所有列匹配。
但InnoDB 更加宽松。它仍然要求对父表中的引用列进行索引,以便查找能够高效,并且引用列位于索引的最左边。但非唯一索引是可以的;允许外键引用它。
这可能会导致奇怪的情况,例如子行引用父级中的多行,但预计您将处理此类异常情况。
我觉得有必要强调最后一点。如果您为父级中的非唯一索引列定义外键,您将获得异常数据。这可能会导致您的查询在进行联接时多次报告行。你不应该使用 InnoDB 的这种行为;您应该只为唯一的父列定义外键。
The foreign key column(s) must reference column(s) comprising a left-most prefix of the primary key or a unique key in the parent table.
In other words, the following examples work in InnoDB:
You got an error because you're trying to do the equivalent of (x) references Foo(b).
Your column codmenuitem is the second of three columns in the primary key of the parent.
It would work if
smenuitememp.codemenuitem
were to referencesmenuitem.codmodulo
, because that column is the leftmost column in the parent table's primary key.Re your followup question:
Keep in mind the way foreign keys work. Every time you insert or update a row in the child table, it needs to look up a row in the parent table to verify that the value exists in the referenced column. If the column isn't indexed, it'll have to do a table-scan to achieve this lookup, and that would be very expensive, assuming your parent table grows.
If you try to look up a row based on the middle column of a multi-column index, the index doesn't help you. By analogy, it's like searching a telephone book for all people with a certain middle name.
Standard ANSI SQL requires that the referenced column be part of a PRIMARY KEY or UNIQUE KEY, and it requires that the foreign key columns match all the columns of a primary or unique constraint in the parent.
But InnoDB is more permissive. It still requires that the referenced column in the parent table be indexed so the lookup can be efficient, and that the referenced columns be the leftmost in the index. But a non-unique index is okay; it's allowed for a foreign key to reference it.
This can lead to weird cases like a child row that references more than one row in the parent, but it's expected that you will handle such anomalies.
I feel the need to emphasize the last point. You will get anomalous data if you define foreign keys to non-uniquely indexed columns in the parent. This will probably cause your queries to report rows multiple time when you do joins. You should not use this behavior of InnoDB; you should define foreign keys only to parent columns that are unique.