Chapter15 一連の処理と正規化

概要と目標 データベースにおける一連の処理と
正規化について学ぼう。

一連の処理を管理するトランザクションについてと、
テーブルの設計に役立つ正規化について学習しましょう。

今回のゴール

コマンドプロンプト

mysql> create database sales_management default character set utf8;
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> use sales_management;
Database changed
mysql> create table detail (
    ->   id int(11) unsigned auto_increment primary key,
    ->   sales_id int(6) unsigned zerofill not null,
    ->   product_id int(11) unsigned not null,
    ->   quantity int(11) unsigned not null
    -> ) engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> create table sales (
    ->   id int(6) unsigned zerofill auto_increment primary key,
    ->   order_date date not null,
    ->   customer_id int(11) unsigned not null
    -> ) engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> create table product (
    ->   id int(11) unsigned auto_increment primary key,
    ->   name varchar(255) not null,
    ->   price int(11) unsigned not null
    -> ) engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.01 sec)

mysql>
mysql> create table customer (
    ->   id int(11) unsigned auto_increment primary key,
    ->   name varchar(255) not null,
    ->   pref varchar(255) not null
    -> ) engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into detail (sales_id, product_id, quantity)
    ->   values (
    ->     1, 1, 2
    ->   ),
    ->   (
    ->     1, 2, 1
    ->   ),
    ->   (
    ->     1, 3, 5
    ->   ),
    ->   (
    ->     2, 4, 2
    ->   ),
    ->   (
    ->     2, 5, 1
    ->   ),
    ->   (
    ->     3, 1, 18
    ->   ),
    ->   (
    ->     3, 5, 1
    ->   ),
    ->   (
    ->     3, 6, 8
    ->   );
Query OK, 8 rows affected (0.01 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql>   insert into sales (order_date, customer_id)
    ->     values (
    ->       '2025-12-10', 1
    ->     ),
    ->     (
    ->       '2025-12-12', 2
    ->     ),
    ->     (
    ->       '2025-12-14', 3
    ->     );
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql>   insert into product (name, price)
    ->     values (
    ->       'えんぴつ', 50
    ->     ),
    ->     (
    ->       '消しゴム', 100
    ->     ),
    ->     (
    ->       'のり', 60
    ->     ),
    ->     (
    ->       'ものさし', 80
    ->     ),
    ->     (
    ->       'ノート', 100
    ->     ),
    ->     (
    ->       '文鎮', 100
    ->     );
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql>   insert into customer (name, pref)
    ->     values (
    ->       '秋元', '東京都'
    ->     ),
    ->     (
    ->       '前田', '東京都'
    ->     ),
    ->     (
    ->       '柴田', '大阪府'
    ->     );
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from product;
+----+--------------+-------+
| id | name         | price |
+----+--------------+-------+
|  1 | えんぴつ     |    50 |
|  2 | 消しゴム     |   100 |
|  3 | のり         |    60 |
|  4 | ものさし     |    80 |
|  5 | ノート       |   100 |
|  6 | 文鎮         |   100 |
+----+--------------+-------+
6 rows in set (0.00 sec)

mysql> select * from customer where pref = '東京都';
+----+--------+-----------+
| id | name   | pref      |
+----+--------+-----------+
|  1 | 秋元   | 東京都    |
|  2 | 前田   | 東京都    |
+----+--------+-----------+
2 rows in set (0.00 sec)

mysql> select count(*) as total from sales;
+-------+
| total |
+-------+
|     3 |
+-------+
1 row in set (0.00 sec)

mysql> select sales_id, sum(quantity) as total
    ->   from detail
    ->   group by sales_id;
+----------+-------+
| sales_id | total |
+----------+-------+
|   000001 |     8 |
|   000002 |     3 |
|   000003 |    27 |
+----------+-------+
3 rows in set (0.00 sec)

mysql> select d.sales_id, p.name, d.quantity
    ->   from detail as d join product as p
    ->   on d.product_id = p.id
    ->   order by d.sales_id asc;
+----------+--------------+----------+
| sales_id | name         | quantity |
+----------+--------------+----------+
|   000001 | えんぴつ     |        2 |
|   000001 | 消しゴム     |        1 |
|   000001 | のり         |        5 |
|   000002 | ものさし     |        2 |
|   000002 | ノート       |        1 |
|   000003 | えんぴつ     |       18 |
|   000003 | ノート       |        1 |
|   000003 | 文鎮         |        8 |
+----------+--------------+----------+
8 rows in set (0.01 sec)

mysql> select
    ->   d.sales_id,
    ->   s.order_date,
    ->   c.name as customer_name,
    ->   c.pref,
    ->   p.name as product_name,
    ->   p.price,
    ->   d.quantity
    ->   from
    ->     detail as d join
    ->     sales as s join
    ->     product as p join
    ->     customer as c
    ->   on
    ->     d.sales_id = s.id and
    ->     d.product_id = p.id and
    ->     s.customer_id = c.id
    ->   order by
    ->     d.sales_id asc;
+----------+------------+---------------+-----------+--------------+-------+----------+
| sales_id | order_date | customer_name | pref      | product_name | price | quantity |
+----------+------------+---------------+-----------+--------------+-------+----------+
|   000001 | 2025-12-10 | 秋元   | 東京都    | えんぴつ     |    50 |        2 |
|   000001 | 2025-12-10 | 秋元   | 東京都    | 消しゴム     |   100 |        1 |
|   000001 | 2025-12-10 | 秋元   | 東京都    | のり         |    60 |        5 |
|   000002 | 2025-12-12 | 前田   | 東京都    | ものさし     |    80 |        2 |
|   000002 | 2025-12-12 | 前田   | 東京都    | えんぴつ     |    50 |        1 |
|   000003 | 2025-12-14 | 柴田   | 大阪府    | えんぴつ     |    50 |       18 |
|   000003 | 2025-12-14 | 柴田   | 大阪府    | ノート       |   100 |        1 |
|   000003 | 2025-12-14 | 柴田   | 大阪府    | 文鎮         |   100 |        8 |
+----------+------------+--------+-----------+--------------+-------+----------+
8 rows in set (0.00 sec)

mysql>  

トランザクションとは 複数の更新処理をひとつにまとめる。

データベースにおいて一連の処理のことを「トランザクション」という。
具体的には、複数のデータの更新処理を1つにまとめて反映したり、取り消しを行ったりする機能のこと。

トランザクション
  1. 口座に残高が100万円 口座に残高が100万円
  2. 「振込」という一連の処理がスタート 「振込」という一連の処理がスタート
  3. 口座Aから振込分引いて、口座Bに振込分足す 口座Aから振込分引いて、口座Bに振込分足す
  4. 処理に問題がないので確定する 処理に問題がないので確定する
  5. 処理を確定することをコミットと言う 処理を確定することをコミットと言う
  6. また、「振込」という一連の処理がスタート また、「振込」という一連の処理がスタート
  7. 口座Aから振込分引く 口座Aから振込分引く
  8. 振込に失敗し口座Bの残高が増えていない 振込に失敗し口座Bの残高が増えていない
  9. 口座Aの出金処理を取り消す必要がある 口座Aの出金処理を取り消す必要がある
  10. 一連の処理を元に戻すことをロールバックと言う 一連の処理を元に戻すことをロールバックと言う

トランザクションの開始 一連の処理を開始するには、
START TRANSACTION」または「BEGIN」。

MySQLは通常、クエリを発行すると同時に自動的にコミットする。
従って、何かエラーがあった場合でも元に戻すことは出来ない。
そこで、「START TRANSACTION」または、「BEGIN」を使って、
トランザクションの開始を明示的に表すことで、一連の流れを管理することができる。

トランザクションの開始
START TRANSACTION;
-- または
BEGIN;

詳細は 13.3.1 START TRANSACTION、COMMIT、および ROLLBACK 構文を参照

トランザクションを
開始してみよう。

  1. MySQLモニタを起動
  2. 「chapter15」 › 「settings」 › 「該当文字コード」フォルダ内の「setting.sql」を
    sourceコマンド、またはファイルの内容をコピー&ペーストし、
    今回のレッスンに必要なデータベースとテーブル、レコードを作成する
source /php-lessons/chapter15/settings/Shift-JIS/settings.sql;

ファイルパスは変更(コマンドラインツールにドラッグ&ドロップ)して下さい

実行例

コマンドプロンプト

mysql> source /php-lessons/chapter15/settings/Shift-JIS/settings.sql
Query OK, 2 rows affected (0.05 sec)

Query OK, 1 row affected (0.00 sec)

Database changed
Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 0 rows affected (0.02 sec)

Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 1 row affected (0.01 sec)

Query OK, 1 row affected (0.00 sec)

+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 秋元   |  100000 | 2017-12-24 23:50:53 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 前田   |  100000 | 2017-12-24 23:50:53 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

mysql>  
  1. my_bank」データベースに作成されたテーブルレコードを確認
「account_a」テーブル
id name balance modified
1 秋元 100000 2017-12-24 23:50:53 (レコードを挿入した時間)
「account_b」テーブル
id name balance modified
1 前田 100000 2017-12-24 23:50:53 (レコードを挿入した時間)
  1. 「chapter15」フォルダ内の「transaction.sql」をテキストエディタで開く
  2. トランザクションを開始するコマンドを記述し、コマンドラインツールにコピー&ペースト
chapter15/transaction.sql
-- トランザクションの開始
begin;
実行例

コマンドプロンプト

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql>  

ここから、一連の処理を管理できる。

処理の取り消し 予期しないエラーが出ても、
ロールバックできる。

一連の処理の中で、何か予期しないエラーが出たり、処理がうまく行かなかった場合、
ROLLBACK」を使えば、一連の処理を取り消すことができる。

処理の取り消し
ROLLBACK;

詳細は 13.3.1 START TRANSACTION、COMMIT、および ROLLBACK 構文を参照

一連の処理を取り消してみよう。

  1. 「chapter15」フォルダ内の「transaction.sql」をテキストエディタで開く
  2. 出金と入金の処理を行うコマンドを記述し、コマンドラインツールにコピー&ペースト
chapter15/transaction.sql
-- 出金と入金の処理
update account_a set balance = 50000 where id = 1;
update account_b set balance = 125000 where id = 1;

select * from account_a;
select * from account_b;
実行例

コマンドプロンプト

mysql> update account_a set balance = 50000 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update account_b set balance = 125000 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>
mysql> select * from account_a;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 秋元   |   50000 | 2017-12-24 23:55:01 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

mysql> select * from account_b;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 前田   |  125000 | 2017-12-24 23:55:01 |
+----+--------+---------+---------------------+
1 row in set (0.01 sec)

mysql>  
  1. あれ!?出金金額と入金金額が一致しない!
    予期しない問題が起きたので、処理を取り消すコマンドを記述し、
    コマンドラインツールにコピー&ペースト
chapter15/transaction.sql
-- 一連の処理を取り消す
rollback;

select * from account_a;
select * from account_b;
実行例

コマンドプロンプト

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> select * from account_a;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 秋元   |  100000 | 2017-12-24 23:56:50 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

mysql> select * from account_b;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 前田   |  100000 | 2017-12-24 23:56:50 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

mysql>  

一連の処理が取り消された

処理の確定 処理が正常に行われたら、
コミットで確定する。

一連の処理が正常に行われた時は、COMMITで確定させる。
COMMITを忘れて、MySQLを終了するとその処理は取り消される。

処理の確定
COMMIT;

詳細は 13.3.1 START TRANSACTION、COMMIT、および ROLLBACK 構文を参照

処理を確定してみよう。

  1. 「chapter15」フォルダ内の「transaction.sql」をテキストエディタで開く
  2. 出金と入金の処理を行うコマンドを記述し、コマンドラインツールにコピー&ペースト
chapter15/transaction.sql
-- 出金と入金の処理
update account_a set balance = 50000 where id = 1;
update account_b set balance = 150000 where id = 1;

select * from account_a;
select * from account_b;
実行例

コマンドプロンプト

mysql> update account_a set balance = 50000 where id = 1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> update account_b set balance = 150000 where id = 1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql>
mysql> select * from account_a;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 秋元   |   50000 | 2018-03-25 00:07:23 |
+----+--------+---------+---------------------+
1 row in set (0.01 sec)

mysql> select * from account_b;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 前田   |  150000 | 2018-03-25 00:07:23 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

mysql> 
  1. 処理が正常に行われたので、処理を確定するコマンドを記述し、
    コマンドラインツールにコピー&ペースト
chapter15/transaction.sql
-- 処理を確定
commit;

select * from account_a;
select * from account_b;
実行例

コマンドプロンプト

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> select * from account_a;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 秋元   |   50000 | 2018-03-25 00:07:23 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

mysql> select * from account_b;
+----+--------+---------+---------------------+
| id | name   | balance | modified            |
+----+--------+---------+---------------------+
|  1 | 前田   |  150000 | 2018-03-25 00:07:23 |
+----+--------+---------+---------------------+
1 row in set (0.00 sec)

mysql> 

正規化 データの重複をなくし、
データを取り扱いやすくする。

正規化とは、データの重複をなくし整合的にデータを使えるようにデータベースを設計すること。
正規化をすれば、データの追加や更新、削除などに伴うデータの不整合や喪失が起きるのを防ぎ、
メンテナンス性を高めることができる。

非正規型
正規化されてないデータ。

非正規型とは、複数の繰り返し項目が存在するような正規化が行われていないテーブルのこと。

非正規型
注文番号 注文日 顧客名 送付先 商品名1 価格1 個数1 小計1 商品名2 価格2 個数2 小計2 商品名3 価格3 個数3 小計3
000001 2025-12-10 秋元 東京都 えんぴつ 50 2 100 消しゴム 100 1 100 のり 60 5 300
000002 2025-12-12 前田 東京都 ものさし 80 2 160 ノート 100 1 100
000003 2025-12-14 柴田 大阪府 えんぴつ 50 18 900 ノート 100 1 100 文鎮 100 8 800

第一正規化
繰り返しと導出を取り除く。

「商品名」、「価格」、「個数」の様に繰り返しがあるグループは、
データベースに格納できるように1レコードづつ並べる。
また、「小計」の様に、他の値から算出できる導出フィールドは削除する。
このように非正規型から、繰り返し導出を取り除くことを第一正規化という。

第一正規形
注文番号 注文日 顧客名 送付先 商品名 価格 個数
000001 2025-12-10 秋元 東京都 えんぴつ 50 2
000001 2025-12-10 秋元 東京都 消しゴム 100 1
000001 2025-12-10 秋元 東京都 のり 60 5
000002 2025-12-12 前田 東京都 ものさし 80 2
000002 2025-12-12 前田 東京都 ノート 100 1
000003 2025-12-14 柴田 大阪府 えんぴつ 50 18
000003 2025-12-14 柴田 大阪府 ノート 100 1
000003 2025-12-14 柴田 大阪府 文鎮 100 8

第二正規化
部分従属するフィールドを分離。

上記の第一正規形の場合は、「注文番号」、「商品名」の組み合わせで他の項目を特定することができる。
このように、レコードの他の項目を特定することができる、項目の組み合わせのことを「候補キー」と言う。
第二正規化は、この候補キーのどちらかだけで特定できるものは、別のテーブルに分割する。
具体的には、「注文番号」が分かれば、「注文日」、「顧客名」、「送付先」は特定できまる。
また、「商品名」が分かれば「価格」が特定できる。
このように候補キーのいずれかだけでも、他の項目を特定できることを「部分従属」といい、
第一正規形から、部分従属するフィールドを取り除くことを第二正規化という。

第二正規形(受注明細テーブル)
注文番号 商品ID 個数
000001 1 2
000001 2 1
000001 3 5
000002 4 2
000002 5 1
000003 1 18
000003 5 1
000003 6 8
第二正規形(受注テーブル)
注文番号 注文日 顧客名 送付先
000001 2025-12-10 秋元 東京都
000002 2025-12-12 前田 東京都
000003 2025-12-14 柴田 大阪府
第二正規形(商品テーブル)
商品ID 商品名 価格
1 えんぴつ 50
2 消しゴム 100
3 のり 60
4 ものさし 80
5 ノート 100
6 文鎮 100


第三正規化
推移従属しているフィールドを分離。

候補キー以外で従属しているものを、推移従属といい、
この推移従属についても別のテーブルに分割する。
具体的には、「送付先」は「顧客名」がわかれば特定することができる。
「顧客名」は候補キーではないので、推移従属していることになる。
このように第二正規形から、推移従属するフィールドを取り除くことを第三正規化という。

第三正規形(受注明細テーブル)
注文番号 商品ID 個数
000001 1 2
000001 2 1
000001 3 5
000002 4 2
000002 5 1
000003 1 18
000003 5 1
000003 6 8
第三正規形(受注テーブル)
注文番号 注文日 顧客ID
000001 2025-12-10 1
000002 2025-12-12 2
000003 2025-12-14 3

第三正規形(商品テーブル)
商品ID 商品名 価格
1 えんぴつ 50
2 消しゴム 100
3 のり 60
4 ものさし 80
5 ノート 100
6 文鎮 100
第三正規形(顧客テーブル)
顧客ID 顧客名 送付先
1 秋元 東京都
2 前田 東京都
3 柴田 大阪府

総合問題 MySQLの理解度をチェック。

「chapter15」フォルダ内の「training.sql」を利用し、以下の問題を解いて下さい。

実行例 (コマンド部分は省略)

コマンドプロンプト

mysql> 【"sales_management"という名前でデータベースを作成して下さい。(文字コード: utf8)】

mysql>
mysql> 【データベースの選択】
Database changed
mysql> 【「sales_management」データーベース内に、以下の名前、フィールドでテーブルを作成してください。(文字コード: utf8)】
mysql> 【「"detail" テーブルの作成】
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> 【「"sales" テーブルの作成】
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> 【「"product" テーブルの作成】
Query OK, 0 rows affected (0.01 sec)

mysql>
mysql> 【「"customer" テーブルの作成】
Query OK, 0 rows affected (0.02 sec)

mysql> 【「datail」テーブルに以下のレコードを挿入して下さい。】
Query OK, 8 rows affected (0.01 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> 【「sales」テーブルに以下のレコードを挿入して下さい。】
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> 【「product」テーブルに以下のレコードを挿入して下さい。】
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> 【「customer」テーブルに以下のレコードを挿入して下さい。】
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> 【「product」テーブルの全てのレコードを全フィールド抽出して下さい】
+----+--------------+-------+
| id | name         | price |
+----+--------------+-------+
|  1 | えんぴつ     |    50 |
|  2 | 消しゴム     |   100 |
|  3 | のり         |    60 |
|  4 | ものさし     |    80 |
|  5 | ノート       |   100 |
|  6 | 文鎮         |   100 |
+----+--------------+-------+
6 rows in set (0.00 sec)

mysql> 【「customer」の「pref」が「東京都」のレコードを全フィールド抽出】
+----+--------+-----------+
| id | name   | pref      |
+----+--------+-----------+
|  1 | 秋元   | 東京都    |
|  2 | 前田   | 東京都    |
+----+--------+-----------+
2 rows in set (0.00 sec)

mysql> 【「sales」テーブルのレコード数を「total」というフィールド名で抽出】
+-------+
| total |
+-------+
|     3 |
+-------+
1 row in set (0.00 sec)

mysql> 【「detail」テーブルの「sales_id」ごとの 「quantityの合計」を抽出なお、表示するフィールドは、以下のフィールド】
+----------+-------+
| sales_id | total |
+----------+-------+
|   000001 |     8 |
|   000002 |     3 |
|   000003 |    27 |
+----------+-------+
3 rows in set (0.00 sec)

mysql> 【「detail」テーブルと「product」テーブルを内部結合し、「sales_id」が小さい順に、レコードを抽出
なお表示するフィールドは、以下の通り】
+----------+--------------+----------+
| sales_id | name         | quantity |
+----------+--------------+----------+
|   000001 | えんぴつ     |        2 |
|   000001 | 消しゴム     |        1 |
|   000001 | のり         |        5 |
|   000002 | ものさし     |        2 |
|   000002 | ノート       |        1 |
|   000003 | えんぴつ     |       18 |
|   000003 | ノート       |        1 |
|   000003 | 文鎮         |        8 |
+----------+--------------+----------+
8 rows in set (0.01 sec)

mysql> 【全てのテーブルを内部結合し、「sales_id」が小さい順に、レコードを抽出
なお表示するフィールドは、以下の通り】
+----------+------------+---------------+-----------+--------------+-------+----------+
| sales_id | order_date | customer_name | pref      | product_name | price | quantity |
+----------+------------+---------------+-----------+--------------+-------+----------+
|   000001 | 2025-12-10 | 秋元   | 東京都    | えんぴつ     |    50 |        2 |
|   000001 | 2025-12-10 | 秋元   | 東京都    | 消しゴム     |   100 |        1 |
|   000001 | 2025-12-10 | 秋元   | 東京都    | のり         |    60 |        5 |
|   000002 | 2025-12-12 | 前田   | 東京都    | ものさし     |    80 |        2 |
|   000002 | 2025-12-12 | 前田   | 東京都    | えんぴつ     |    50 |        1 |
|   000003 | 2025-12-14 | 柴田   | 大阪府    | えんぴつ     |    50 |       18 |
|   000003 | 2025-12-14 | 柴田   | 大阪府    | ノート       |   100 |        1 |
|   000003 | 2025-12-14 | 柴田   | 大阪府    | 文鎮         |   100 |        8 |
+----------+------------+--------+-----------+--------------+-------+----------+
8 rows in set (0.00 sec)

mysql> 
    • データベース名: "sales_management"
    • テーブル名: "detail"
    • テーブル名: "sales"
    • テーブル名: "product"
    • テーブル名: "customer"
    "detail" テーブルのフィールド情報
    フィールド名 データ型 制約
    id 表示桁数11桁の整数(マイナスの数は使わない) 自動連番、主キー
    sales_id 表示桁数6桁の整数(マイナスの数は使わない、ゼロ詰め) 空白不可
    product_id 表示桁数11桁の整数(マイナスの数は使わない) 空白不可
    quantity 表示桁数11桁の整数(マイナスの数は使わない) 空白不可
    "sales" テーブルのフィールド情報
    フィールド名 データ型 制約
    id 表示桁数6桁の整数(マイナスの数は使わない、ゼロ詰め) 自動連番、主キー
    order_date 日付 空白不可
    customer_id 表示桁数11桁の整数(マイナスの数は使わない) 空白不可
    "product" テーブルのフィールド情報
    フィールド名 データ型 制約
    id 表示桁数11桁の整数(マイナスの数は使わない) 自動連番、主キー
    name 可変文字列 空白不可
    price 表示桁数11桁の整数(マイナスの数は使わない) 空白不可
    "customer" テーブルのフィールド情報
    フィールド名 データ型 制約
    id 表示桁数11桁の整数(マイナスの数は使わない) 自動連番、主キー
    name 可変文字列 空白不可
    pref 可変文字列 空白不可
  1. id sales_id product_id quantity
    1 000001 1 2
    2 000001 2 1
    3 000001 3 5
    4 000002 4 2
    5 000002 5 1
    6 000003 1 18
    7 000003 5 1
    8 000003 6 8
  2. id order_date customer_id
    000001 2025-12-10 1
    000002 2025-12-12 2
    000003 2025-12-14 3
  3. id name price
    1 えんぴつ 50
    2 消しゴム 100
    3 のり 60
    4 ものさし 80
    5 ノート 100
    6 文鎮 100
  4. id name pref
    1 秋元 東京都
    2 前田 東京都
    3 柴田 大阪府
    • "sales_id"
    • "quantity"の合計(フィールド名: "total")
    抽出結果
    sales_id total
    000001 8
    000002 3
    000003 27
    • "sales_id"("detail"テーブル)
    • "name"("product"テーブル)
    • "quantity"
    抽出結果
    sales_id name quantity
    000001 えんぴつ 2
    000001 消しゴム 1
    000001 のり 5
    000002 ものさし 2
    000002 ノート 1
    000003 えんぴつ 18
    000003 ノート 1
    000003 文鎮 8
    • "sales_id"("detail"テーブル)
    • "order_date"
    • "name"("customer"テーブル)(フィールド名: "customer_name")
    • "pref"
    • "name"("product"テーブル)(フィールド名: "product_name")
    • "price"
    • "quantity"
    抽出結果
    sales_id order_date customer_name pref product_name price quantity
    000001 2025-12-10 秋元 東京都 えんぴつ 50 2
    000001 2025-12-10 秋元 東京都 消しゴム 100 1
    000001 2025-12-10 秋元 東京都 のり 60 5
    000002 2025-12-12 前田 東京都 ものさし 80 2
    000002 2025-12-12 前田 東京都 ノート 100 1
    000003 2025-12-14 柴田 大阪府 えんぴつ 50 18
    000003 2025-12-14 柴田 大阪府 ノート 100 1
    000003 2025-12-14 柴田 大阪府 文鎮 100 8
解答例
chapter15/training.sql
-- データベース「sales_management」をUTF-8で作成
create database sales_management default character set utf8;

use sales_management;

-- テーブル「detail」、「sales」、「product」、「customer」をUTF-8で作成
create table detail (
  id int(11) unsigned auto_increment primary key,
  sales_id int(6) unsigned zerofill not null,
  product_id int(11) unsigned not null,
  quantity int(11) unsigned not null
) engine=InnoDB default charset=utf8;

create table sales (
  id int(6) unsigned zerofill auto_increment primary key,
  order_date date not null,
  customer_id int(11) unsigned not null
) engine=InnoDB default charset=utf8;

create table product (
  id int(11) unsigned auto_increment primary key,
  name varchar(255) not null,
  price int(11) unsigned not null
) engine=InnoDB default charset=utf8;

create table customer (
  id int(11) unsigned auto_increment primary key,
  name varchar(255) not null,
  pref varchar(255) not null
) engine=InnoDB default charset=utf8;


-- 「datail」テーブルにレコードを挿入
insert into detail (sales_id, product_id, quantity)
  values (
    1, 1, 2
  ),
  (
    1, 2, 1
  ),
  (
    1, 3, 5
  ),
  (
    2, 4, 2
  ),
  (
    2, 5, 1
  ),
  (
    3, 1, 18
  ),
  (
    3, 5, 1
  ),
  (
    3, 6, 8
  );

  -- 「sles」テーブルにレコードを挿入
  insert into sales (order_date, customer_id)
    values (
      '2025-12-10', 1
    ),
    (
      '2025-12-12', 2
    ),
    (
      '2025-12-14', 3
    );

  -- 「product」テーブルにレコードを挿入
  insert into product (name, price)
    values (
      'えんぴつ', 50
    ),
    (
      '消しゴム', 100
    ),
    (
      'のり', 60
    ),
    (
      'ものさし', 80
    ),
    (
      'ノート', 100
    ),
    (
      '文鎮', 100
    );

  -- 「customer」テーブルにレコードを挿入
  insert into customer (name, pref)
    values (
      '秋元', '東京都'
    ),
    (
      '前田', '東京都'
    ),
    (
      '柴田', '大阪府'
    );

-- 「product」テーブルの全てのレコードを全フィールド抽出
select * from product;

-- 「customer」の「pref」が「東京都」のレコードを全フィールド抽出
select * from customer where pref = '東京都';

-- 「sales」テーブルのレコード数を「total」というフィールド名で抽出
select count(*) as total from sales;

-- 「detail」テーブルの「sales_id」ごとの 「quantityの合計」を抽出
-- なお、表示するフィールドは、「sales_id」と 「quantityの合計(フィールド名は「total」)」とする
select sales_id, sum(quantity) as total
  from detail
  group by sales_id;

-- 「detail」テーブルと「product」テーブルを内部結合し、
-- 「sales_id」が小さい順に、レコードを抽出
-- なお表示するフィールドは、「sales_id」、「name」、「quantity」とする
select d.sales_id, p.name, d.quantity
  from detail as d join product as p
  on d.product_id = p.id
  order by d.sales_id asc;

-- 全てのテーブルを内部結合し、
-- 「sales_id」が小さい順に、レコードを抽出
-- なお表示するフィールドは、「sales_id」(「detail」テーブル)、「order_date」、
-- 「name」(「customer」テーブル)、「pref」、「name」(「product」テーブル)、
-- 「price」「quantity」とする
select
  d.sales_id,
  s.order_date,
  c.name as customer_name,
  c.pref,
  p.name as product_name,
  p.price,
  d.quantity
  from
    detail as d join
    sales as s join
    product as p join
    customer as c
  on
    d.sales_id = s.id and
    d.product_id = p.id and
    s.customer_id = c.id
  order by
    d.sales_id asc;

解答例は全問題のチェックボックスが on になるとご覧いただけます。

後始末 授業で作ったデータベースを削除。

MySQLの授業はこれでおしまい。
不要なデータベースは削除しておく。

不要なデータベースを削除しよう。

  1. 下記のデータベースを削除するコマンドを、コマンドラインツールにコピー&ペースト
不要なデータベースを削除
drop database if exists my_bank;
drop database if exists my_blog;
drop database if exists sales_management;
show databases;
実行例

コマンドプロンプト

mysql> drop database if exists my_bank;
Query OK, 3 rows affected (0.02 sec)

mysql> drop database if exists my_blog;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> drop database if exists sales_management;
Query OK, 4 rows affected (0.02 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.01 sec)

mysql>  
  1. 授業で使ったデータベースが削除されているかを確認

まとめ 一連の処理はトランザクション。
データの重複をなくすのが正規化。

データベースでは一連の処理をトランザクションと呼ぶ。
正規化をすれば、データが取り扱いやすくなる。

  • 一連の処理をひとまとめにしたものをトランザクションという
  • 非正規型から繰り返しを排除したのが第一正規形
  • 第一正規形から部分従属を排除したのが第二正規形
  • 第二正規形から推移従属を排除したのが第三正規形