[PR] 本記事にはプロモーションが含まれています。

【データベース編 第7回】控える・戻す ― mysqldump の控えは、戻し方まで確かめる

必要なカードだけを控えの箱に入れておき、消えた場所にそのカードを戻している様子を表したイラスト MySQL

【2026年10月24日時点の情報です】

第6回では、書き換えを取り消せるトランザクションを試しました。ただし、トランザクションで戻せるのは、確定する前の書き換えだけです。確定したあとで間違いに気づいたときに備えて、書き換える前のデータをファイルに控えておきます。

第7回は、mysqldump で一部の行だけを控え、その行を消してから、控えで戻しました。途中で、パスワードの入力で何度もつまずきました。

場面0:この回の前に知っておくこと

mysqldump の控えは、SQL の命令の並び

mysqldump は、データベースの中身を、SQL の命令の形で書き出すコマンドです。bash で使います(MariaDB の中では使いません)。何も付けずに表を控えると、中身は次の3つの命令になります。

No.命令意味
1DROP TABLE IF EXISTS表があれば消す
2CREATE TABLE表を作り直す(第2回の内容)
3INSERT INTOデータを入れ直す(第3回の内容)

控えを戻すと、この3つが上から順に実行されます。つまり、表を一度消してから作り直す形です。組み込みでいえば、書き込み用のスクリプトで、領域を消去してからイメージを書き戻すのと同じです。

一部だけ控えるときの2つの指定

  • –where=”条件”:
    条件に合う行だけを控える。ただし、これだけだと DROP TABLE と CREATE TABLE も入る
  • –no-create-info:
    DROP TABLE と CREATE TABLE を書き出さない。INSERT の行だけになる
--where だけで控えたものを戻すと表が作り直されてほかの行が消え、--no-create-info を付けて控えたものを戻すと控えた行だけが入り直すことを比べた図

一部の行だけを –where で控えて、そのまま戻すと、表を消して作り直してから控えた行だけを入れるので、ほかの行がすべて消えます。一部だけを控えるときは、–no-create-info を付けます。

> と <

  • > ファイル:
    コマンドの結果を、画面に出す代わりにファイルに書き出す(控えるとき)
  • < ファイル:
    ファイルの中身を、コマンドへの入力として流し込む(戻すとき)

パスワードを聞かれるコマンドは、1行ずつ実行する

mysql や mysqldump に -p を付けると、「Enter password:」と入力を待ちます。そこに、一緒に貼り付けた次の行が流れ込むと、その文字列がパスワードとして使われてしまいます。今回は、これで何度もつまずきました。

場面1:血糖の行だけを控える

血糖の2行だけを、–no-create-info を付けて控えました。練習用のデータは、第6回で id 4 を 105 に書き換えたままの状態です(値はすべて練習用の架空のもの)。

Bash
mysqldump -u practice -p --no-create-info sql_practice measurements --where="item_name='血糖'" > ~/work/blood_sugar_rows.sql
  • –no-create-info:
    DROP TABLE と CREATE TABLE を入れない
  • sql_practice measurements:
    データベース sql_practice の、表 measurements だけを控える
  • –where=”item_name=’血糖'”:
    項目名が血糖の行だけ。外側を ” “、内側の文字列を ‘ ‘ で囲む
  • > ~/work/blood_sugar_rows.sql:
    控えをファイルに書き出す

最初は、この行と、中身を確かめる grep の行を、まとめて貼り付けて実行しました。すると、何も表示されませんでした。パスワードを聞かれているところに、grep の行が流れ込んだのだと思います。

そこで、mysqldump の行だけを実行し直すと、今度は次のエラーになりました。

結果の例:

Plaintext
mysqldump: Got error: 1045: "Access denied for user 'practice'@'localhost' (using password: YES)" when trying to connect
  • Access denied … (using password: YES):
    パスワードは送られたが、合っていなかったという意味

パスワードを入力し直して通ったあと、控えに入っている命令を grep で確かめました。

Bash
grep -E "^(DROP|CREATE|INSERT)" ~/work/blood_sugar_rows.sql

結果の例:

Plaintext
INSERT INTO `measurements` VALUES

DROP TABLE と CREATE TABLE の行はなく、INSERT の行だけでした。ただ、値の部分が出てこないので、後ろの行も一緒に表示しました。

Bash
grep -A 3 "^INSERT" ~/work/blood_sugar_rows.sql

結果の例:

Plaintext
INSERT INTO `measurements` VALUES
(1,'2026-09-01','血糖','98',98.000,'mg/dL'),
(4,'2026-10-01','血糖','105',105.000,'mg/dL');
/*!40000 ALTER TABLE `measurements` ENABLE KEYS */;
  • -A 3:
    見つかった行の後ろ(After)を3行、あわせて表示する。この mysqldump は、入れる行を次の行から1行ずつ書き出していた
  • (1,…)、(4,…):
    血糖の2行(id 1 と 4)だけが入っている。id 4 は第6回で書き換えた 105
  • /*!40000 … */:
    バージョン付きのコメント。MariaDB や MySQL は、中身を命令として実行する。行を入れ終わったあとに、索引をまとめて作り直すための命令で、mysqldump が自動で付ける

場面2:消すつもりが、消えていなかった

次は、血糖の2行を消してから、控えで戻す練習です。消すコマンドと、確かめるコマンドを、また2行まとめて貼り付けてしまいました。

Bash
mysql -u practice -p sql_practice -e "DELETE FROM measurements WHERE item_name='血糖';"
mysql -u practice -p sql_practice -e "SELECT * FROM measurements;"

結果の例:

Plaintext
Enter password:
ERROR 1045 (28000): Access denied for user 'practice'@'localhost' (using password: YES)
Enter password:
+----+-------------+-----------+------------+-----------+-------+
| 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  |
+----+-------------+-----------+------------+-----------+-------+

血糖の行が残っています。起きたことを順に並べると、次のとおりです。

No.起きたこと
11行目の DELETE のコマンドが、パスワードを聞いてきた
2一緒に貼った2行目の文字列が流れ込み、パスワードとして使われた
3パスワードが違うので Access denied。DELETE は実行されていない
42つ目のコマンドが動き、本当のパスワードを入れたので SELECT は成功した

エラーのあとに表が表示されたので、一瞬、消せたように見えます。結果の表を見て、消えているべき行が残っていないかを確かめることが大事でした。

場面3:残っている行に戻すと、重複エラーで止まる

血糖の行が残ったまま、控えを流し込んでしまいました。

Bash
mysql -u practice -p sql_practice < ~/work/blood_sugar_rows.sql

結果の例:

Plaintext
--------------
INSERT INTO `measurements` VALUES
(1,'2026-09-01','血糖','98',98.000,'mg/dL'),
(4,'2026-10-01','血糖','105',105.000,'mg/dL')
--------------

ERROR 1062 (23000) at line 25: Duplicate entry '1' for key 'PRIMARY'
  • Duplicate entry ‘1’ for key ‘PRIMARY’:
    id 1 の行がすでにあるので、同じ番号の行は入れられない。第2回で付けた PRIMARY KEY(重複を許さない)が効いている
  • at line 25:
    控えのファイルの25行目の命令で止まった

このとき、id 4 の行も入っていません。INSERT の命令は1つのまとまりとして扱われるので、途中でエラーになると、その命令全体が実行されません。組み込みでいえば、書き込みのパケットを、ベリファイのエラーで丸ごと破棄するのと同じです。

失敗ではありますが、守りが働いた結果でもあります。同じ控えをうっかり2回流しても、同じ行が2つに増えることはありません。

場面4:1行ずつ実行して、消してから戻す

今度は、コマンドを1つ貼り付けて実行し、行頭に戻ったのを確かめてから次を貼る、を守って進めました。

Bash
mysql -u practice -p sql_practice -e "DELETE FROM measurements WHERE item_name='血糖';"

パスワードを入れると、何も表示されずに行頭に戻りました。-e で実行した DELETE は、消した件数を表示しません。確かめます。

Bash
mysql -u practice -p sql_practice -e "SELECT * FROM measurements;"

結果の例:

Plaintext
+----+-------------+-----------+------------+-----------+-------+
| id | measured_on | item_name | value_text | value_num | unit  |
+----+-------------+-----------+------------+-----------+-------+
|  2 | 2026-09-01  | CRP       | 0.05       |     0.050 | mg/dL |
|  3 | 2026-09-01  | 尿蛋白    | (-)        |      NULL | NULL  |
|  5 | 2026-10-01  | CRP       | 0.03未満   |     0.030 | mg/dL |
|  6 | 2026-10-01  | 尿蛋白    | (+-)       |      NULL | NULL  |
+----+-------------+-----------+------------+-----------+-------+

血糖の2行が消えて、4行になりました。id が 2、3、5、6 と飛び飛びになっているのは、消した行の番号が詰められずに空くためです。控えを流し込みます。

Bash
mysql -u practice -p sql_practice < ~/work/blood_sugar_rows.sql

今度はエラーが出ずに、行頭に戻りました。もう一度確かめます。

Bash
mysql -u practice -p sql_practice -e "SELECT * FROM measurements;"

結果の例:

Plaintext
+----+-------------+-----------+------------+-----------+-------+
| 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  |
+----+-------------+-----------+------------+-----------+-------+

血糖の2行が、同じ id(1 と 4)のまま戻り、6行になりました。CRP と尿蛋白の4行には、何も起きていません。–no-create-info で控えたので、表を消して作り直すことなく、血糖の行だけが入り直しました。

場面5:タイトルを変える前に取った控えを読む

ブログの連載のタイトルをまとめて変える前(第6回の場面5)には、次のコマンドで、対象の記事を控えていました。

Bash
mysqldump -u wordpress -p wordpress wp_posts --where="post_type='post' AND post_name LIKE 'embedded-to-web-0%'" > ~/work/backup_titles_20261012.sql
  • wordpress wp_posts:
    データベース wordpress の、記事の表 wp_posts
  • –where=”…”:
    連載の入門編の記事だけを控える

この控えには、–no-create-info が付いていません。場面0 のとおり、中には DROP TABLE と CREATE TABLE が入ります。このまま流し込んでいたら、wp_posts の表がまるごと消えて、連載の8本以外のブログの記事がすべて消えるところでした。

タイトルの変更はうまくいったので、この控えを戻すことはありませんでした。ただ、「控えを取ったから安心」ではなく、戻したらどうなるかまで確かめておく必要があると分かりました。この控えは、戻すのに使えない形なので、消しておくのが安全です。

まとめ

第7回では、一部の行だけを控え、消してから戻しました。覚えたことは、次のとおりです。

No.覚えたことつまずいたところ
1mysqldump の控えは、DROP TABLE → CREATE TABLE → INSERT の並び―
2一部だけを控えるときは、–where に –no-create-info を付けるタイトルを変える前の控えは、戻すと表が消える形だった
3パスワードを聞かれるコマンドは、1行ずつ実行する2行まとめて貼り、2行目がパスワードとして読まれた
4エラーのあとに表が出ても、中身を見て確かめるDELETE が実行されていないのに、消えたつもりで戻そうとした
5同じ行を二重に入れようとすると、PRIMARY KEY の重複エラーで止まる血糖の行が残ったまま戻した
6控えは、戻したらどうなるかまで確かめておく―

今回いちばん多かったのは、パスワードを聞かれるコマンドをまとめて貼るまちがいでした。まとめて貼れるのは、パスワードを聞かれないコマンドだけです。

次回は、「測定データ」と「項目の対応表」のように、2つの表をつないで取り出す JOIN を試します。

この記事は、シリーズ「組み込みエンジニアの Web 開発入門」の1本です。ほかの回は、シリーズの目次からどうぞ。

ほかの開発・プログラミングの記事は、開発・プログラミングメモの目次から、テーマ別に探せます。

このブログは、にほんブログ村と人気ブログランキングに参加しています。記事が役に立ったら、下のランキングのバナーのどれかを押して応援してもらえると励みになります。

ブログランキング・にほんブログ村へにほんブログ村

サーバー構築・運用ランキング プログラムランキング

MySQL
watasoftdevをフォローする

コメント