(book,author,chapter) が主キーになり、章が一意の (book,author) の組み合わせごとに個別に自動インクリメントされるのは、1 つの状況でのみ可能です。
ストレージ エンジンは である必要がありますMyISAM
。
このように定義されたMyISAM
テーブルは、一意の (a,b) ごとに列 `c` を "1" から開始して、期待どおりに動作します。
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 でのこの従来の動作は、別の方法で行う正当な理由にはなりません。
第 2 に、これは自動インクリメントの適切な使用方法ではありません。自動インクリメントは、実際には代理値として必要であるが、現実世界では実際の意味を持たない値に対してのみ使用する必要があります。
第 3 に、あなたのテーブルは適切に設計されていないように見えます。
この構造に基づいて、次の 2 つのいずれかが真である必要があります。
本の各章には異なる著者がいる可能性があり、これは (book,author) で自動インクリメントしようとする点全体を壊します... または (より可能性が高い) (book,author) のすべての行に author 属性が存在します。の章) は冗長です。
おそらく、このテーブルの唯一の候補キーは (本、章) であり、著者が本と章の両方に依存していない場合、テーブルは 2NF ではありません。
さらに、本の名前も各行に格納しないでください。特定のデータは、リレーショナル データベース内の単一のテーブルの単一の行の単一の列にのみ表示され、それ以外はすべてキーによって参照されます (たとえば、ここでの「book_id」は、本の「タイトル」の列を含む「本」テーブル)。
したがって、私の答えは、あなたが正しい問題を解決しようとしているのではないという提案であり、構造を再設計して、各本に 1 行しかないテーブルで著者が本の属性になるようにすることを検討する必要があります。このテーブルには (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()
が必要なのは、列が null 可能でない場合、MySQL はこれまで、トリガーを起動する前に null を 0 に強制するためです (この動作は正しくありません)。