【2026年10月24日時点の情報です】
第5回までは、表を作り、データを入れ、取り出し、数えるところまで進みました。どれも、データを読むだけの操作です。
第6回は、初めてデータを書き換えたり、消したりします。書き換えは、間違えると元に戻せないことがあります。そこで、取り消しのできる「トランザクション」という仕組みの中で、わざと危ない書き換えも試してみました。
ブログの管理で、連載のタイトルをまとめて変えたときに使った UPDATE も、最後に読み解きます。
場面0:この回の前に知っておくこと
練習用のデータ
第5回と同じ、6行の練習用のデータ(値はすべて架空のもの)を使います。この回で id 4 の値を書き換えるので、終わったあとに最初の状態に戻したいときは、第1回の付録の手順を使ってください。
mysql -u practice -p sql_practice以下の SQL は、すべて MariaDB の中(行頭が MariaDB [sql_practice]>)で打ちます。
書き換える・消す命令の形
| No. | 命令 | 形 | 何をするか |
|---|---|---|---|
| 1 | UPDATE | UPDATE 表 SET 列 = 値 WHERE 条件 | 条件に合う行の、指定した列を書き換える |
| 2 | DELETE | DELETE FROM 表 WHERE 条件 | 条件に合う行を、まるごと消す |
どちらも、WHERE を書き忘れると、すべての行が対象になります。そのため、書き換える前に、同じ条件の SELECT で対象の行を確かめるのが基本です。
トランザクション
START TRANSACTION から始めると、その後の書き換えは「仮の書き換え」になります。ROLLBACK で取り消すか、COMMIT で確定するかを、あとから選べます。

- START TRANSACTION:
ここから先の書き換えを、仮の状態にする。組み込みでいえば、フラッシュに書く前に、RAM 上のシャドウで編集を始める - ROLLBACK:
仮の書き換えを捨てて、元に戻す。シャドウを捨てる - COMMIT:
仮の書き換えを確定する。シャドウをフラッシュに書き込む
START TRANSACTION を使わずに打った UPDATE や DELETE は、その場で確定します。取り消しはできません。
場面1:1行だけ書き換える(UPDATE)
id 4 の血糖(104)を、105 に書き換えました。まず SELECT で対象の行を確かめてから、同じ条件のまま UPDATE に置き換えます。
SELECT * FROM measurements WHERE id = 4;
UPDATE measurements SET value_text = '105', value_num = 105 WHERE id = 4;
SELECT * FROM measurements WHERE id = 4;- UPDATE measurements:
measurements 表の行を書き換える - SET value_text = ‘105’, value_num = 105:
どの列を、どの値にするか。カンマで区切って、複数の列を一度に書き換えられる - WHERE id = 4:
どの行を書き換えるか。直前の SELECT と同じ条件にする
UPDATE の結果には、次のような行が出ます。
- Rows matched:
条件に合った行の数 - Changed:
実際に値が変わった行の数。同じ値で書き換えると、matched は 1 でも changed は 0 になる
id 4 が 105 になったことは、次の場面2 で表示した表で確かめられます。この書き換えはトランザクションの外で行ったので、その場で確定しています。
場面2:取り消せる状態で書き換える(トランザクション)
次に、血糖の項目名を「血糖(空腹時)」に書き換えてから、取り消してみました。
START TRANSACTION;
UPDATE measurements SET item_name = REPLACE(item_name, '血糖', '血糖(空腹時)') WHERE item_name = '血糖';
SELECT * FROM measurements;- REPLACE(item_name, ‘血糖’, ‘血糖(空腹時)’):
item_name の文字列の中の「血糖」を「血糖(空腹時)」に置き換えた文字列を作る関数
続けて表示した表です。
結果の例:
+----+-------------+-----------------------+------------+-----------+-------+
| id | measured_on | item_name | value_text | value_num | unit |
+----+-------------+-----------------------+------------+-----------+-------+
| 1 | 2026-09-01 | 血糖(空腹時) | 98 | 98.000 | mg/dL |
| 2 | 2026-09-01 | CRP | 0.05 | 0.050 | mg/dL |
| 3 | 2026-09-01 | 尿蛋白 | (-) | NULL | NULL |
| 4 | 2026-10-01 | 血糖(空腹時) | 105 | 105.000 | mg/dL |
| 5 | 2026-10-01 | CRP | 0.03未満 | 0.030 | mg/dL |
| 6 | 2026-10-01 | 尿蛋白 | (+-) | NULL | NULL |
+----+-------------+-----------------------+------------+-----------+-------+
6 rows in set (0.000 sec)血糖の2行が「血糖(空腹時)」になり、id 4 は場面1 で書き換えた 105 になっています。ここで、取り消しました。
ROLLBACK;
SELECT * FROM measurements;結果の例:
Query OK, 0 rows affected (0.000 sec)
+----+-------------+-----------+------------+-----------+-------+
| id | measured_on | item_name | value_text | value_num | unit |
+----+-------------+-----------+------------+-----------+-------+
| 1 | 2026-09-01 | 血糖 | 98 | 98.000 | mg/dL |
| 2 | 2026-09-01 | CRP | 0.05 | 0.050 | mg/dL |
| 3 | 2026-09-01 | 尿蛋白 | (-) | NULL | NULL |
| 4 | 2026-10-01 | 血糖 | 105 | 105.000 | mg/dL |
| 5 | 2026-10-01 | CRP | 0.03未満 | 0.030 | mg/dL |
| 6 | 2026-10-01 | 尿蛋白 | (+-) | NULL | NULL |
+----+-------------+-----------+------------+-----------+-------+
6 rows in set (0.000 sec)項目名は「血糖」に戻りました。一方、id 4 の 105 は戻りません。場面1 の書き換えは、START TRANSACTION より前に確定していたからです。ROLLBACK で戻るのは、START TRANSACTION から後の書き換えだけです。
場面3:WHERE を忘れると、どうなるか
UPDATE で WHERE を書き忘れたらどうなるかを、トランザクションの中でわざと試しました。
START TRANSACTION;
UPDATE measurements SET unit = 'X';
SELECT * FROM measurements;結果の例:
Query OK, 0 rows affected (0.000 sec)
Query OK, 6 rows affected (0.000 sec)
Rows matched: 6 Changed: 6 Warnings: 0
+----+-------------+-----------+------------+-----------+------+
| id | measured_on | item_name | value_text | value_num | unit |
+----+-------------+-----------+------------+-----------+------+
| 1 | 2026-09-01 | 血糖 | 98 | 98.000 | X |
| 2 | 2026-09-01 | CRP | 0.05 | 0.050 | X |
| 3 | 2026-09-01 | 尿蛋白 | (-) | NULL | X |
| 4 | 2026-10-01 | 血糖 | 105 | 105.000 | X |
| 5 | 2026-10-01 | CRP | 0.03未満 | 0.030 | X |
| 6 | 2026-10-01 | 尿蛋白 | (+-) | NULL | X |
+----+-------------+-----------+------------+-----------+------+
6 rows in set (0.000 sec)- Rows matched: 6 Changed: 6:
WHERE がないので、条件に合う行は「すべての行」になる。6行すべての単位が X に書き換わった
C でいえば、配列の特定の要素だけに書くつもりが、添字を書き忘れて全要素に書いてしまうのと同じです。トランザクションの中なので、取り消しました。
ROLLBACK;
SELECT * FROM measurements;結果の例:
Query OK, 0 rows affected (0.000 sec)
+----+-------------+-----------+------------+-----------+-------+
| id | measured_on | item_name | value_text | value_num | unit |
+----+-------------+-----------+------------+-----------+-------+
| 1 | 2026-09-01 | 血糖 | 98 | 98.000 | mg/dL |
| 2 | 2026-09-01 | CRP | 0.05 | 0.050 | mg/dL |
| 3 | 2026-09-01 | 尿蛋白 | (-) | NULL | NULL |
| 4 | 2026-10-01 | 血糖 | 105 | 105.000 | mg/dL |
| 5 | 2026-10-01 | CRP | 0.03未満 | 0.030 | mg/dL |
| 6 | 2026-10-01 | 尿蛋白 | (+-) | NULL | NULL |
+----+-------------+-----------+------------+-----------+-------+
6 rows in set (0.000 sec)単位が元に戻りました。これが、書き換える前に必ず同じ条件の SELECT で確かめる理由です。不安なときは、トランザクションの中で試してから COMMIT します。
場面4:行を消す(DELETE)
消す練習のために、「テスト」という行を1つ足してから、その行を消しました。
INSERT INTO measurements (measured_on, item_name, value_text, value_num, unit)
VALUES ('2026-10-01', 'テスト', '1', 1, NULL);
SELECT * FROM measurements WHERE item_name = 'テスト';結果の例:
Query OK, 1 row affected (0.004 sec)
+----+-------------+-----------+------------+-----------+------+
| id | measured_on | item_name | value_text | value_num | unit |
+----+-------------+-----------+------------+-----------+------+
| 7 | 2026-10-01 | テスト | 1 | 1.000 | NULL |
+----+-------------+-----------+------------+-----------+------+
1 row in set (0.000 sec)足した行は id 7 になりました。この行を、同じ条件で消します。
DELETE FROM measurements WHERE item_name = 'テスト';
SELECT * FROM measurements;結果の例:
Query OK, 1 row affected (0.005 sec)
+----+-------------+-----------+------------+-----------+-------+
| id | measured_on | item_name | value_text | value_num | unit |
+----+-------------+-----------+------------+-----------+-------+
| 1 | 2026-09-01 | 血糖 | 98 | 98.000 | mg/dL |
| 2 | 2026-09-01 | CRP | 0.05 | 0.050 | mg/dL |
| 3 | 2026-09-01 | 尿蛋白 | (-) | NULL | NULL |
| 4 | 2026-10-01 | 血糖 | 105 | 105.000 | mg/dL |
| 5 | 2026-10-01 | CRP | 0.03未満 | 0.030 | mg/dL |
| 6 | 2026-10-01 | 尿蛋白 | (+-) | NULL | NULL |
+----+-------------+-----------+------------+-----------+-------+
6 rows in set (0.000 sec)- DELETE FROM measurements:
measurements 表から行を消す。SELECT と違って、列の名前や * は書かない(行をまるごと消すため) - WHERE item_name = ‘テスト’:
消す行の条件。忘れると、全行が消える - Query OK, 1 row affected:
1行消えたという意味
消した id 7 の番号は、次に行を入れても再利用されず、次の行は 8 から振られます。AUTO_INCREMENT は、使った番号を戻さないカウンタだからです。
場面5:タイトルをまとめて変えたコマンドを読む
ブログの連載のタイトルを、「【第◯回】」から「【入門編 第◯回】」にまとめて変えたときは、次の2つを順に流していました。
まず、書き換えずに、変えたあとの形を表示して確かめました。
SELECT ID, post_status, post_title AS before_title,
REPLACE(post_title, '【第', '【入門編 第') AS after_title
FROM wp_posts
WHERE post_type = 'post' AND post_name LIKE 'embedded-to-web-0%'
AND post_status IN ('publish', 'future')
ORDER BY post_name;確かめたあと、同じ条件で書き換えました。
UPDATE wp_posts
SET post_title = REPLACE(post_title, '【第', '【入門編 第')
WHERE post_type = 'post' AND post_name LIKE 'embedded-to-web-0%'
AND post_status IN ('publish', 'future')
AND post_title LIKE '【第%';- REPLACE(post_title, ‘【第’, ‘【入門編 第’) AS after_title:
書き換えたあとのタイトルを、表示だけする。SELECT なので、データは変わらない - SET post_title = REPLACE(…):
確かめたのと同じ置き換えで、本当に書き換える - post_name LIKE ‘embedded-to-web-0%’:
連載の入門編(スラッグが embedded-to-web-0 で始まる記事)だけ。番外編(embedded-to-web-extra-…)は入らない - AND post_title LIKE ‘【第%’:
まだ変えていないタイトルだけ。うっかり2回流しても、「【入門編 入門編 第」のように二重にはならない
場面1 の「SELECT で確かめてから、同じ条件で UPDATE」と、まったく同じ順番です。このときはトランザクションを使わず、代わりに、書き換える前の記事をファイルに控えておきました。控えの取り方と戻し方は、次回のテーマです。
まとめ
第6回では、初めてデータを書き換え、消しました。覚えたことは、次のとおりです。
| No. | 覚えたこと | C・組み込みでいうと |
|---|---|---|
| 1 | UPDATE 表 SET 列 = 値 WHERE 条件 で書き換える | 配列の要素のメンバへの代入 |
| 2 | DELETE FROM 表 WHERE 条件 で行を消す。列は書かない | 要素をまるごと取り除く |
| 3 | WHERE を忘れると、すべての行が対象になる | 添字を書き忘れて全要素に書く |
| 4 | 書き換える前に、同じ条件の SELECT で確かめる | 書き込む前にアドレスを確かめる |
| 5 | START TRANSACTION の中なら、ROLLBACK で取り消せる。前に確定したものは戻らない | RAM 上のシャドウで編集して、捨てるか書き込むか選ぶ |
| 6 | AUTO_INCREMENT は、消した番号を再利用しない | 使った番号を戻さないカウンタ |
次回は、mysqldump でデータをファイルに控え、そこから元に戻す方法を試します。控え方によっては、戻したときにほかの行まで消えてしまう落とし穴もありました。
この記事は、シリーズ「組み込みエンジニアの Web 開発入門」の1本です。ほかの回は、シリーズの目次からどうぞ。



コメント