【⑫MySQL | 制約(2)】外部キー | デフォルト値 | チェック制約 — 包括的なケース

序文

✨Xiao KMySQL コラムへようこそ。このセクションでは、MySQL 外部キー | デフォルト値 | チェック制約と包括的なケースの共有について説明します✨


6. 外部キー制約 (FOREIGN KEY、FK)

上記で紹介した整合性制約はすべて 1 つのテーブルに設定されますが、外部キー制約は複数のテーブル (通常は 2 つのテーブル) 間、つまり 2 つのテーブルの 2 つのフィールド間の参照関係の参照整合性を保証します。

6.1 コンセプト

外部キー制約のある 2 つのテーブル間には親子関係が存在します。つまり、子テーブルのフィールドの値の範囲は親テーブルによって決まります。たとえば、部門と従業員の関係、つまり各部門に複数の従業員がいる関係を表す場合です。まず、部門テーブルと従業員テーブルという 2 つのテーブルが存在する必要があります。次に、従業員テーブルには部門番号を表すフィールド deptno があります。これは部門テーブルの主キーに依存するため、フィールド deptno は従業員テーブルの外部キー。これを介して部門テーブルと従業員テーブルの関係が確立されます。

関連付け関係のある 2 つのテーブルの場合、関連付けられたフィールドの主キーが配置されているテーブルが主テーブル (親テーブル) となり、外部キーが配置されているテーブルが副テーブル (子テーブル) になります。

FK 制約を具体的に設定する場合、FK 制約を設定するフィールドはデータベース内の既存の親テーブルの主キーに依存する必要があり、外部キーは NULL にすることができます。
ここに画像の説明を挿入

6.2 特徴

  • スレーブ テーブルの外部キー列は、メイン テーブルの一意性制約の主キーまたは列を参照 (参照) する必要があります。これは、参照の値が一意である必要があるためです。
  • 外部キー制約を作成するときに、外部キー制約に名前を付けないと、デフォルト名は列名ではなく、emp11_ibfk_1 などの外部キー名が自動的に生成されます。外部キー制約名を指定することもできます。
  • テーブルを作成するときは、最初にマスター テーブルを作成し、次にスレーブ テーブルを作成する必要があります。
  • テーブルを削除するには、まずスレーブ テーブルを削除し (または、最初に外部キー制約を削除し)、次にメイン テーブルを削除する必要があります。
  • マスターテーブルのレコードがスレーブテーブルから参照されている場合、マスターテーブルのレコードは削除できません。データを削除したい場合は、スレーブテーブルのこのフィールドに依存するレコードを削除する必要があります。まず、マスターテーブルのレコードを削除できます
  • 外部キー制約を作成すると、システムはデフォルトで列に対応する通常のインデックスを作成します。外部キー制約を削除した後は、手动対応するインデックスを削除する必要があります。

6.3 外部キー制約の追加

テーブル内のフィールドの FK 制約の設定は非常に簡単で、その構文は次のとおりです。

CREATE TABLE table_name(
	字段名 数据类型,
    字段名 数据类型,
    ...
    CONSTRAINT 外键约束名 FOREIGN KEY (字段名1)
    	REFERENCES 主表名 (字段名2)
);

上記のステートメントでは、「外部キー制約名」は制約名を識別するために使用され、「フィールド名 1」は子テーブルに設定されている外部キーのフィールド名、「フィールド 2」は親テーブルのフィールド名です。子テーブルによって参照されるテーブル。

(1) テーブル作成時に追加

CREATE TABLE 主表名
(
	字段名 数据类型 PRIMARY KEY,
    字段名 数据类型,
    ...
);

CREATE TABLE 从表名
(
    字段名 数据类型 PRIMARY KEY,
    字段名 数据类型,
    ...
    CONSTRAINT 约束名 FOREIGN KEY(外键约束字段名)
    REFERENCES 主表(参考字段名)
);

(1) テーブル作成後に追加

一般に、テーブル間の関連付けは事前に設計されているため、外部キー制約はテーブルの作成時に定義されます。ただし、テーブルの設計を変更する必要があるが (新しいフィールドの追加、新しいリレーションシップの追加など)、事前定義された外部キー制約がない場合は、テーブルを変更して定義を補足する必要があります。

フォーマット:

ALTER TABLE 从表名 ADD [CONSTRAINT 约束名] FOREIGN KEY(从表字段名) REFERENCES 主表名(被参考字段) [ON UPDATE XX][ON DELETE XX];

例:

ALTER TABLE emp ADD [CONSTRAINT fk_emp_deptno] FOREIGN KEY(deptno) REFERENCES dept(deptno);

6.4 デモンストレーション

6.4.1 テーブルの作成

#新建数据库
CREATE DATABASE db_maye;
USE db_maye;

#创建表
CREATE TABLE dept
(
	deptno INT PRIMARY KEY COMMENT '部门编号',
	dname VARCHAR(20) NOT NULL  COMMENT '部门名称',
	loc   VARCHAR(20)  COMMENT '部门所在位置'
);

CREATE TABLE emp
(
	empno INT PRIMARY KEY  COMMENT '员工编号',
	ename VARCHAR(10) NOT NULL  COMMENT '员工姓名',
	deptno INT  COMMENT '员工所在部门编号',	#外键必须使用表级约束
	CONSTRAINT fk_emp_deptno FOREIGN key(deptno) REFERENCES dept(deptno)
);
#必须先创建dept表,再创建emp表,如果没有指定外键,那么随便先创建哪个都行

6.4.2 動作テーブル

  • レコードを追加する
#给员工表添加一条记录
INSERT INTO emp(empno,ename,deptno) VALUES(1234,'king',10);
-- 在dept表中不存在10号部门,所以错误->error:无法添加或更新子行:外键约束失败(' db_maye ')。 外键约束:fk_emp_deptno (' deptno ')

#先给dept添加记录,再执行上面的插入语句即可
INSERT INTO dept(deptno,dname,loc) VALUES(10,'C/C++','武汉');
  • レコードの削除

#删除主表dept中的记录
DELETE FROM dept WHERE deptno=10;
-- 在从表emp中有部门编号为10的,所以错误->Cannot delete or update a parent row: a foreign key constraint fails...

#先删除从表emp中参考指定值的记录,再执行上面的删除语句即可
DELETE FROM emp WHERE deptno=10;
  • 変更記録
#修改主表dept中的部门编号(把部门编号为10的改为20)
UPDATE dept SET deptno=20 WHERE deptno=10;
-- 在emp表中有参考dept表的deptno的外键,所以不能修改-> Cannot delete or update a parent row: a foreign key constraint fails...

#可以先删除从表emp中参考指定值的记录,再执行上面的语句
DELETE FROM emp WHERE deptno=10;
  • テーブル作成後に外部キー制約を追加する
ALTER TABLE emp ADD [CONSTRAINT fk_emp_deptno] FOREIGN KEY(deptno) REFERENCES dept(deptno);
  • 制約とインデックスを削除する
#先查看约束名
SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE table_name='emp';

#删除外键约束
ALTER TABLE emp DROP FOREIGN KEY fk_emp_deptno;

#查看指定表的索引
SHOW INDEX FROM emp;
#最后手动删除索引
ALTER TABLE emp DROP INDEX fk_emp_deptno;

6.5 開発シナリオ

質問 1: 従業員テーブルと部門テーブル (1 対多) など、2 つのテーブル (1 対 1、1 対多) の間にリレーションシップがある場合、それらの間に外部キー制約を確立する必要がありますか?

回答: いいえ、外部キー制約がなくても正常に動作します。

質問 2: 外部キー制約を構築するか否かの違いは何ですか?

答え:

  • 外部キー制約を設定すると、操作 (テーブルの作成、テーブルの削除、データの追加、変更、削除) が制限されます。

    • 例: 部門テーブルで部門番号が見つからない場合、従業員テーブルに従業員情報を追加することはできません。
  • 外部キー制約を確立しない場合、操作 (テーブルの作成、テーブルの削除、データの追加、変更、削除) は制限されませんが、データの参照整合性も保証する必要があります。信頼できるのは または のみ程序员的自觉です在访问的时候进行限定

    • たとえば、従業員テーブルでは、部門が部門テーブルにない場合でも従業員情報を追加できます。

質問 3: 外部キー制約を構築するかどうかのクエリと関係がありますか?

答え: いいえ

MySQL では、外部キー制約にはコストがかかり、システム リソースを消費します。大規模な同時 SQL 操作には適さない可能性があります。大規模な Web サイトの中央データベースなどの場合があります因为外键约束的系统开销而变得非常慢したがって、MySQL を使用すると、システムに付属する外部キー制約を使用せずに、应用层面データの整合性をチェックするロジックを完了できます。つまり、外部キー制約を使用しない場合でも、データの一貫性を確保するために、ロジックを追加せずにアプリケーション層を通じて外部キー制約の機能を実装する方法を見つける必要があります。

6.6 アリババ開発仕様

[必須] 外部キーとカスケードは許可されず、すべての外部キーの概念はアプリケーション層で解決される必要があります。

説明: 部門テーブル dept の deptno は主キーであり、従業員テーブル emp の empno は外部キーです。部門テーブルの deptno を更新し、同時に従業員テーブルの deptno の更新をトリガーする場合、それはカスケード更新です。外部キーとカスケード更新は適している場合单机低并发と適さない場合があります分布式、高并发集群。カスケード更新は強力にブロックされ、更新风暴データベースにリスクがあります。外部キーはデータベースの挿入速度に影響します。

6.7 カスケード動作

部門テーブル(マスターテーブル)の情報を削除する場合、まず従業員テーブル(スレーブテーブル)の関連データを削除する必要があり、非常に面倒です。

このとき、カスケード操作が利用できます。カスケード操作とは、マスターテーブルを操作すると、スレーブテーブルが自動的に操作されることを指します。

2 つのカスケード操作

  • カスケード削除: メインテーブルのデータを削除するときに、テーブルから関連データを自動的に削除します。
  • カスケード更新: メイン テーブルの外部キー制約フィールド (通常は主キー) が更新されると、スレーブ テーブルのデータが自動的に更新されます。

5 つのカスケード方式

セカンダリ テーブルの外部キーを定義するときに指定された ON UPDATE/ON DELETE 句について、InnoDB は次の 5 つのメソッドをサポートします。

  • CASCADE カスケード方式

    • マスターテーブルのレコードを更新/削除すると、スレーブテーブルの一致するレコードも同期的に更新/削除されます。
  • SET NULL NULL に設定

    • マスターテーブルのレコードを更新/削除する場合、スレーブテーブルの一致するレコードの列をNULLに設定します。
  • NO ACTION の更新と削除は許可されません

    • スレーブ テーブルに一致するレコードがある場合、マスター テーブルの関連フィールドを更新することはできません。
  • RESTRICT制限

    • 同NO ACTION
  • デフォルトを設定

    • メインテーブルに変更があると、サブテーブルは外部キー列をデフォルト値に設定しますが、Innodb はそれを認識しません...

:マスターテーブルのデータ変更により下図のスレーブテーブルのデータが変化しており、マスターテーブルは制限されていてデータの削除ができないことがわかります。

CREATE TABLE emp1
(
	empno INT PRIMARY KEY  COMMENT '员工编号',
	ename VARCHAR(10) NOT NULL  COMMENT '员工姓名',
	deptno INT  COMMENT '员工所在部门编号',	#外键必须使用表级约束
	CONSTRAINT fk_emp_deptno FOREIGN KEY(deptno) REFERENCES dept(deptno)
    ON UPDATE CASCADE ON DELETE RESTRICT
);

INSERT INTO emp1(empno,ename,deptno) VALUES(1234,'king',20);
INSERT INTO emp1(empno,ename,deptno) VALUES(234,'ing',20);
INSERT INTO emp1(empno,ename,deptno) VALUES(34,'ng',20);

UPDATE dept SET deptno=30 WHERE deptno=20;

DELETE FROM dept WHERE deptno=30;

ここに画像の説明を挿入
ここに画像の説明を挿入

7. デフォルト値制約とチェック制約

7.1 チェック制約(Check)

フィールドの値が xx の要件を満たしているかどうかを確認します。通常は値の範囲を指します。

MySQL5.7ではチェック制約を使用できますが、チェック制約は有効になりません~

MySQL8.0ではチェック制約の使用が開始され、有効になり、正しくチェックできるようになります。

  • テーブルの作成時にチェック制約を追加します。直接追加することも、後で (エイリアスを使用して) 追加することもできます。削除する方が便利です。
#1
CREATE TABLE stu
(
	 id INT PRIMARY KEY AUTO_INCREMENT,
	 name VARCHAR(10),
	 gender CHAR CHECK(gender IN('男','女'))
);

#2
CREATE TABLE stu
(
	 id INT PRIMARY KEY AUTO_INCREMENT,
	 name VARCHAR(10),
	 gender CHAR CHECK(gender IN('男','女')),
	 age TINYINT,
	 sal DECIMAL(10,2),
	 CONSTRAINT ck_stu_sal CHECK(sal>200),
	 CONSTRAINT ck_stu_age CHECK(age BETWEEN 18 AND 120)
);
  • もう一つの例
age TINYINT check(age>20) 
或
age TINYINT check(age BETWEEN 18 AND 120) 
  • テーブル作成後にチェック制約を追加する
ALTER TABLE stu ADD CONSTRAINT ck_stu_sal CHECK(sal>2000);

チェック制約を削除する

ALTER TABLE stu DROP CHECK ck_stu_sal;

ここに画像の説明を挿入

7.2 デフォルト制約(デフォルト)

データベース テーブルに新しいレコードを挿入するときに、フィールドに値が割り当てられていない場合、データベース システムはこのフィールドにデフォルト値を自動的に挿入します。この効果を実現するには、SQL ステートメントのキーワード DEFAULT を使用して設定できます。

データベース テーブル内のフィールドのデフォルト値の設定は非常に簡単で、その構文は次のとおりです。

  • テーブル作成時に追加する
CREATE TABLE df
(
		id INT PRIMARY KEY,
		name VARCHAR(10) DEFAULT 'maye'
);
  • テーブルを作成した後、追加します
ALTER TABLE df MODIFY name VARCHAR(10) DEFAULT 'hello';
  • デフォルトの制約を削除する
ALTER TABLE df MODIFY name VARCHAR(10);

ここに画像の説明を挿入

8. 総合的な実戦

8.1 データテーブルの作成

8.1.1 テーブルフィールドの説明

秋になり、生徒の運動量を増やすため、学校では生徒運動会の準備が始まり、競技成績情報の保存を容易にするために、以下のデータテーブルを定義しました。

  • プレイヤーテーブル (スポーツ選手):
    • 選手番号sporterno、選手名name、選手性別性別、部門番号deptno
  • スポーツアイテム表(アイテム):
    • アイテム番号 itemno、アイテム名 iname、競技場所 loc
  • グレード:
    • 選手番号スポルター番号、アイテム番号アイテム番号、スコアマーク

ここに画像の説明を挿入

スコア テーブルには、アスリートの番号とイベントの番号という 2 つの外部キーがあります。この設計の理由は、1 人のアスリートが複数のイベントに参加でき、1 つのイベントに複数のアスリートが参加できるためです。異なるプロジェクトには独自のキーがあります。成績。したがって、アスリートとプロジェクトの間には多対多の関係が存在します。以前学習した emp-dept は 1 対多の関係です。

8.1.2 テーブルの制約

ここに画像の説明を挿入

8.1.3 SQL ステートメント

# 创建数据库
CREATE DATABASE IF NOT EXISTS games1;
USE games1;

CREATE TABLE IF NOT EXISTS spoter
(
	spoterno INT,
	name     VARCHAR(30) NOT NULL,
	gender   CHAR        NOT NULL,
	deptname VARCHAR(30) NOT NULL,
	CONSTRAINT pk_spoterno PRIMARY key(spoterno),
	CONSTRAINT ck_gender   check(gender IN('男','女'))
)COMMENT '运动员表';

CREATE TABLE IF NOT EXISTS item
(
	itemno   INT,
	itemname VARCHAR(30) NOT NULL,
	loc      VARCHAR(30) NOT NULL,
	CONSTRAINT pk_itemno PRIMARY key(itemno)
)COMMENT '项目表';

CREATE TABLE IF NOT EXISTS grade
(
	spoterno INT,
	itemno INT,
	mark INT,
	CONSTRAINT ck_mark CHECK(mark IN(0,2,4,6)),
	CONSTRAINT fk_spoterno FOREIGN key(spoterno) REFERENCES spoter(spoterno),
	CONSTRAINT fk_itemno FOREIGN key(itemno) REFERENCES item(itemno)
)COMMENT '成绩表';


--  添加测试数据
INSERT INTO spoter(spoterno,name,gender,deptname) VALUES(1001,'rust','男','计算机系');
INSERT INTO spoter(spoterno,name,gender,deptname) VALUES(1002,'go','男','数学系');
INSERT INTO spoter(spoterno,name,gender,deptname) VALUES(1003,'python','男','计算机系');
INSERT INTO spoter(spoterno,name,gender,deptname) VALUES(1004,'c++','男','物理系');
INSERT INTO spoter(spoterno,name,gender,deptname) VALUES(1005,'c','女','心理系');
INSERT INTO spoter(spoterno,name,gender,deptname) VALUES(1006,'java','女','数学系');

INSERT INTO item(itemno,itemname,loc) VALUES(1,'男子五千米','一操场');
INSERT INTO item(itemno,itemname,loc) VALUES(2,'男子标枪','一操场');
INSERT INTO item(itemno,itemname,loc) VALUES(3,'男子跳远','二操场');
INSERT INTO item(itemno,itemname,loc) VALUES(4,'女子跳高','二操场');
INSERT INTO item(itemno,itemname,loc) VALUES(5,'女子三千米','三操场');

INSERT INTO grade(spoterno,itemno,mark) VALUES(1001,1,6);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1002,1,4);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1003,1,2);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1004,1,0);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1001,3,4);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1002,3,6);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1004,3,2);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1003,3,0);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1005,4,6);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1006,4,4);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1001,4,2);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1002,4,0);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1003,2,6);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1005,2,4);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1006,2,2);
INSERT INTO grade(spoterno,itemno,mark) VALUES(1001,2,0);

SELECT * FROM spoter;
SELECT * FROM item;
SELECT * FROM grade;

8.2 データ操作

問題 1 : 合計ポイントが最も高い学部名とそのポイントを調べてください。

  1. 必要なデータシートを特定する
    1. 発言者: 部署名
    2. グレード: ポイント
  2. 既知の関連フィールドを特定する
    1. 遠距離動員とポイント:sporter.sporterno=grade.sporterno
WITH temp AS
(	
	SELECT s.deptname deptname,SUM(g.mark) totalmark
	FROM spoter s,grade g
	WHERE s.spoterno=g.spoterno
	GROUP BY deptname
)
SELECT deptname,totalmark FROM temp
HAVING totalmark=(SELECT MAX(totalmark) FROM temp);

2 番目の質問: 遊び場の各イベントの名前とチャンピオンの名前を調べてください。

  1. 必要なデータシートの決定
    #sporter: チャンピオンの名前
    #item: プレイグラウンドプレーヤー
    #grade: チャンピオンを見つける
  2. 関連フィールドを決定します。
    #アスリートとポイント: Sporter.sporterno=grade.sporterno
    #アイテムとポイント: item.itemno = Grade.itemno
WITH temp AS
(	
	SELECT i.itemno,MAX(g.mark) maxmark
	FROM item i,grade g
	WHERE i.itemno=g.itemno AND i.loc='一操场'
	GROUP BY i.itemno
)
SELECT * 
FROM temp t,spoter s,item i,grade g
WHERE g.mark=t.maxmark AND s.spoterno=g.spoterno 
AND i.itemno=g.itemno AND t.itemno=g.itemno;

質問 3 : C++ が参加したプロジェクトに参加した他の学生の名前を調べてください。
必要なデータシートを決定スポーツ者: c++グレード: c++ プロジェクトに参加

WITH temp AS
(
	SELECT g.itemno
	FROM spoter s,grade g
	WHERE s.spoterno=g.spoterno
	AND s.name='c++'
)
SELECT DISTINCT s.name
FROM spoter s,grade g
WHERE s.spoterno=g.spoterno 
AND g.itemno IN(SELECT * FROM temp)
AND s.name!='c++';

質問 4 : 調査の結果、禁止薬物の使用により C++ のスコアが 0 と記録されています。データベースを変更してください。

UPDATE grade SET mark=0 WHERE spoterno=
(SELECT spoterno FROM spoter WHERE name='c++');

質問 5 : 組織委員会と協議した結果、女子走り高跳びの種目は削除される必要があります。まずグレード内の外部キーを削除します

ALTER TABLE grade DROP FOREIGN KEY fk_itemno;
DELETE FROM item WHERE itemname='女子跳高';

要約する

一般に、制約を使用すると、データベースのデータ品質、一貫性、整合性が向上し、データ操作が簡素化され、データベースのパフォーマンスが向上します。これはデータベースの設計と管理における重要な概念であり、データの信頼性と有効性を確保するのに役立ちます次のセクションでは、全員のデータ型を共有します。

おすすめ

転載: blog.csdn.net/qq_72157449/article/details/132386049