MySQLで外部キー制約の動作を確認する
モチベーション
ActiveRecordでアソシエーションの設定をする前に、MySQLの外部キー制約の設定方法の確認をしたい
準備
環境
mysql --version mysql Ver 14.14 Distrib 5.6.25, for osx10.10 (x86_64) using EditLine wrapper
実行するクエリ
CREATE TABLE authors(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE publishers(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE books(
id INT NOT NULL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
author_id INT NOT NULL,
publisher_id INT NOT NULL,
FOREIGN KEY(author_id)
REFERENCES authors(id)
ON UPDATE RESTRICT ON DELETE RESTRICT,
FOREIGN KEY(publisher_id)
REFERENCES publishers(id)
ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB;
INSERT authors(id, name) VALUES
(1, 'author1'),
(2, 'author2'),
(3, 'author3'),
(4, 'author4'),
(5, 'author5');
INSERT publishers (id, name) VALUES
(1, 'publisher1'),
(2, 'publisher2'),
(3, 'publisher3'),
(4, 'publisher4'),
(5, 'publisher5');
INSERT books(id ,title, author_id, publisher_id) VALUES
(1, 'book1', 1, 1),
(2, 'book2', 2, 2),
(3, 'book3', 3, 3),
(4, 'book4', 4, 4);
この時、小テーブルのにレコードを挿入する、
INSERT books(id ,title, author_id, publisher_id) VALUES
(1, 'book1', 1, 1),
(2, 'book2', 2, 2),
(3, 'book3', 3, 3),
(5, 'book4', 4, 4);を最後に実行しないと以下のエラーが出てレコードを挿入できない。
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`book`.`books`, CONSTRAINT `books_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`))各テーブルのレコード情報
mysql> SELECT * FROM authors; +----+---------+ | id | name | +----+---------+ | 1 | author1 | | 2 | author2 | | 3 | author3 | | 4 | author4 | | 5 | author5 | +----+---------+ mysql> SELECT * FROM publishers; +----+------------+ | id | name | +----+------------+ | 1 | publisher1 | | 2 | publisher2 | | 3 | publisher3 | | 4 | publisher4 | | 5 | publisher5 | +----+------------+ mysql> SELECT * FROM books; +----+-------+-----------+--------------+ | id | title | author_id | publisher_id | +----+-------+-----------+--------------+ | 1 | book1 | 1 | 1 | | 2 | book2 | 2 | 2 | | 3 | book3 | 3 | 3 | | 4 | book4 | 4 | 4 | +----+-------+-----------+--------------+
準備完了!
外部キー制約の動作確認
作成したテーブルやレコードを元に外部キー制約の動作を確認する。外部キー制約としてCASCADEとRESTRICT以外にもSET NULLやNO ACTIONもあるが今回は動作確認対象外とする。
UPDATE ON RESTRICTの動作確認
mysql> UPDATE authors SET id = 100 WHERE id = 1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`book`.`books`, CONSTRAINT `books_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`))
続いて、books.author_id = 1のレコードを全て削除した後に親レコードを更新する。
mysql> DELETE FROM books WHERE author_id =1; Query OK, 2 rows affected (0.00 sec) mysql> UPDATE authors SET id = 100 WHERE id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
authors.id = 1のレコードがid =100に更新されていることを確認する。
mysql> SELECT * from authors; +-----+---------+ | id | name | +-----+---------+ | 2 | author2 | | 3 | author3 | | 4 | author4 | | 5 | author5 | | 100 | author1 | +-----+---------+ mysql> SELECT * FROM books; +----+-------+-----------+--------------+ | id | title | author_id | publisher_id | +----+-------+-----------+--------------+ | 2 | book2 | 2 | 2 | | 3 | book3 | 3 | 3 | | 4 | book4 | 4 | 4 | +----+-------+-----------+--------------+
DELETE ON RESTRICTの動作確認
まずは、RESTRICTで親レコードを消せないことを確認する。
mysql> DELETE FROM authors WHERE id =2; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`book`.`books`, CONSTRAINT `books_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`))
続いて、books.authors_id = 2の子レコードを全て削除したと後に、親レコードを削除する。
mysql> DELETE FROM books WHERE author_id =2; Query OK, 2 rows affected (0.00 sec) mysql> DELETE FROM authors WHERE id =2; Query OK, 1 row affected (0.00 sec)
authors.id = 2の親レコードが削除されていることを結果を確認する。
mysql> SELECT * FROM authors; +-----+---------+ | id | name | +-----+---------+ | 3 | author3 | | 4 | author4 | | 5 | author5 | | 100 | author1 | +-----+---------+ 4 rows in set (0.00 sec) mysql> SELECT * FROM books; +----+-------+-----------+--------------+ | id | title | author_id | publisher_id | +----+-------+-----------+--------------+ | 3 | book3 | 3 | 3 | | 4 | book4 | 4 | 4 | +----+-------+-----------+--------------+
UPDATE ON CASCADEの動作確認
CASCADEの場合はいきなり親要素の更新が出来る。
mysql> UPDATE publishers SET id = 300 WHERE id = 3;
結果を確認。
mysql> SELECT * FROM publishers; +-----+------------+ | id | name | +-----+------------+ | 1 | publisher1 | | 2 | publisher2 | | 4 | publisher4 | | 5 | publisher5 | | 300 | publisher3 | +-----+------------+ 5 rows in set (0.00 sec) mysql> SELECT * FROM books; +----+-------+-----------+--------------+ | id | title | author_id | publisher_id | +----+-------+-----------+--------------+ | 3 | book3 | 3 | 300 | | 4 | book4 | 4 | 4 | +----+-------+-----------+--------------+
子レコードの更新に伴い、親レコードも更新されている。
DELETE ON CASCADEの動作確認
DELETEも同様子レコードの削除に伴い、親レコードも削除される
DELETE FROM publishers WHERE id =4;
book.id = 4が同時に削除されているか、結果を確認する。
mysql> SELECT * FROM publishers; +-----+------------+ | id | name | +-----+------------+ | 1 | publisher1 | | 2 | publisher2 | | 5 | publisher5 | | 300 | publisher3 | +-----+------------+ 4 rows in set (0.00 sec) mysql> SELECT * FROM books; +----+-------+-----------+--------------+ | id | title | author_id | publisher_id | +----+-------+-----------+--------------+ | 3 | book3 | 3 | 300 | +----+-------+-----------+--------------+