6

我有一个带有复合主键的 Mysql 表。
我需要主键的一个字段分别为其他两个字段的每个唯一对自动递增。
例如:

书名 | 作者姓名 | 第一章
| 作者1 | 1
本书1 | 作者1 | 2
本书1 | 作者1 | 3
书 2 | 作者2 | 1
本书2 | 作者2 | 2
本书2 | 作者2 | 3
本书3 | 作者3 | 1
本书3 | 作者3 | 2
本书 3 | 作者3 | 3


有谁知道如何在 Mysql Workbench 中做到这一点?

4

1 回答 1

9

只有在一种情况下, (book,author,chapter) 才有可能成为主键,并且对于每个唯一的 (book,author) 组合,章节独立地自动递增:

存储引擎必须是MyISAM.

像这样定义的MyISAM表将完全符合您的预期,对于每个唯一 (a,b),在“1”处开始列 `c`:

CREATE TABLE `aa_test` (
  `a` varchar(48) NOT NULL,
  `b` varchar(48) NOT NULL,
  `c` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`a`,`b`,`c`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

但是,不要这样做

至少出于以下原因:

首先,您不应该使用 MyISAM。它是一种非常古老的技术恐龙,它不是事务性的,而且InnoDB在损坏和崩溃恢复方面也没有那么强大。您应该使用 InnoDB,而 MyISAM 中的这种遗留行为并没有很好的理由以不同的方式进行。

其次,这并不是真正适合使用自动增量。自动增量实际上应该只用于需要作为代理值但在现实世界中没有实际意义的值。

第三,您的表格似乎没有经过精心设计,甚至可能不是第二范式

基于此结构,两件事之一必须为真:

一本书的每一章都可以有一个不同的作者,这打破了尝试自动递增 (book,author) 的全部意义……或者(更有可能)在 (book,章)是多余的。

可以说,该表中唯一的候选键是(书,章),如果作者不依赖于书和章,则该表不在 2NF 中。

此外,您也不应该在每一行中存储书名。任何给定的数据只应出现在关系数据库中单个表的单个行中的单个列中,其他所有内容都通过键引用它(例如,此处的“book_id”引用单个“id” “书”表,其中包含书的“标题”列)。

那么,我的回答是建议您不要试图解决正确的问题,并且应该考虑重新设计您的结构,以便作者是表中每本书只有一行的书的属性,然后您将拥有此表带有(书,章节),您的应用程序可以手动填充这些章节编号。

或者,如果您坚持自动生成这些值,您可以使用BEFORE INSERT触发器来计算插入时的适当值,其中包含如下逻辑:

IF IFNULL(NEW.Chapter,0) = 0 THEN  
  SET NEW.Chapter = (SELECT COUNT(1) FROM this_table_name x
                      WHERE x.Book_Name = NEW.Book_Name
                        AND x.Author_Name = NEW.Author_Name) + 1;
END IF;

具有此逻辑的触发器适用于任何存储引擎。

IFNULL()是必需的,因为 MySQL 在历史上在列不可为空时触发触发器之前将 null 强制为 0,即使此行为不正确。

于 2013-09-22T23:51:23.270 回答