只有在一种情况下,(book,author,chapter) 才有可能成为主键,并且对于每个唯一的 (book,author) 组合,chapter 独立地自动递增:
存储引擎必须是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 中的这种遗留行为并没有很好的理由这样做。
其次,这并不是真正适合使用自动增量。自动增量实际上应该只用于需要作为代理值但在现实世界中没有实际意义的值。
第三,你的表似乎设计得不好,甚至在2nd normal form中也可能没有。
根据此结构,必须满足以下两项之一:
一本书的每一章都可以有不同的作者,这打破了尝试自动递增 (book,author) 的全部意义……或者(更有可能)每行都存在 author 属性(书,章)是多余的。
可以说,该表中唯一的候选键是 (book,chapter),如果作者不依赖于书和章节,则该表不在 2NF 中。
此外,您也不应该将书名存储在每一行中。任何给定的数据只应出现在关系数据库中单个表的单个行中的单个列中,其他所有内容都通过键引用它(例如,此处的“book_id”引用单个“id” "book" 表,其中包含书籍的“标题”列)。
然后,我的回答是建议您不是在尝试解决正确的问题,并且应该考虑重新设计您的结构,以便作者是表中每本书只有一行的书的属性,然后您'会让这个表带有 (book,chapter),并且您的应用程序可以手动填充这些章节编号。
或者,如果您坚持自动生成这些值,您可以使用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 历来在列不可为空时触发触发器之前将空值强制为 0,即使此行为不正确。