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

【MariaDB】初心者のSQL練習帳 第3回:消した記事の残りを片付けた|前のコマンドをまねして、テーブルと条件を直し忘れた

消した記事を指したまま残っていた札を、控えを取ってから片付けている様子を表したイラスト MySQL

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

このシリーズでは、練習用のWordPressで、AI(Claude)にお題を出してもらい、ヒントだけを見て自分でSQLを書いています。

第2回では、SQLで Hello world!(ID 1)の記事を消したところ、その記事を指したままのカテゴリーの行とコメントの行が残っていました。第3回のお題は、この残りを片付けることです。

流れは第2回と同じ「控えを取る → 確かめる → 消す → 確かめる」ですが、今回はテーブルが2つあります。その分、前のコマンドをまねしたときの直し忘れが、たくさん出ました。

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

片付ける2つの行

第2回の場面0で整理した4つのテーブルのうち、今回さわるのは次の3つです。

No.テーブル残っている行消した記事(ID 1)を指している列
1wp_term_relationships「ID 1 の記事は、未分類に入っている」という行object_id
2wp_commentsID 1 の記事に付いていたコメントの行comment_post_ID
3wp_term_taxonomy(消さない)未分類の記事の数(count)が正しいかを見るー

テーブルごとに、記事を指している列の名前がちがいます。wp_posts では ID でしたが、ほかのテーブルには ID という列はありません。

なお、第2回のあとで、管理画面から新しい Hello world! を作り直しています(ID 4321)。今回消すのは ID 1 を指している行だけで、4321 の行は残します。

控えは、テーブルを消す命令を入れずに取る

第2回で分かったとおり、mysqldump で何も付けずに控えを取ると、テーブルを消して作り直す命令(DROP TABLE)も入ります。今回は最初から、次の2つを入れた形で取ります。

  • --no-create-info:
    DROP TABLE・CREATE TABLE を書き出さない。INSERT の行だけになる
  • $(date +%Y%m%d-%H%M%S):
    ファイルの名前に日付と時刻を入れて、上書きされないようにする

SELECT と DELETE の形のちがい

No.命令形列を書くか
1SELECTSELECT 列 FROM テーブル WHERE 条件書く(どの列を見るか)
2DELETEDELETE FROM テーブル WHERE 条件書かない(行をまるごと消す)

count は、公開中の記事だけを数える

wp_term_taxonomy の count には、そのカテゴリーに入っている記事のうち、公開中(publish)の記事の数が入っています。下書きや非公開の記事は、カテゴリーに入っていても数えません。

管理画面で記事を作ったり消したりすると、WordPress が count を数え直します。SQL で行を消したときは、数え直しません(SQLで下書きに戻したら空のカテゴリーが残った記事と同じ理由です)。

場面1:控えを取ったら、中身が別のテーブルだった

最初のお題は、残っている2つの行の控えを取ることでした。第2回の最後に取った、新しい Hello world! の控えのコマンドをもとにして、ファイルの名前を2つに分けて書きました。

Bash
sudo mysqldump --no-create-info wp_practice wp_posts --where="ID = 4321" > ~/work/wp_term_relationships-hello-$(date +%Y%m%d-%H%M%S).sql
sudo mysqldump --no-create-info wp_practice wp_posts --where="ID = 4321" > ~/work/wp_comments-hello-$(date +%Y%m%d-%H%M%S).sql

控えに INSERT の行があるか、テーブルを消す命令がないかを、grep で確かめました。

No.ファイルgrep -c “^INSERT INTO”grep -c “DROP TABLE”
1wp_term_relationships-hello-20261021-104834.sql10
2wp_comments-hello-20261021-104834.sql10

どちらも思ったとおりの数でしたが、中身はまちがっていました。もとにしたコマンドの、ファイルの名前だけを変えていて、テーブル(wp_posts)と条件(ID = 4321)がそのままでした。2つとも、中身は新しい Hello world! の記事の行です。

No.書いたところ書いたもの本当は
1テーブルwp_posts(2回とも)wp_term_relationships と wp_comments
2条件ID = 4321(2回とも)object_id = 1 と comment_post_ID = 1
3ファイルの名前wp_term_relationships-hello-…、wp_comments-hello-…合っていた

grep -c "^INSERT INTO" は、INSERT の行があるかしか見ていません。どのテーブルの INSERT かまで確かめるには、INSERT の行に入っているテーブルの名前で探します。

Bash
grep -c 'INSERT INTO `wp_term_relationships`' wp_term_relationships-hello-20261021-104834.sql
  • ‘INSERT INTO `wp_term_relationships`’:
    mysqldump は、テーブルの名前を ` `(バッククォート)で囲んで書き出す。シェルで ` を文字のまま探すために、全体を ‘ ‘ で囲む

場面2:テーブルを直したら、ID という列がなかった

テーブルの名前だけを直して、もう一度流しました。

Bash
sudo mysqldump --no-create-info wp_practice wp_term_relationships --where="ID = 4321" > ~/work/wp_term_relationships-hello-$(date +%Y%m%d-%H%M%S).sql
sudo mysqldump --no-create-info wp_practice wp_comments --where="ID = 4321" > ~/work/wp_comments-hello-$(date +%Y%m%d-%H%M%S).sql

結果の例:

Plaintext
mysqldump: Couldn't execute 'SELECT /*!40001 SQL_NO_CACHE */ `object_id`, `term_taxonomy_id`, `term_order` FROM `wp_term_relationships` WHERE ID = 4321': Unknown column 'ID' in 'WHERE' (1054)
mysqldump: Couldn't execute 'SELECT /*!40001 SQL_NO_CACHE */ `comment_ID`, `comment_post_ID`, `comment_author`, `comment_author_email`, `comment_author_url`, `comment_author_IP`, `comment_date`, `comment_date_gmt`, `comment_content`, `comment_karma`, `comment_approved`, `comment_agent`, `comment_type`, `comment_parent`, `user_id` FROM `wp_comments` WHERE ID = 4321': Unknown column 'ID' in 'WHERE' (1054)
  • Unknown column ‘ID’ in ‘WHERE’ (1054):
    WHERE に書いた ID という列が、このテーブルにない。第2回の場面5と同じエラー
  • SELECT のあとに並んでいる名前:
    そのテーブルの列の名前。エラーの文の中に、列の一覧が出ている

条件の列の名前を、テーブルに合わせる必要がありました。それに、値も 4321 ではなく、片付けたいのは ID 1 を指している行です。

もう1つ、コマンドがエラーで止まっても、> の部分で、空のファイルが作られていました。> は、コマンドを動かす前に、書き出す先のファイルを作るためです。

場面3:ちがうファイルを確かめて、こんがらがった

次に流した2つのコマンドです。

Bash
sudo mysqldump --no-create-info wp_practice wp_comments --where="comment_post_ID = 1" > ~/work/wp_comments-hello-$(date +%Y%m%d-%H%M%S).sql
sudo mysqldump --no-create-info wp_practice wp_term_relationships --where="object_id = 1 = 1" > ~/work/wp_comments-hello-$(date +%Y%m%d-%H%M%S).sql

1つ目(wp_comments)は正しく書けていました。2つ目には、まちがいが2つありました。

No.書いたところ書いたもの本当は
1条件object_id = 1 = 1object_id = 1(「= 1」が1つ多い)
2ファイルの名前wp_comments-hello-…wp_term_relationships-hello-…(1つ目のコマンドをまねして、名前を直し忘れた)

No.1 は、たまたまエラーにはなりません。MariaDB は「(object_id = 1) が 1(本当)」と読むので、結果は object_id = 1 と同じになります。

そのうえ、確かめの grep では、場面2のエラーのときにできた空のファイルを見ていたので、0 が出て、何が正しいのか分からなくなりました。この時点で、wp_comments-hello- と wp_term_relationships-hello- で始まるファイルが、7つもできていました。

いったん全部消して、完成したコマンドで取り直した

ここで、お題3で作ったファイルを全部消して、最初から取り直すことにしました。残すのは、第2回で取った新しい Hello world! の控え(wp_posts-hello-20261021-102819.sql)だけです。

Bash
cd ~/work
ls -l wp_comments-hello-*.sql wp_term_relationships-hello-*.sql
rm wp_comments-hello-*.sql wp_term_relationships-hello-*.sql
  • ls -l …:
    消す前に、消えるファイルの一覧を見る
  • rm …:
    名前が wp_comments-hello- と wp_term_relationships-hello- で始まるファイルを消す

取り直しは、こんがらがらないように、完成したコマンドを教えてもらいました。1つのコマンドの中で、テーブル・条件の列・ファイルの名前の3か所がそろっているかを見比べます。

Bash
sudo mysqldump --no-create-info wp_practice wp_term_relationships --where="object_id = 1" > ~/work/wp_term_relationships-hello-$(date +%Y%m%d-%H%M%S).sql
sudo mysqldump --no-create-info wp_practice wp_comments --where="comment_post_ID = 1" > ~/work/wp_comments-hello-$(date +%Y%m%d-%H%M%S).sql
No.見比べるところ1行目2行目
1テーブルwp_term_relationshipswp_comments
2条件の列object_idcomment_post_ID
3ファイルの名前の頭wp_term_relationships-hello-wp_comments-hello-

2つのファイルの中身を、テーブルの名前まで確かめました。

Bash
ls -l ~/work/wp_*-hello-*.sql
for f in ~/work/wp_term_relationships-hello-*.sql ~/work/wp_comments-hello-*.sql; do echo "== $f"; grep -o 'INSERT INTO `[a-z_]*`' "$f"; grep -c "DROP TABLE" "$f"; done
  • grep -o ‘INSERT INTO `[a-z_]*`’ “$f”:
    INSERT の行の、テーブルの名前の部分だけを出す
  • for f in …; do …; done:
    2つのファイルを、1つずつ順番に調べる

結果の例:

Plaintext
-rw-r--r-- 1 user user 1938 10月 21 12:54 /home/user/work/wp_comments-hello-20261021-125438.sql
-rw-r--r-- 1 user user 1753 10月 21 10:28 /home/user/work/wp_posts-hello-20261021-102819.sql
-rw-r--r-- 1 user user 1515 10月 21 12:54 /home/user/work/wp_term_relationships-hello-20261021-125434.sql
== /home/user/work/wp_term_relationships-hello-20261021-125434.sql
INSERT INTO `wp_term_relationships`
0
== /home/user/work/wp_comments-hello-20261021-125438.sql
INSERT INTO `wp_comments`
0

ファイルの名前と、INSERT INTO のあとのテーブルの名前が同じで、DROP TABLE が 0 になりました。今度こそ、正しい控えです。

場面4:消す前の SELECT で、また前の形をまねした

消す前に、控えと同じ条件で SELECT して、消す行を確かめます。最初に書いたのは、次の2つです。

Bash
sudo mysql wp_practice -e "SELECT comment_ID, comment_post_ID, comment_author FROM wp_comments WHERE comment_ID=1"
sudo mysql wp_practice -e "SELECT ID, post_title FROM wp_term_relationships WHERE object_id=1 AND term_taxonomy_id=1"

結果の例:

Plaintext
+------------+-----------------+------------------------------------+
| comment_ID | comment_post_ID | comment_author                     |
+------------+-----------------+------------------------------------+
|          1 |               1 | WordPress コメントの投稿者         |
+------------+-----------------+------------------------------------+
ERROR 1054 (42S22) at line 1: Unknown column 'ID' in 'SELECT'

2つ目は、SELECT のあとに、wp_posts のときの列(ID, post_title)を書いていました。エラーの場所が、今度は ‘WHERE’ ではなく ‘SELECT’ になっています。wp_term_relationships の列は3つしかないので、SELECT * にしました。

もう1つ、どちらも条件が、控えを取ったときとちがっていました。

No.テーブル控えの条件書いた SELECT の条件
1wp_commentscomment_post_ID = 1comment_ID=1
2wp_term_relationshipsobject_id = 1object_id=1 AND term_taxonomy_id=1

今回は、たまたまどちらも同じ1行が出ますが、SELECT で確かめる意味は、「控えの行」「確かめた行」「消す行」が同じかを見ることです。3つの条件をそろえておかないと、ずれることがあります。たとえば、もし記事が2つのカテゴリーに入っていたら、AND で term_taxonomy_id までしぼった形では、1つしか選ばれません。

控えと同じ条件にそろえて、流し直しました。

Bash
sudo mysql wp_practice -e "SELECT * FROM wp_term_relationships WHERE object_id=1"
sudo mysql wp_practice -e "SELECT comment_ID, comment_post_ID, comment_author FROM wp_comments WHERE comment_post_ID=1"

結果の例:

Plaintext
+-----------+------------------+------------+
| object_id | term_taxonomy_id | term_order |
+-----------+------------------+------------+
|         1 |                1 |          0 |
+-----------+------------------+------------+
+------------+-----------------+------------------------------------+
| comment_ID | comment_post_ID | comment_author                     |
+------------+-----------------+------------------------------------+
|          1 |               1 | WordPress コメントの投稿者         |
+------------+-----------------+------------------------------------+

どちらも、消したい1行だけが選ばれました。

場面5:DELETE に列を書いて、エラーになった

ヒントは「SELECT … FROM の部分を DELETE FROM に変える」でした。私は、SELECT のところだけを DELETE に変えて、列や * を残したまま流しました。

Bash
sudo mysql wp_practice -e "DELETE  comment_ID, comment_post_ID, comment_author FROM wp_comments WHERE comment_post_ID=1"
sudo mysql wp_practice -e "DELETE  * FROM wp_term_relationships WHERE object_id=1"

結果の例:

Plaintext
ERROR 1109 (42S02) at line 1: Unknown table 'comment_ID' in MULTI DELETE
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* FROM wp_term_relationships WHERE object_id=1' at line 1
  • ERROR 1109 … in MULTI DELETE:
    DELETE のすぐあとに名前を書くと、MariaDB は「いくつかのテーブルから、まとめて消す」書き方(MULTI DELETE)だと読む。comment_ID というテーブルはないので、エラー
  • ERROR 1064 near ‘* FROM …’:
    DELETE のあとに * は書けない、という文の形のエラー

どちらもエラーで止まったので、何も消えていません。場面0の表のとおり、DELETE には列を書きません。行をまるごと消すからです。

Bash
sudo mysql wp_practice -e "DELETE FROM wp_term_relationships WHERE object_id=1"
sudo mysql wp_practice -e "DELETE FROM wp_comments WHERE comment_post_ID=1"

今度は何も表示されずに終わりました。DELETE は、うまくいっても何も出ません。

消えたかの確かめで、古い SELECT を呼び出した

消えたかを確かめるために、場面4の SELECT をもう一度流しました。wp_comments は何も出ず、消えていました。ところが wp_term_relationships のほうは、上矢印のキーで呼び出したコマンドが、場面4で最初にまちがえた SELECT(SELECT ID, post_title … AND term_taxonomy_id=1)で、また ERROR 1054 が出ました。第2回で控えが上書きされたのと同じ、「履歴から呼び出したコマンドが、思っていたものとちがう」まちがいです。

正しい SELECT で、確かめ直しました。

Bash
sudo mysql wp_practice -e "SELECT * FROM wp_term_relationships WHERE object_id=1"

何も出ませんでした。ID 1 を指していた2つの行は、どちらも消えています。

場面6:未分類の数を確かめたら、もう正しかった

最後は、未分類の記事の数(count)です。SQL で未分類の行を消したので、count は前の数のままのはず、と考えていました。

最初は、count を wp_term_relationships で探して、エラーになりました。

Bash
sudo mysql wp_practice -e "SELECT term_taxonomy_id, count FROM wp_term_relationships WHERE term_taxonomy_id=1"

結果の例:

Plaintext
ERROR 1054 (42S22) at line 1: Unknown column 'count' in 'SELECT'

count があるのは、名前のよく似た wp_term_taxonomy のほうでした。

No.テーブル中身1行は
1wp_term_relationshipsどの記事が、どのカテゴリーに入っているか記事とカテゴリーの組み合わせ1つ
2wp_term_taxonomyカテゴリーそのもの(count はここ)カテゴリー1つ
Bash
sudo mysql wp_practice -e "SELECT term_taxonomy_id, count FROM wp_term_taxonomy WHERE term_taxonomy_id=1"

結果の例:

Plaintext
+------------------+-------+
| term_taxonomy_id | count |
+------------------+-------+
|                1 |     1 |
+------------------+-------+

count は 1 でした。これが「消した Hello world! の分が残った 1」なのか、「新しい Hello world!(ID 4321)の 1」なのかを見るために、未分類に入っている記事を出しました。

Bash
sudo mysql wp_practice -e "SELECT * FROM wp_term_relationships WHERE term_taxonomy_id=1"

30行が出ました。ID 4321 のほかに、本番から読み込んだ記事(下書きにした Laravel の記事などと同じ番号)が入っていました。count は公開中の記事だけを数えるので、30行のうち公開中がいくつかを数えます。ここは、2つのテーブルをつなぐ JOIN を使うので、完成した SQL を教えてもらいました。

Bash
sudo mysql wp_practice -e "SELECT p.post_status, COUNT(*) AS n FROM wp_term_relationships tr JOIN wp_posts p ON p.ID = tr.object_id WHERE tr.term_taxonomy_id = 1 AND p.post_type = 'post' GROUP BY p.post_status;"
  • wp_term_relationships tr:
    テーブルに tr という短い呼び名を付ける
  • JOIN wp_posts p ON p.ID = tr.object_id:
    wp_posts を p と呼んでつなげる。tr の object_id と、p の ID が同じ行どうしを、1つの行にする
  • GROUP BY p.post_status:
    記事の状態(公開中・下書きなど)ごとにまとめて数える

結果の例:

Plaintext
+-------------+----+
| post_status | n  |
+-------------+----+
| draft       | 28 |
| private     |  1 |
| publish     |  1 |
+-------------+----+

公開中は1本(ID 4321)だけでした。count の 1 は、正しい数です。新しい Hello world! を管理画面で作ったときに、WordPress が未分類の数を数え直していたので、今回は数え直す必要がありませんでした。

まとめ

第3回では、消した記事(ID 1)を指したまま残っていた2つの行を、控えを取ってから片付けました。未分類の数は、管理画面で記事を作ったときに数え直されていて、正しいままでした。

覚えたことは、次のとおりです。

No.覚えたことまちがえたところ
1前のコマンドをまねするときは、テーブル・条件の列・ファイルの名前の3か所を見比べるテーブルと条件が wp_posts・ID = 4321 のままだった、ファイルの名前を直し忘れた
2どのテーブルの控えかは、INSERT INTO のあとのテーブルの名前で確かめるINSERT の行があるかだけを見て、中身がちがうのに気づかなかった
3テーブルごとに、記事を指している列の名前がちがう。エラーの文に列の一覧が出るwp_term_relationships と wp_comments に ID を書いた
4> は、コマンドがエラーでも先にファイルを作る。確かめるのは、今作ったファイルエラーのときの空のファイルを grep していた
5控え・確かめる SELECT・DELETE の条件は、同じにそろえるSELECT で別の条件を書いた
6DELETE には列も * も書かないDELETE のあとに列や * を残した
7履歴から呼び出したコマンドは、流す前に読み直す古い SELECT を呼び出して流した
8count は wp_term_taxonomy にあり、公開中の記事だけを数える名前の似た wp_term_relationships で探した

今回いちばん多かったのは、前のコマンドをまねして、どこかを直し忘れるまちがいでした。コピーして直すのは速いですが、直す場所が多いほど、直し忘れも増えます。

SQLで記事を触ると、カテゴリーの数がずれることは、SQLで下書きに戻したら空のカテゴリーが残った記事でも書いています。SQLの部品の意味は、データベースのコマンドの記事で説明しています。

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

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

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

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

MySQL
watasoftdevをフォローする

コメント