Nao000のぶろぐ

蝶を追っている少年になりたい

mysql 外部キー制約を観察する( ON DELETE RESTRICT )

準備

イメージを取得

docker pull mysql

コンテナ起動

docker run --name mysql_study_references -it --env MYSQL_ROOT_PASSWORD=password -d mysql

mysql に接続

mysql -h localhost -u root -ppassword

バージョン情報

mysql> select version(), current_date;
+-----------+--------------+
| version() | current_date |
+-----------+--------------+
| 8.0.29    | 2022-04-30   |
+-----------+--------------+

データベース作成

mysql> create database learning character set utf8mb4;

データベース選択

mysql> use learning

参照制約付きカラムを含めたテーブル作成

CREATE TABLE parent (
    parent_id INT NOT NULL AUTO_INCREMENT,
    parent_name varchar(255),
    PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (
    child_id INT NOT NULL AUTO_INCREMENT,
    parent_id INT NOT NULL,
    PRIMARY KEY (child_id),
    INDEX parent_index (parent_id),
    FOREIGN KEY (parent_id)
        REFERENCES parent(parent_id)
        ON DELETE RESTRICT
) ENGINE=INNODB;

データインサート

insert into parent (parent_name) values ('sample1'), ('sample2'), ('sample3'), ('sample4'), ('sample5');

insert into child (parent_id) values (1), (2), (3), (2), (3), (3), (1);

観察

child テーブルに parent テーブルに存在しないレコードをインサートする

mysql> insert into child (parent_id) values (6);

結果

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`learning`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`parent_id`) ON DELETE RESTRICT)

parent テーブルに存在しないデータを child テーブルにインサートすると、確かにエラーになることが確認できます。

parent テーブルのレコードを削除してみる

mysql> DELETE FROM parent where parent_id = 1;

結果

ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`learning`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`parent_id`) ON DELETE RESTRICT)

child テーブルにインサートすると、確かにエラーになることが確認できます。

child テーブルから参照されていない parent テーブルのレコードを削除してみる

新しく parent テーブルにレコードをインサートします。このレコードを参照する child テーブルのレコードは作成しません。

mysql> insert into parent (parent_name) values ('sample6');

インサートしたレコードを削除してみる。

mysql> DELETE FROM parent where parent_id = 6;

結果

Query OK, 1 row affected (0.01 sec)

child テーブルから参照されていないので削除できます。

トランケートするとき

TRUNCATE TABLE は外部キー関係を持つ InnoDB テーブルに対して実行することは出来ません。ので、一時的に外部キー制約を解除します。MyISAM の場合はそもそも外部キーをサポートしていないそうです。

mysql> set foreign_key_checks = 0;
mysql> truncate table parent;
mysql> truncate table child;
mysql> set foreign_key_checks = 1;

参考

https://hub.docker.com/_/mysql https://docs.docker.com/engine/reference/commandline/run/ https://dev.mysql.com/doc/refman/5.6/ja/create-table-foreign-keys.html https://dev.mysql.com/doc/refman/5.6/ja/truncate-table.html https://dev.mysql.com/doc/refman/5.6/ja/myisam-storage-engine.html https://qiita.com/pugiemonn/items/b17288494e4b627f4475

終わり

終わりです。じっくり観察するのはこれが初めてな気がします。今回使用した mysql のバージョンは8系ですが、参考にした公式サイトのバージョンが5.6なのは仕様です。