web-dev-qa-db-ja.com

複合主キーの値の一意の組み合わせのみを許可する

booksという名前の次のテーブルを作成しました。

CREATE TABLE IF NOT EXISTS `books` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

booksテーブルの2冊の本を比較するために、compareという別のタブレットを作成しました。

CREATE TABLE IF NOT EXISTS `compare` (
`id_1` BIGINT UNSIGNED NOT NULL,
`id_2` BIGINT UNSIGNED NOT NULL, 
PRIMARY KEY (`id_1`,`id_2`),
FOREIGN KEY (`id_1`) REFERENCES books(`id`),
FOREIGN KEY (`id_2`) REFERENCES books(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

以前は期待どおりに機能しますが、MySQLにcompareテーブルの値の一意の組み合わせのみを許可するように強制する必要があります。

たとえば、compareテーブルに次の行があるとします。

id_1 | id_2
------------
  1  |  2

MySQLに次の行を挿入させないようにしたいのですが。

id_1 | id_2
------------
  2  |  1

MySQLに1,2または2,1両方ではありません。

10.2.14-MariaDBを使用しています-MariaDBサーバー

5
Michael Samuel

MariaDB 10.2を使用しているため、CHECK制約を追加して、最初のIDが2番目のID(id_1 < id_2)よりも小さいことを強制できます。 CHECK constraint はバージョン10.2.1で追加されました。

これには、INSERTステートメントのIDを正しい順序で指定する必要があるという制限があります((3,2)がであっても、(2,3)の組み合わせを挿入することはできませんいない):

ALTER TABLE compare
  ADD CONSTRAINT ids_unique_combination_chk
    CHECK (id_1 < id_2) ;

dbfiddle.uk でテストされています。


INSERTステートメントとプロシージャに手間をかけたくない場合は、2つの VIRTUAL(またはPERSISTENT)列UNIQUE制約。

バージョン5.2以降、MariaDBで仮想列が利用可能になり、10.2.1でいくつかの制限が解除されました。

ALTER TABLE compare
  ADD small_id BIGINT AS (LEAST(id_1, id_2)) VIRTUAL,
  ADD big_id   BIGINT AS (GREATEST(id_1, id_2)) VIRTUAL,
  ADD CONSTRAINT ids_unique_combination_uq
    UNIQUE (small_id, big_id);

Dbfiddle.ukでもテスト: fiddle-2

9
ypercubeᵀᴹ