MySQL 外部キー制約の例の説明

MySQL 外部キー制約の例の説明

MySQL の外部キー制約は、2 つのテーブル間のリンクを確立するために使用されます。 1 つのテーブルが変更されると、もう 1 つのテーブルも変更されます。この機能の主な目的は、テーブル データの一貫性と整合性を確保することです。
外部キーによって関連付けられた 2 つのテーブルの場合、関連フィールドの主キーが配置されているテーブルは主テーブル (親テーブルとも呼ばれます) であり、外部キーが配置されているテーブルは副テーブル (子テーブルとも呼ばれます) です。外部キーを定義するときは、いくつかのルールに従う必要があります。

1. 親テーブルはデータベース内に既に存在しているか、現在作成中のテーブルである必要があります。後者の場合、親テーブルと子テーブルは同じテーブルです。このようなテーブルは自己参照テーブルと呼ばれ、この構造は自己参照と呼ばれます。
2. 親テーブルに主キーを定義する必要があります。
3. 主キーには null 値を含めることはできませんが、外部キーには null 値を含めることができます。つまり、外部キーの null 以外の値がすべて指定された主キーに表示されている限り、この外部キーの内容は正しいことになります。
4. 外部キーの列数は、親テーブルの主キーの列数と同じである必要があります。
5. 外部キーの列のデータ型は、親テーブルの主キーの対応する列のデータ型と同じである必要があります。これらはすべてかなり一般的なので、いくつか例を見てみましょう。

mysql:yeyztest ::>>テーブルfk_test_1(を作成します 
 -> id int not null 主キー auto_increment,
 -> name varchar() デフォルト '');
クエリは正常、行は影響を受けました (0.10 秒)

mysql:yeyztest ::>>テーブルfk_test_2(を作成します
 -> id int not null 主キー auto_increment,
 -> uid int、 
 -> 外部キー f​​k_uid(uid) は fk_test_1(id) を参照します。
クエリは正常、行は影響を受けました (0.06 秒)

ここでは、fk_test_1 と fk_test_2 の 2 つのテーブルを作成します。fk_test_2 の uid 列に外部キーを設定し、fk_test_1 のテーブルの id 列を関連付けます。ここでは、fk_test_1 が親テーブルで、fk_test_2 が子テーブルであることは明らかです。次に、データ挿入実験を行います。

mysql:yeyztest ::>>fk_test_1 に値 (,'aaa'),(,'bbb') を挿入します。
クエリは正常、行は影響を受けました (0.00 秒)
レコード: 重複: 警告: 

mysql:yeyztest ::>>fk_test_1 から * を選択します。
+----+------+
| ID | 名前 |
+----+------+
| | ああ |
| | bbb |
+----+------+
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>fk_test_2 に値 (,),(,); を挿入します。
クエリは正常、行は影響を受けました (0.00 秒)
レコード: 重複: 警告: 

mysql:yeyztest ::>>fk_test_2 の値に挿入します(,);
クエリは正常、行は影響を受けました (0.00 秒)


mysql:yeyztest ::>>fk_test_2 の値に挿入します(,);  
エラー (): 子行を追加または更新できません: 外部キー制約が失敗しました (`yeyztest`.`fk_test_2`、制約 `fk_test_2_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `fk_test_1` (`id`))

まず、メイン テーブルに id=1 と id=2 の 2 つのデータを挿入し、次に子テーブルにデータを挿入します。子テーブルは、uid=1 と uid=2 のデータを正常に挿入できますが、uid=3 のデータの挿入は失敗します。つまり、デフォルトでは、子テーブルに挿入する場合、挿入される外部キー関連フィールド値は、親テーブルの関連列に含まれる値である必要があります。ここでのデフォルトの状況に注意してください。これについては後で説明します。

削除状況を見てみましょう。

mysql:yeyztest ::>>fk_test_2 から * を選択します。
+----+------+
| ID | ユーザID |
+----+------+
| | |
| | |
| | |
+----+------+
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>id=; の fk_test_2 から削除します。
クエリは正常、行は影響を受けました (0.00 秒)

mysql:yeyztest ::>>fk_test_1 から * を選択します。  
+----+------+
| ID | 名前 |
+----+------+
| | ああ |
| | bbb |
+----+------+
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>id=; の fk_test_1 から削除します。 
エラー (): 親行を削除または更新できません: 外部キー制約が失敗しました (`yeyztest`.`fk_test_2`、制約 `fk_test_2_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `fk_test_1` (`id`))

子テーブル fk_test_2 で削除しても問題ないことがわかりますが、親テーブル fk_test_1 で削除すると、id=1 の値が削除できないことがわかります。 理由は、外部キー制約があるためです。 つまり、デフォルトでは、親テーブルから削除する場合、子テーブルですでに従属関係にある列値を直接削除することはできません。ここではデフォルトに注意してください。これについては以下で説明します。

削除に失敗したので、更新を試みてください。

mysql:yeyztest ::>>fk_test_1 を更新し、id= を設定します。id=;   
エラー (): 親行を削除または更新できません: 
外部キー制約が失敗する (`yeyztest`.`fk_test_2`、 
制約 `fk_test_2_ibfk_1` 外部キー (`uid`) 参照 `fk_test_1` (`id`))

mysql:yeyztest ::>>fk_test_1 を更新し、name='ccc' を設定します (id=;) 
クエリは正常、行は影響を受けました (0.00 秒)
一致した行: 変更: 警告:

親テーブルの主キー列の更新はまだ正常に実行できないことがわかりますが、他の列の更新は正常に実行できます。

この時点で、外部キーの存在はデータの整合性と統一性を保証するためのものであることはすでにわかっていますが、小さな問題も発生します。つまり、子テーブルに依存する親テーブルの列は削除できません。これは私たちが望んでいることではありません。一部のデータは確かに期限切れになり、削除する必要がありますが、この時点で何をすべきでしょうか。

上記のテストでは、繰り返し言及しましたが、デフォルトでは、外部キーの削除および更新ルールを設定していませんでした。ここで、MySQL は、最も厳しいルールである制限を使用するのに役立ちました。実際には、他にもいくつかのルールがあり、それらはすべてここにリストされています。

  • 親テーブルを削除します。

カスケード、null 設定、アクションなし、制限

  • 親テーブルを更新します。

カスケード、null 設定、アクションなし、制限

  • 制限はデフォルトの操作であり、親テーブルは子テーブルが依存する外部キー列を削除または変更できないことを意味します。これは最も安全な設定です。
  • カスケードとは、親テーブルが削除されると、子テーブルのレコードも直接削除されることを意味します。これは最も危険な設定です。
  • null を設定すると、親テーブルが削除されたときに、子テーブルは null 値で処理されます。
  • アクションなしとは、親テーブルが削除されても、子テーブルには変更が加えられないことを意味します。

関連付けを設定するための構文は次のとおりです。

テーブル名を変更し、制約 FK_ID 外部キー (外部キー フィールド名) を追加して、外部テーブル名 (主キー フィールド名) を参照します。
[削除時に {カスケード | null を設定 | アクションなし | 制限}]
[更新時に {カスケード | null を設定 | アクションなし | 制限}]

それでは、カスケードケースから始めて、他の 3 つのケースをテストしてみましょう。

mysql:yeyztest ::>>fk_test_1 から * を選択します。
+----+------+
| ID | 名前 |
+----+------+
| | ccc |
| | bbb |
+----+------+
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>fk_test_2 から * を選択します。
+----+------+
| ID | ユーザID |
+----+------+
| | |
| | |
+----+------+
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>テーブル fk_test_2\G の作成を表示
************************** 1. 行 ****************************
  テーブル: fk_test_2
テーブルの作成: CREATE TABLE `fk_test_2` (
 `id` int() NOT NULL AUTO_INCREMENT、
 `uid` int() デフォルト NULL,
 主キー (`id`)、
 キー `fk_uid` (`uid`),
 制約 `fk_test_2_ibfk_1` 外部キー (`uid`) 参照 `fk_test_1` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= デフォルト CHARSET=utf8
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>テーブルfk_test_2を変更し、外部キーfk_test_2_ibfk_1を削除します。
クエリは正常、行は影響を受けました (0.02 秒)
レコード: 重複: 警告: 

mysql:yeyztest ::>>テーブルfk_test_2を変更し、制約fk_uidを追加し、外部キー(uid)は削除カスケードでfk_test_1(id)を参照します。
クエリは正常、行は影響を受けました (0.03 秒)
レコード: 重複: 警告: 

#######################################
####ここで親テーブル id= のレコードを削除し、子テーブルの結果を確認します###
#######################################
mysql:yeyztest ::>>id=; の fk_test_1 から削除します。
クエリは正常、行は影響を受けました (0.00 秒)

mysql:yeyztest ::>>fk_test_1 から * を選択します。
+----+------+
| ID | 名前 |
+----+------+
| | ccc |
+----+------+
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>fk_test_2 から * を選択します。
+----+------+
| ID | ユーザID |
+----+------+
| | |
+----+------+
 セット内の行数 (0.00 秒)

最初は親テーブルの値にid=1とid=2の値が含まれ、子テーブルの値にuid=2とuid=1の値が含まれていることがわかります。親テーブルのid=2の値を削除すると、子テーブルのuid=2の値も直接削除されます。これがカスケードの役割、つまりカスケード削除です。

set null の場合を見てみましょう。

mysql:yeyztest ::>>テーブルfk_test_2を変更し、外部キーfk_uidを削除します。   
クエリは正常、行は影響を受けました (0.02 秒)
レコード: 重複: 警告: 

mysql:yeyztest ::>>テーブル fk_test_2 を変更し、制約 `fk_uid` 外部キー (`uid`) 参照 `fk_test_1` (`id`) を追加し、削除時に null を設定します。
クエリは正常、行は影響を受けました (0.03 秒)
レコード: 重複: 警告: 

mysql:yeyztest ::>>id=; の fk_test_1 から削除します。
クエリは正常、行は影響を受けました (0.00 秒)

mysql:yeyztest ::>>fk_test_1から*を選択します。
空のセット (0.00 秒)

mysql:yeyztest ::>>fk_test_2から*を選択します。
+----+------+
| ID | ユーザID |
+----+------+
| | NULL |
+----+------+
 セット内の行数 (0.00 秒)

set null を設定した後、親テーブルで id=1 の値を削除すると、子テーブルの uid の値が null になり、レコードが削除されないことがわかります。

アクションなしの状況も同様ですが、子テーブル内のレコードは変更されません。

上記は親テーブルを削除する操作です。親テーブルが更新されると、子テーブルも上記の 4 つの状況を選択できますが、基本的には削除と同じなので、ここでは繰り返しません。ご興味があれば、ぜひご自身でお試しください。

最後に、子テーブルの外部キー列には null 値が含まれる可能性があることに注意してください。

mysql:yeyztest ::>>fk_test_1 の値に挿入します(,);
クエリは正常、行は影響を受けました (0.00 秒)

mysql:yeyztest ::>>fk_test_2から*を選択します。   
+----+------+
| ID | ユーザID |
+----+------+
| | NULL |
+----+------+
 セット内の行数 (0.00 秒)

mysql:yeyztest ::>>fk_test_2 に値を挿入します ​​(,NULL);
クエリは正常、行は影響を受けました (0.00 秒)

mysql:yeyztest ::>>fk_test_2 に値を挿入します ​​(,NULL);
クエリは正常、行は影響を受けました (0.00 秒)

mysql:yeyztest ::>>fk_test_2 から * を選択します。
+----+------+
| ID | ユーザID |
+----+------+
| | NULL |
| | NULL |
| | NULL |
+----+------+
 セット内の行数 (0.00 秒)

上記はMySQL外部キー制約の例の説明の詳細な内容です。MySQL外部キー制約の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • MySQL に外部キー制約を追加する具体的な方法
  • MySQL 外部キー制約 (FOREIGN KEY) ケースの説明
  • MySQL 外部キー制約とテーブル関係の概要
  • MySQL 外部キー制約の詳細な説明
  • 外部キー制約を持つテーブルデータを削除する MySQL メソッドの紹介
  • MySQL テーブルを削除するときに外部キー制約を無視するシンプルな実装
  • MySQL 子テーブルで外部キー制約チェックを無効にする方法
  • MySQL で外部キー制約を作成および削除する方法

<<:  Alibaba Cloud Server Linux システムは Tomcat を構築して Web プロジェクトを展開します

>>:  JavaScript 関数構文の説明

推薦する

MySQL 8.0.11 のインストールと設定方法のグラフィックチュートリアル

MySQL 8.0のインストールと設定方法は参考までに。具体的な内容は以下のとおりです。ダウンロード...

Centos システムの指定された場所に Nginx をインストールする方法

Centos システムの指定された場所に Nginx をインストールするにはどうすればいいですか?は...

Windows 10 で MySQL を完全にアンインストールして再インストールするための詳細な手順

さまざまな理由で、誰もが MySQL を再インストールする必要があると思います。 MySQL と Q...

Vue バインディング オブジェクト、配列データを動的にレンダリングできないケースの詳細な説明

プロジェクトシナリオ: Dark Horse Vueプロジェクト管理の実践、製品分類の取得、拡張バー...

Docker で hyperf を開発する完全な使用例の詳細な説明

ハイパーフ公式サイトHyperf 公式ドキュメントのインストール1. Dockerの使用docker...

Vue+Websocketはチャット機能を実装するだけです

この記事では、チャット機能を簡単に実装するためのVue+Websocketの具体的なコードを参考まで...

ウェブページを作るときに知っておくべきいくつかのスキル

1. IE6 では z-index が無効です。 CSS では、階層を変更するために z-index...

エレガントなJSコードの書き方

目次変数意味があり発音しやすい変数名を使用する同じ型の変数には同じ語彙を使用する検索可能な名前を使用...

Vue-routerルーティングの使い方

目次1. 説明2. インストール3. テスト1. 説明Vue Router は、Vue.js の公式...

HTML における DOM 要素のスクロールバースクロール制御の詳細な説明

dom要素に新しい子要素を追加し、新しく追加された新しい要素がコンテナーのスコープを超えた場合は、次...

mysql を解決: エラー 1045 (28000): ユーザー 'root'@'localhost' のアクセスが拒否されました (パスワードの使用: NO/YES)

1. 問題時々Mysqlにログインしてパスワードを入力すると、この状況が発生しますmysql -u...

ul リスト タグ デザイン ウェブ ページ 複数列レイアウト

数日前、CSS で 3 列レイアウトを書いていたときに、突然この方法を思いつきました。このアイデアは...

HTML の表の行と列を結合する問題の解決策の詳細な説明

私たちが構築しようとしていたウェブサイトには、長い文章だけでなく、多数の表も含まれており、表のレイア...

MySQLパラダイムの使用に関する詳細な説明

1. パラダイムこのパラダイムの英語名は Normal Form であり、1970 年代にリレーショ...

Centos7でのパーティションのフォーマットとマウントの実装

Linux では、ハードディスクの追加やパーティションの再マウントといった状況に頻繁に遭遇します。こ...