[MySQL] SQL フィールドの制約

MySQL では、保存する必要があるデータには、特定のシナリオでさまざまな制約が必要です。新しく挿入されたデータがフィールドの制約フィールドに違反する場合、MySQL は挿入を直接禁止します。

  • データ型も制約ですが、データ型制約は単純すぎます。
  • たとえば、保存する必要があるのがシリアル番号である場合、負の数値は使用できません。この場合、整数を制限するにはunsigned を使用する必要があります。
  • 保存したいものが日付であり、この日付のすべてのフィールドに日付が必要な場合は、NOT NULL空にならないように制約する必要があります。
  • 保存したいものがユーザー ID である場合、この値はユーザー システム全体で一意である必要があり、これを使用してUNIQUE一意性を制限できます。

この記事では主に、MySQL における ddl 型のステートメント操作である次のタイプの制約を紹介します。

null/not null
default
comment
zerofill
primary key
auto_increment
unique key

ちなみに、MySQL では各カラムの値をまたは と呼びますが字段、一般的には とは呼びません键值

そして、テーブル内の各行は次のように呼ばれます。一条记录

1. 空の属性

1.1 説明

empty 属性には 2 つの値 が含まれており、NULL/NOT NULLそれぞれ空と空ではないことに対応します。

データベースでは、行を挿入するときに列の値を指定しない場合、データベースは値を NULL に設定します。

ここで、NULL と空の文字列の区別に注意してください。空の文字列は NULL ではありません。

しかし、実際にデータを使用する場合、これが整数データであると仮定して、それを取り出して演算する必要があります。このとき、NULLで得られる結果は数値ではないため、演算を行うことはできません。フィールドの制約を設定したり、NOT NULLデフォルト値 (0 や空の文字列など) を追加したりすることがよくあります。

MariaDB [hello]> select null;
+------+
| NULL |
+------+
| NULL |
+------+
1 row in set (0.000 sec)

MariaDB [hello]> select not null;
+----------+
| not null |
+----------+
|     NULL |
+----------+
1 row in set (0.001 sec)

以下のことから、空の属性は操作に参加できず、操作がどのように実行されたとしても結果は NULL になることがわかります。

Python では、NULL は None に直接対応するため、None および int 型で操作を実行しようとすると、Python はエラーを報告します。CPPでも同様です。

MariaDB [hello]> select 1+null;
+--------+
| 1+null |
+--------+
|   NULL |
+--------+
1 row in set (0.001 sec)

1.2 事例

フロア上のクラスと教室に対応するテーブルがあり、クラス番号と教室番号の 2 つのフィールドが含まれているとします。

  • クラス番号が空の場合、この教室にどのクラスがあるのか​​わかりません。
  • 教室番号が空の場合、どこで授業が行われているかわかりません。

実際のシナリオからわかるように、これら 2 つのフィールドはどちらも空にすることはできないため、テーブルを作成するときにこれを考慮する必要があります。

create table if not exists myclass(
	class_name varchar(30) not null,
    class_room varchar(30) not null
)default charset=utf8;

テーブルの作成後、NULL フィールドを挿入しようとすると、特定の列を空にすることができないことを示す次のプロンプトが表示されます。

MariaDB [hello]> insert into myclass values ('510',NULL);
ERROR 1048 (23000): Column 'class_room' cannot be null

空の文字列を挿入できます。これは、私たちが考えているものはNULL と同じではないことをもう一度示しています。空の文字列は NULL ではありません。

MariaDB [hello]> insert into myclass values ('510','');
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> select * from myclass;
+------------+------------+
| class_name | class_room |
+------------+------------+
| 510        |            |
+------------+------------+
1 row in set (0.000 sec)

2.デフォルト値デフォルト

特定のウェブサイトに登録する際、一部の情報が入力されていない場合は、システムによってデフォルトとして設定されます。

たとえば、年齢を選択しない場合、システムはあなたを 0 歳として表示することがありますが、他のユーザーは、あなたの個人ホームページに表示される 0 歳を見たときに、あなたが本当の年齢を入力していないことがわかります。(フロントエンド開発時は0が未入力とみなし「非表示年齢」として表示することもできます)

また、弊社ウェブサイトにはユーザーポイントの値があり、ユーザー登録時にはポイントを0にする必要があります(新規ユーザーにポイントを付与する運用は当面考慮しておりません)。ポイント列の値は 0 に設定できます。挿入時にこの列にデータを明示的に挿入する必要はありません。

MySQL では、カラムにデフォルト値が設定された後。挿入時にこの列のデータが指定されていない場合は、デフォルト値が使用されます。

create table if not exists web_user(
    name varchar(30) not null default '默认用户名',
    age tinyint not null default 0,
    gender char(2) not null default '男' 
);

このテーブルを作成した後、テーブル構造を確認すると、テーブルが空かどうか、およびデフォルトの関連属性がわかります。

MariaDB [hello]> desc web_user;
+--------+-------------+------+-----+-----------------+-------+
| Field  | Type        | Null | Key | Default         | Extra |
+--------+-------------+------+-----+-----------------+-------+
| name   | varchar(30) | NO   |     | 默认用户名      |       |
| age    | tinyint(4)  | NO   |     | 0               |       |
| gender | char(2)     | NO   |     | 男              |       |
+--------+-------------+------+-----+-----------------+-------+
3 rows in set (0.004 sec)

このテーブルの 3 つのフィールドに初期値を設定しているため、何も指定せずにデータを直接挿入することもできます。以下に示すように、すべての列がその列の初期値に設定されます。

MariaDB [hello]> insert into web_user values ();
Query OK, 1 row affected (0.001 sec)

MariaDB [hello]> select * from web_user;
+-----------------+-----+--------+
| name            | age | gender |
+-----------------+-----+--------+
| 默认用户名      |   0 | 男     |
+-----------------+-----+--------+
1 row in set (0.000 sec)

デフォルト値は、特定の列の値を設定したくない場合に役立ちます。

これはエラーのデモです。valuesには2つの値を設定するだけですが、新しく挿入されたユーザーの性別にデフォルト値を採用させることが目的です。しかし、MySQL は値の数が列の数と一致しないというエラーを報告しました。

MariaDB [hello]> insert into web_user values ('李华',16);
ERROR 1136 (21S01): Column count doesn't match value count at row 1

これは、挿入時に、これら 2 つの値がどの列であるかを MySQL に明示的に伝えなかったためです。李華さんは名前や性別を記載していますか?MySQL にはそれ自体を決定する方法がありません。したがって、単純に挿入を拒否します。

したがって、特定のカラムにデフォルト値を使用させたい場合は、現在指定している値がデータのどのカラムであるかを MySQL に伝える必要があります。

insert into web_user (name,age) values ('李华',16);

この方法でのみ挿入を成功させることができます

MariaDB [hello]> insert into web_user (name,age) values ('李华',16);
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> select * from web_user;
+-----------------+-----+--------+
| name            | age | gender |
+-----------------+-----+--------+
| 默认用户名      |   0 | 男     |
| 李华            |  16 | 男     |
+-----------------+-----+--------+
2 rows in set (0.001 sec)

ここでは列名を表示して指定するため、必ずしもテーブル内の列名の順序に従う必要はなく、例えば以下のように逆に挿入することも可能です。ただし、これを行うことはお勧めできません。挿入時の列名の順序は、テーブル内の列の順序と一致している必要があります。

MariaDB [hello]> insert into web_user (age,name) values (18,'小李');
Query OK, 1 row affected (0.001 sec)

MariaDB [hello]> select * from web_user;
+-----------------+-----+--------+
| name            | age | gender |
+-----------------+-----+--------+
| 默认用户名      |   0 | 男     |
| 李华            |  16 | 男     |
| 小李            |  18 | 男     |
+-----------------+-----+--------+
3 rows in set (0.001 sec)

age 列に初期値を使用する場合は、次のように挿入します。

MariaDB [hello]> insert into web_user (name,gender) values ('菲菲公主','女');
Query OK, 1 row affected (0.005 sec)

2.1 デフォルト値とNULL

デフォルト値とNOT NULL併用する必要はないことに注意してください。

  • デフォルト値を設定しているが設定されていない場合はNOT NULL、明示的に NULL を挿入できます。
  • デフォルト値を NULL に設定することもできます
create table if not exists test_user(
    name varchar(30) not null default '默认用户名',
    age tinyint not null default 0,
    gender char(2) default null
);

上記の SQL を使用してテーブルを作成すると、データベースはエラーを報告しません。これは、構文がサポートされていることを意味します。性別は操作に関与する必要がないため、性別の欄が空の場合は未选择性别オプションであると考えることができます。ただし、この問題は、デフォルト値として空の文字列を使用することによっても解決できます。それと比較して、空の文字列を使用すると、null の特別な処理を必要とせずに、このフィールドの値が常に文字列になるため、より優れています。

画像-20230804095037098

default null一緒に使用することはできませんnot null、それは確かです!

3. 列の説明コメント

SQLite ではコメントがサポートされていないことに注意してください。データベースが異なると、SQL フィールドのサポートが若干異なります。使用しているデータベースを参照してください。この記事で説明する内容は、MySQL と MariaDB に基づいています。

いわゆる列の説明は、列の機能の説明であり、コードのコメントに相当します。それ自体には何の意味もありません。

列コメントの主な機能は、このデータベースとこのテーブルを使用するすべてのユーザーがこのフィールドの役割を理解できるようにすることです。追加のコメントを追加して、プログラマがさまざまなモジュールのアップロード コードで追加の処理を実行できるようにすることもできます。

たとえば、2 番目のポイントで登場した user テーブルを次の形式に変更し、各フィールドにコメントを追加します。

create table if not exists web_user(
    name varchar(30) not null default '默认用户名' comment '用户名',
    age tinyint not null default 0 comment '用户年龄',
    gender char(2) not null default '男' comment '用户性别' 
);

この SQL を使用してこのテーブルを作成した後、フィールドのコメントをクエリする場合は、次のコマンドを使用して、テーブルの作成時に使用されたコマンド (テーブルのコメントを含む) を表示できます。

SHOW CREATE TABLE web_user;

以下のように表示されます

MariaDB [hello]> SHOW CREATE TABLE web_user;
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                                                                                                                                                                               |
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| web_user | CREATE TABLE `web_user` (
  `name` varchar(30) NOT NULL DEFAULT '默认用户名' COMMENT '用户名',
  `age` tinyint(4) NOT NULL DEFAULT 0 COMMENT '用户年龄',
  `gender` char(2) NOT NULL DEFAULT '男' COMMENT '用户性别'
) ENGINE=InnoDB DEFAULT CHARSET=utf8                  |
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

次のコマンドを使用して、コメントを含むすべての列と列のプロパティを表示することもできます。

SHOW FULL COLUMNS FROM web_user;
MariaDB [hello]> SHOW FULL COLUMNS FROM web_user;
+--------+-------------+-----------------+------+-----+-----------------+-------+---------------------------------+--------------+
| Field  | Type        | Collation       | Null | Key | Default         | Extra | Privileges                      | Comment      |
+--------+-------------+-----------------+------+-----+-----------------+-------+---------------------------------+--------------+
| name   | varchar(30) | utf8_general_ci | NO   |     | 默认用户名      |       | select,insert,update,references | 用户名       |
| age    | tinyint(4)  | NULL            | NO   |     | 0               |       | select,insert,update,references | 用户年龄     |
| gender | char(2)     | utf8_general_ci | NO   |     | 男              |       | select,insert,update,references | 用户性别     |
+--------+-------------+-----------------+------+-----+-----------------+-------+---------------------------------+--------------+
3 rows in set (0.002 sec)

desc コマンドによって表示される結果には、列のコメントが含まれないことに注意してください。

MariaDB [hello]> desc web_user;
+--------+-------------+------+-----+-----------------+-------+
| Field  | Type        | Null | Key | Default         | Extra |
+--------+-------------+------+-----+-----------------+-------+
| name   | varchar(30) | NO   |     | 默认用户名      |       |
| age    | tinyint(4)  | NO   |     | 0               |       |
| gender | char(2)     | NO   |     | 男              |       |
+--------+-------------+------+-----+-----------------+-------+
3 rows in set (0.001 sec)

画像-20230804101749987

4.ゼロフィル

4.1 テスト結果

まず、次のコマンドを使用してテーブルを作成します

create table if not exists test_int(
	a int not null,
	b int unsigned not null
);

作成が完了したら、このテーブルの作成に使用されたステートメントを確認すると、int の後に余分な括弧があり、その後に数字が続いていることがわかります。

char と varchar では、文字列の文字長を制限するために括弧が使用されることはわかっていますが、整形には括弧がどのように使用されるのでしょうか?

MariaDB [hello]> show create table test_int;
+----------+------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                           |
+----------+------------------------------------------------------------------------------------------------------------------------+
| test_int | CREATE TABLE `test_int` (
  `a` int(11) NOT NULL,
  `b` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.001 sec)

まず、このテーブルにデータを挿入し、クエリを実行してそれを表示します。

MariaDB [hello]> insert into test_int values (3,1);
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> select * from test_int;
+---+---+
| a | b |
+---+---+
| 3 | 1 |
+---+---+
1 row in set (0.000 sec)

列 a の属性を次のフィールド タイプに変更すると、

alter table test_int change a a int(5) unsigned zerofill;

再度テーブル作成コマンドを確認すると以下のようになり、a列が文字の属性に変更されました。

MariaDB [hello]> alter table test_int change a a int(5) unsigned zerofill;
Query OK, 1 row affected (0.005 sec)               
Records: 1  Duplicates: 0  Warnings: 0

MariaDB [hello]> show create table test_int;
+----------+---------------------------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                                                |
+----------+---------------------------------------------------------------------------------------------------------------------------------------------+
| test_int | CREATE TABLE `test_int` (
  `a` int(5) unsigned zerofill DEFAULT NULL,
  `b` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+---------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

それでは、括弧内の数字はゼロフィルで何をするのでしょうか?

このテーブルを再度クエリすると、挿入したばかりのデータが列 a の 3 に変更されていることがわかります00003

MariaDB [hello]> select * from test_int;
+-------+---+
| a     | b |
+-------+---+
| 00003 | 1 |
+-------+---+
1 row in set (0.000 sec)

4.2 0によるパディング

現時点では、この属性の役割は非常に明確です。数値を 0 で埋めるために使用されます。5 は数値の長さではなく、指定された 0 の埋め込みの長さです。桁数が 5 未満の場合、パッド 0 をトリガーします。

int(5)テーブル構造に表示されている場合でも、このテーブルに 5 桁を超える数値を挿入できることがわかります。

MariaDB [hello]> insert into test_int values (12345678,1);
Query OK, 1 row affected (0.005 sec)

したがって、この括弧は int の長さを制限するために使用されるのではなく、数値が 5 桁に満たない場合、数値の前に 0 が追加されます。

MariaDB [hello]> insert into test_int values (18,3);
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> select * from test_int;
+----------+---+
| a        | b |
+----------+---+
|    00003 | 1 |
| 12345678 | 1 |
|    00018 | 3 |
+----------+---+
3 rows in set (0.001 sec)

これより長い値に変更するとint(5) zerofill、先頭の 0 の長さが変わります。

alter table test_int change a a int(7) unsigned zerofill;
MariaDB [hello]> alter table test_int change a a int(7) unsigned zerofill;
Query OK, 0 rows affected (0.007 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [hello]> select * from test_int;
+----------+---+
| a        | b |
+----------+---+
|  0000003 | 1 |
| 12345678 | 1 |
|  0000018 | 3 |
+----------+---+
3 rows in set (0.001 sec)

int(n)の属性は、zerofillと一緒に使用される前に 0 を追加する操作のみをトリガーすることに注意してください。これは、最初に作成されたテーブルの数値int(11)にゼロが埋め込まれていない理由を説明することができます。

ここで先頭に追加された 0 は、 MySQL の内部で表示される単なる最適化です。実際、数値自体はまだ保存されています。たとえば、上記の表で 3 をクエリすると、それを直接見つけることができます。

MariaDB [hello]> select * from test_int where a = 3;
+---------+---+
| a       | b |
+---------+---+
| 0000003 | 1 |
+---------+---+
1 row in set (0.001 sec)

たとえば、保存したい数値はすべて 5 桁で、先頭の 0 が設定されている場合、テーブル全体をクエリしたときに表示される書式設定された出力結果は、先頭の 0 がない結果よりもはるかに快適に見えます。

4.3 なぜ int は 11 で unsigned 10 なのでしょうか?

前にデフォルトの create table i ステートメントをクエリすると、MySQL システムのデフォルトが int の場合は 11 ビット、unsigned int の場合は 10 ビットであることがわかります。

画像-20230804104708752

これは、10 ビットの長さで int 範囲内のすべての値をすでに識別でき、符号付き整数には正負の符号を表示するために使用されるもう 1 ビットがあるためです。

5.主キー

主キーはフィールド内のデータを制限するために使用されます。繰り返したり、空にしたりすることはできません。テーブルには主キーが 1 つだけ (またはまったくありません)、通常は整数が主キーとして使用されます。

主キーは、テーブル内の各レコードの一意性を決定するために使用され、このテーブルにデータを挿入する場合は、主キーの値が競合しないようにする必要があることをユーザーに通知します。

5.1 主キーの設計タイプ

ユーザーシステムを例に挙げます

  • ユーザー名を主キーとして設定できます。ユーザーが既存のユーザー名を選択すると、そのユーザー名を拒否してユーザーに通知します。
  • 別の無関係な番号を主キーとして使用できます。たとえば、QQ はユーザーの一意性を識別するために QQ 番号を使用します。ユーザーのユーザー名が同じであってはいけないという必要はありません (現在、ほとんどのチャット ソフトウェアがこの方法を使用しています。 QQ や KOOK のように、WeChat には QQ のような一意の識別子はありませんが、バックグラウンドで一意の識別子として主キーが必要です)、
  • 複数の列を結合して複合主キーにすることができます

5.2 主キーの削除と追加

テーブルを作成するときは、次の 2 つの方法で主キーを指定できます。

-- 方法1,在字段后指明
create table test_pri_1(
	id int unsigned not null primary key,
    name varchar(30) not null
);
-- 方法2,在表的最后指明
create table test_pri_2(
	id int unsigned not null,
    name varchar(30) not null,
    primary key(id)
);

どちらも正常に実行できます。

また、主キー自体を空にすることはできないため、主キー列を定義するときに主キーを記述する必要はありません。not null

MariaDB [hello]> create table test_pri_1(
    -> id int unsigned not null primary key,
    ->     name varchar(30) not null
    -> );
Query OK, 0 rows affected (0.017 sec)

MariaDB [hello]> create table test_pri_2(
    -> id int unsigned not null,
    ->     name varchar(30) not null,
    ->     primary key(id)
    -> );
Query OK, 0 rows affected (0.019 sec)

テーブル構造も同じで、id列のKeyにPRIと表示されていますが、これは のPrimary略であり、id列が主キーであることを意味します。

MariaDB [hello]> desc test_pri_1;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(10) unsigned | NO   | PRI | NULL    |       |
| name  | varchar(30)      | NO   |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.001 sec)

MariaDB [hello]> desc test_pri_2;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(10) unsigned | NO   | PRI | NULL    |       |
| name  | varchar(30)      | NO   |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.001 sec)

既存のテーブルの場合は、主キーを追加したり、主キーを削除したりすることもできます。

alter table 表名 drop primary key;
-- 用于删除主键列的主键属性,因为主键列只能有一个
-- 注意,这个语句不会删除该列
alter table 表名 add primary key(id);
-- 给id列加上主键属性(但是ID列里面不能有重复值)

テストすると、id 列の PRI 属性がなくなっていることがわかります。

MariaDB [hello]> alter table test_pri_1 drop primary key;
Query OK, 0 rows affected (0.010 sec)              
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [hello]> desc test_pri_1;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(10) unsigned | NO   |     | NULL    |       |
| name  | varchar(30)      | NO   |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.002 sec)

テーブルにデータを挿入するときに、同じレコードを主キー列に挿入したい場合、MySQL は挿入を拒否します。

MariaDB [hello]> insert into test_pri_2  values (1,'李华');
Query OK, 1 row affected (0.006 sec)

MariaDB [hello]> insert into test_pri_2  values (1,'李明');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

5.3 複合主キー

テーブルには主キーが 1 つだけありますが、主キーには複数の列を含めることができます

私が自分で作成したアクティビティ統計ロボットを例に挙げます。ロボットは異なるサーバーにあり、異なるユーザーから異なるサーバー ID と操作を受け取ります。異なるサーバー上の異なるユーザーのアクティビティをユーザー統計テーブルに記録するには、次のようにします。サーバー ID とユーザー ID の両方が必要です。この時点で、ユーザーは 2 つのサーバーに参加し、両方のサーバーが私のロボットを使用します。テーブルにフィードバックされると、ユーザー ID が 2 回表示されますが、対応するサーバー ID は異なります。

この場合、ユーザー ID またはサーバー ID を単独で主キーとして設定することはできません。ユーザー ID とサーバー ID を主キーと一致するように設定できます。

複合主キーを設定すると、同じサーバー ID と同じユーザー ID を使用できるようになります。ただし、指定できるのは特定のサーバーのユーザーのみであり同じサーバー ID とユーザー IDを持つレコードが2 つ存在することはできません。これが複合主キーの目的です。

create table user(
	guild_id int unsigned comment '服务器ID',
	user_id int unsigned not null comment '用户ID',
	score tinyint unsigned not null default 0 comment '用户积分',
	primary key(guild_id, user_id) -- guild_id + user_id 为复合主键
);

このときのテーブル構造を見ると、サーバー ID とユーザー ID の 2 つのキー値が Key に属性を持っていることがわかります。つまり、PRIどちらも主キーです。

また、たとえguild_id指定されていない場合でもnot null、そのNULL属性は NO です。主キーを NULL にすることはできないためです。

MariaDB [hello]> create table user(
    -> guild_id int unsigned comment '服务器ID',
    -> user_id int unsigned not null comment '用户ID',
    -> score tinyint unsigned not null default 0 comment '用户积分',
    -> primary key(guild_id, user_id) -- guild_id + user_id 为复合主键
    -> );
Query OK, 0 rows affected (0.011 sec)

MariaDB [hello]> desc user;
+----------+---------------------+------+-----+---------+-------+
| Field    | Type                | Null | Key | Default | Extra |
+----------+---------------------+------+-----+---------+-------+
| guild_id | int(10) unsigned    | NO   | PRI | NULL    |       |
| user_id  | int(10) unsigned    | NO   | PRI | NULL    |       |
| score    | tinyint(3) unsigned | NO   |     | 0       |       |
+----------+---------------------+------+-----+---------+-------+
3 rows in set (0.003 sec)

挿入すると、サーバー ID とユーザー ID をそれぞれの列で繰り返すことができます。

MariaDB [hello]> insert into user values (1,1,0);
Query OK, 1 row affected (0.008 sec)

MariaDB [hello]> insert into user values (1,2,0);
Query OK, 1 row affected (0.008 sec)

MariaDB [hello]> insert into user values (2,1,0);
Query OK, 1 row affected (0.001 sec)

ただし、サーバー ID 1 とユーザー ID 1の既存のレコードに基づいて別のそのようなレコードを挿入したい場合は、エラーが報告され、挿入は拒否されます。

MariaDB [hello]> select * from user;
+----------+---------+-------+
| guild_id | user_id | score |
+----------+---------+-------+
|        1 |       1 |     0 |
|        1 |       2 |     0 |
|        2 |       1 |     0 |
+----------+---------+-------+
3 rows in set (0.000 sec)

MariaDB [hello]> insert into user values (1,1,10);
ERROR 1062 (23000): Duplicate entry '1-1' for key 'PRIMARY'

6.自動インクリメント

自動インクリメントは、名前が示すように、MySQL がこの列にデータを自動的に追加することを意味します。たとえば、シリアル番号の場合、新しいレコードを追加するとシリアル番号が 1 つ増加します。自動インクリメント属性はシェーピングにのみ追加できます。

自動インクリメントされる列は主キーである必要があります。

6.1 使用方法

自動インクリメントを使用する方法は、テーブルのキー値を作成した後にこの制約を追加することです。

create table test_pri_3(
	id int unsigned auto_increment,
    name varchar(30) not null,
    primary key(id)
);

テーブル構造を見ると、id 列が主キーであり、空ではなく、自動インクリメント属性があることがわかります。

MariaDB [hello]> desc test_pri_3;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name  | varchar(30)      | NO   |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.003 sec)

自動インクリメント列は主キーである必要があるため、主キーとは別に使用することはできません。

自動インクリメントの設定時にこの列が主キーとして設定されていない場合、テーブルの作成時にエラーが報告されます。

MariaDB [hello]> create table test_pri_4(
    -> id int unsigned auto_increment,
    ->     name varchar(30) not null
    -> );
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key

自動インクリメントを設定した後、列の値を明示的に指定することもできます。また、値を指定せずに他の列からデータを直接挿入することもできます。MySQL は、現在のレコードを +1 するのに自動的に役立ちます。

MariaDB [hello]> insert into test_pri_3 values (1,'李华');
Query OK, 1 row affected (0.007 sec)

MariaDB [hello]> select * from test_pri_3;
+----+--------+
| id | name   |
+----+--------+
|  1 | 李华   |
+----+--------+
1 row in set (0.001 sec)

MariaDB [hello]> insert into test_pri_3 (name) values ('小明');
Query OK, 1 row affected (0.001 sec)

MariaDB [hello]> select * from test_pri_3;
+----+--------+
| id | name   |
+----+--------+
|  1 | 李华   |
|  2 | 小明   |
+----+--------+
2 rows in set (0.000 sec)

さらにいくつかのデータを挿入すると、ID 列が正常にインクリメントされたことがわかります。

MariaDB [hello]> insert into test_pri_3 (name) values ('小明3');
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> insert into test_pri_3 (name) values ('小明5');
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> select * from test_pri_3;
+----+---------+
| id | name    |
+----+---------+
|  1 | 李华    |
|  2 | 小明    |
|  3 | 小明3   |
|  4 | 小明5   |
+----+---------+
4 rows in set (0.000 sec)

6.2 自動インクリメントは現在のシリアル番号の位置をどのように決定しますか?

自動増加する長さは最大値から始まりますか? それとも他の処理手順があるのでしょうか?

まず、キー値 1000 をテーブルにアクティブに挿入してから、ID を指定せずに 2 行のレコードを挿入してみます。

MariaDB [hello]> insert into test_pri_3 values (1000,'test');
Query OK, 1 row affected (0.006 sec)

MariaDB [hello]> insert into test_pri_3 (name) values ('test1');
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> insert into test_pri_3 (name) values ('test2');
Query OK, 1 row affected (0.001 sec)

リストをクエリすると、1000 以降のレコードはすべて 1000 から追加されていることがわかります。

MariaDB [hello]> select * from test_pri_3;
+------+---------+
| id   | name    |
+------+---------+
|    1 | 李华    |
|    2 | 小明    |
|    3 | 小明3   |
|    4 | 小明5   |
| 1000 | test    |
| 1001 | test1   |
| 1002 | test2   |
+------+---------+
7 rows in set (0.000 sec)

最大の ID に基づいて自動的にインクリメントされるのでしょうか? もう一度試してみましょう。

まず最大の ID を持つレコードを削除してから、新しいデータを挿入します。

MariaDB [hello]> delete from test_pri_3 where id = 1002;
Query OK, 1 row affected (0.007 sec)

MariaDB [hello]> insert into test_pri_3 (name) values ('test3');
Query OK, 1 row affected (0.006 sec)

再度クエリを実行すると、自動インクリメントされた ID が 1003 であることがわかります。テーブル内の id 列の最大値を判断するのではなく、内部に記録された id の最大値が追加の内部レコードに従って自動的にインクリメントされることがわかります。

MariaDB [hello]> select * from test_pri_3;
+------+---------+
| id   | name    |
+------+---------+
|    1 | 李华    |
|    2 | 小明    |
|    3 | 小明3   |
|    4 | 小明5   |
| 1000 | test    |
| 1001 | test1   |
| 1003 | test3   |
+------+---------+
7 rows in set (0.001 sec)

では、この追加レコードはどこにあるのでしょうか?

show create table test_pri_3;

上記のコマンドを使用して、テーブルを作成する SQL ステートメントを表示すると、テーブルの直後に自動インクリメント フィールドがあることがわかります。AUTO_INCREMENT=1004

MariaDB [hello]> show create table test_pri_3;
+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table      | Create Table                                                                                                                                                                              |
+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_pri_3 | CREATE TABLE `test_pri_3` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1004 DEFAULT CHARSET=utf8 |
+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

これは、MySQL の自動インクリメント フィールドの現在の値の定義です。ここに保存されるのは、次に挿入されるレコードの自動インクリメント値とその ID です。新しいレコードが挿入されるたびに、ここでの自動インクリメント値が次のレコードの値に変換されます。

たとえば、システムの ID を 10001 から増やしたい場合は、テーブルの作成後に、ID 10000 のレコードをテーブルに直接挿入できます。これ以降に作成される他のレコードの ID は 10001 から増加します。

画像-20230804133951367

6.3 索引

そういえば、MySQL のインデックスの概念について触れておきます。

インデックス: リレーショナル データベースでは、インデックスはデータベース テーブル内の 1 つ以上の列の値を並べ替える別個の物理ストレージ構造です。これは、テーブル内の 1 つ以上の列値のコレクションと、これらの値を物理的に識別するテーブル内のデータ ページへの対応する論理ポインタのリストです。

索引は書籍の目次に相当し、目次のページ番号から必要な内容をすぐに見つけることができます。インデックスは、テーブルの指定された列に格納されているデータ値へのポインターを提供し、指定した並べ替え順序に従ってこれらのポインターを並べ替えます。データベースはインデックスを使用して特定の値を検索し、前方をポイントしてその値を含む行を検索します。

これにより、テーブルに対応する SQL ステートメントがより高速に実行され、データベース テーブル内の特定の情報に迅速にアクセスできるようになります。

インデックス作成は基本的に、スペースと時間を交換するルーチンです。現在のマルチ同時実行ビジネスでは、メモリやディスクの使用量よりも実行速度の方がはるかに重要です。

7. ユニークキー ユニーク

フィールドの一意キーの制約は、この列のデータを同じにすることができないことです。

主キーに似ていますが、実際には主キーとは独立した一意制約です。主キーとの違いは、一意のキーが NULL になる可能性があることです。

ご存知のように、テーブルに設定できる主キーは 1 つだけです。複合主キーはニーズを満たさない場合があります。そのため、MySQL は主キーに加えて追加の一意キー制約を提供し、他のカラムに一意性を設定できるようにします。

なぜですか?これは免責事項のようなものです: 私の列のデータは一意になるように設定されているため、2 つの同一のレコードを受け入れることはできません (たとえば、ユーザー テーブル内の 2 人の人物が同じ携帯電話番号を持っていることは許可されません)。挿入が拒否されたときにエラーが発生した場合は、MySQL が一意性を維持していない、またはレコードの挿入を拒否していると非難するのではなく、ビジネス処理コードのバグを確認する必要があります。

7.1 個別に一意のキー

QQ と同様に QQ 番号をユーザーの主キーとして使用するプラットフォームがあるとしますが、実名認証では 1 つの ID カードに 1 つのアカウントしか登録できないようにする必要があります。現時点では、複合主キーを使用すると列の 1 つを繰り返すことができるため、この問題を解決するために複合主キーを使用することはできません。必要なのは、ユーザー アカウント番号とユーザー ID 番号を繰り返すことができないことです。

同時に、ユーザーの連絡先情報で、2 人のユーザーの電話番号と WeChat ID が同じであってはならず、電話番号のキー値を追加したい場合は、それを設定することもできますunique

このとき、ユーザー番号を主キーとして使用し、ユーザー ID 番号をunique一意のキーとして設定できます。

create table test_unique_1(
	no int unsigned not null primary key,
	name varchar(30) not null,
    id_card varchar(30) not null unique 
);

テーブル構造、一意のキー列を表示します。キー制約は UNI (UNI のunique略称)です。

MariaDB [hello]> desc test_unique_1;
+---------+------------------+------+-----+---------+-------+
| Field   | Type             | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| no      | int(10) unsigned | NO   | PRI | NULL    |       |
| name    | varchar(30)      | NO   |     | NULL    |       |
| id_card | varchar(30)      | NO   | UNI | NULL    |       |
+---------+------------------+------+-----+---------+-------+
3 rows in set (0.001 sec)

id_card同じレコードを主キー列またはこのテーブルの列に挿入すると、MySQL は挿入を拒否します。

MariaDB [hello]> insert into test_unique_1 values (1,'李华',123456);
Query OK, 1 row affected (0.006 sec)

MariaDB [hello]> insert into test_unique_1 values (1,'李华',1234567);
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

MariaDB [hello]> insert into test_unique_1 values (3,'小明',123456);
ERROR 1062 (23000): Duplicate entry '123456' for key 'id_card'

7.2 複合一意キー

一意キーには複数の列を設定することもでき、その効果は複合主キーと同じであるため、ここでは説明しません。

create table user(
	user_no int unsigned primary key auto_increment comment '用户编号 主键',
	guild_id int unsigned comment '服务器ID',
	user_id int unsigned not null comment '用户ID',
	score tinyint unsigned not null default 0 comment '用户积分',
	unique(guild_id, user_id) -- guild_id + user_id 为复合唯一键
);

テーブル内のペアの制約は、次の図に示すように にguild_id和user_idなります。MUL

guild_id設定がないためnot null、NULL 列は YES であることがわかります。これは、この列が NULL になる可能性があることを意味します (一意のキーは NULL にすることができますが、主キーは NULL にすることはできません)

MUL は、現在、この列内で複数の行が同じ値を持つことは許可されていますが、guild_id和user_id同じ 2 つの行が存在することは許可されていないことを意味します。

MariaDB [hello]> desc user;
+----------+---------------------+------+-----+---------+----------------+
| Field    | Type                | Null | Key | Default | Extra          |
+----------+---------------------+------+-----+---------+----------------+
| user_no  | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| guild_id | int(10) unsigned    | YES  | MUL | NULL    |                |
| user_id  | int(10) unsigned    | NO   |     | NULL    |                |
| score    | tinyint(3) unsigned | NO   |     | 0       |                |
+----------+---------------------+------+-----+---------+----------------+
4 rows in set (0.001 sec)

以下に示すように、最後の挿入は最初の挿入と同じであるguild_id和user_idため、挿入拒否エラーが発生します。

MariaDB [hello]> insert into user values (1,1,1,20);
Query OK, 1 row affected (0.006 sec)

MariaDB [hello]> insert into user values (2,1,2,21);
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> insert into user values (3,2,3,22);
Query OK, 1 row affected (0.006 sec)

MariaDB [hello]> insert into user values (4,1,1,23);
ERROR 1062 (23000): Duplicate entry '1-1' for key 'guild_id'

7.3 MySQL の MUL、PRI、UNI とは何ですか?

Mysql 5.7公式 Web サイトのドキュメントから:

  • キーが PRI の場合、列は主キー、または複数列の主キー内の列の 1 つです。
  • キーが UNI の場合、この列は一意のインデックスの最初の列になります (一意のインデックスでは複数の NULL 値が許可されますが、列が NULL を許可するかどうかは NULL フィールドをチェックすることで判断できます)。
  • キーが MUL の場合、その列は非一意インデックスの最初の列となり、列内で特定の値が複数出現することが許可されます。

8.外部キー

8.1 説明

外部キーは、2 つのテーブル内の特定のフィールド間の関係を定義し、レコードを制約するために使用されます。

基本的な構文は次のとおりで、テーブルを作成するときに使用されます。外部キーが設定されているテーブルがスレーブテーブルです!

foreign key (字段名) references 主表()

たとえば、下図では、student テーブルの各生徒のクラス番号が、class テーブルのクラス ID に対応していますが、このとき、クラス テーブルの ID を、student テーブルの外部キーとして設定できますclass_id

class テーブルのデータを Student テーブルに直接挿入することもできますが、これは合理的ではありません。クラスまたは生徒用に多くのフィールドがある場合、これら 2 つのテーブルを組み合わせるのは非常に不便です。同じクラスの生徒が多いため、テーブルを結合すると同じクラスの生徒と等価になり、クラス列の情報がすべて同じになり、無意味なリソースの占有(冗長性)が生じます。

対照的に、テーブルを分割した後は、外部キーを使用して2 つのフィールドをバインドすることをお勧めします。

画像-20230804161621345

上記の状況では、myclass がマスター テーブルであり、stu がスレーブ テーブルです。

-- 主表 班级
create table myclass (
	id int primary key comment '班级号',
	name varchar(30) not null comment '班级名'
);
-- 从表 学生
create table stu (
	id int primary key,
	name varchar(30) not null comment '学生名',
	class_id int,
	foreign key (class_id) references myclass(id) -- 设置从表外键约束
);

8.2 テスト

class_idテーブルを作成した後、まず Student テーブル i の属性を見てみましょう。テーブルのキーは、前に複合一意キーを設定したときと同じ MUL であることがわかります。

MariaDB [hello]> desc stu;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | NO   | PRI | NULL    |       |
| name     | varchar(30) | NO   |     | NULL    |       |
| class_id | int(11)     | YES  | MUL | NULL    |       |
+----------+-------------+------+-----+---------+-------+
3 rows in set (0.001 sec)

Student テーブルにデータを挿入しようとすると、エラーが報告されます。

MariaDB [hello]> insert into stu values (1,'李华',2);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`hello`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))

これは、設定したレコードでは、生徒のクラス番号 2 がクラス テーブルにまったく存在しないためです。存在しないクラスにどうやって生徒がいるでしょうか? したがって、当然のことながら挿入を拒否します。

したがって、学生を挿入したい場合は、学生のレコードが存在するクラスがクラス テーブルに存在することを確認する必要があります。このようにして、学生とクラスの N 対 1 のバインドが実現されます。

MariaDB [hello]> insert into myclass values (1,'少华班');
Query OK, 1 row affected (0.002 sec)

MariaDB [hello]> insert into stu values (1,'李华',1);
Query OK, 1 row affected (0.005 sec)

MariaDB [hello]> select * from myclass;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 少华班    |
+----+-----------+
1 row in set (0.001 sec)

MariaDB [hello]> select * from stu;
+----+--------+----------+
| id | name   | class_id |
+----+--------+----------+
|  1 | 李华   |        1 |
+----+--------+----------+
1 row in set (0.000 sec)

ここにさらにいくつかのデータを挿入しました

MariaDB [hello]> select * from stu;
+----+-----------+----------+
| id | name      | class_id |
+----+-----------+----------+
|  1 | 李华      |        1 |
|  2 | 小明      |        1 |
|  3 | 小流      |        1 |
|  4 | 小流2     |        2 |
|  5 | 猪猪侠    |        2 |
|  6 | 苗条俊    |        2 |
+----+-----------+----------+
6 rows in set (0.000 sec)

MariaDB [hello]> select * from myclass;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 少华班    |
|  2 | 你好班    |
+----+-----------+
2 rows in set (0.000 sec)

現時点で別の質問があります。このクラスに生徒がいる場合、このクラスを削除できますか?

考えてみれば、それは絶対に不可能です。そのようなクラスがないため、対応する生徒を挿入することはできません。このクラスに生徒がいる場合は、クラスを削除しないでください。この 2 つは相互に論理的であり、MySQL でも同様であり、クラスに対応する学生がいる場合、削除は許可されません。

MariaDB [hello]> delete from myclass where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`hello`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))

このクラスに生徒がいなくなった場合にのみ、クラス テーブルからクラスを削除できます。

MariaDB [hello]> delete from stu where class_id = 2;
Query OK, 3 rows affected (0.005 sec)

MariaDB [hello]> delete from myclass where id = 2;
Query OK, 1 row affected (0.006 sec)

MariaDB [hello]> 

学生テーブルにはこのクラスにバインドされている学生が存在するため、クラス ID の更新も許可されません。MySQL では、すべての生徒のクラス番号を直接更新することはできません。

MariaDB [hello]> update  myclass set id = 3 where name = '你好班'; 
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`hello`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))

8.3 外部キー制約

上記の状況では、外部キー関係なしで 2 つの独立したテーブルを完全に確立し、コード層で 2 つのテーブル間の関係を維持できます。

ただし、この方法では、これら 2 つのテーブルの操作はまだ独立しています。MySQL は 2 つのテーブル間に接続があることを認識しません。この時点では、存在しないクラスに学生を挿入したり、まだ学生がいるクラスを削除したりできます。 . 落としてしまうと、最終的にはめちゃくちゃになってしまいます

  • 自己保守: 2 つの表の情報は関連しています。
  • プラス外部キー: MySQL 制約

2 つの組み合わせが完全な外部キーです。

そのため、MySQL でこれら 2 つのテーブル間に外部キー制約を定義し、MySQL に 2 つのテーブル内のデータ関係を維持させる必要があります。

注: 現時点では MySQL によって操作が制限されますが、実際のビジネス プロセスは依然としてプログラマーによってコード内で処理される必要があります。たとえば、クラスが存在しない学生を MySQL に挿入しないでください (MySQL は挿入を拒否するだけで、クラスの修正には役立ちません)。

終わり

これらは基本的な制約操作ですが、他にも使用されるものや将来追加されるものがあります。

おすすめ

転載: blog.csdn.net/muxuen/article/details/132158703