【2026年10月15日時点の情報です】
このブログは、自宅のAlmaLinuxサーバーでWordPressを動かしています。記事の書き直しやサイトの整理では、AI(Claude)に教わりながら、データベースを操作するコマンドを何十回も実行してきました。
ただ、正直に言うと、言われるがままにコピーして貼り付けていただけで、何をしているのかはほとんど分かっていませんでした。それでは、何かあったときに自分で判断できません。
そこで、実際に使ってきたコマンドを、場面ごとに「何のためか」「それぞれの部分にどんな意味があるか」から整理しました。同じように、コピペでデータベースを触っている人の参考になればうれしいです。
WordPressのデータはどこにあるのか
WordPressの記事やカテゴリー、設定は、ファイルではなくデータベースに入っています。このブログでは、データベースのソフトにMariaDB(MySQLとほぼ同じ使い方ができるもの)を使っています。
データベースの中は、Excelの表のような「テーブル」に分かれています。よく使ったのは次の4つです。
| テーブル | 入っているもの | 例 |
|---|---|---|
| wp_posts | 記事・固定ページ・画像の登録など | タイトル(post_title)、本文(post_content)、スラッグ(post_name)、状態(post_status) |
| wp_postmeta | 記事や画像に付いた追加の情報 | アイキャッチの画像ID(_thumbnail_id)、画像のファイルの場所(_wp_attached_file)、メタディスクリプション |
| wp_options | サイト全体の設定 | テーマの設定、ウィジェットの中身 |
| wp_terms など | カテゴリーやタグ | カテゴリーの名前とスラッグ |
記事も画像も、wp_posts の1行として登録されています。どちらなのかは、post_type という列(記事なら post、画像なら attachment)で見分けます。
コマンドの入り口
どのコマンドも、まず次の形から始まっています。
sudo mysql wordpress -e "SELECT ...;"- sudo:
管理者の権限で実行する。このサーバーのMariaDBは、管理者(root)でログインするときに、パスワードの代わりにLinuxの管理者の権限で確かめる設定になっているため - mysql:
データベースに命令を送るためのプログラム - wordpress:
使うデータベースの名前 - -e “…”:
「この文字の命令を1回だけ実行して終わる」という意味。付けないと、命令を打ち込む画面が開いたままになる - -N(付けたときだけ):
結果の一番上の列の名前を出さない。結果を、ほかのコマンドに渡して加工するときに使う
「SELECT …;」の部分がSQL(データベースへの命令の言葉)で、ここが場面ごとに変わります。
長いSQLのときは、次のような書き方もしました。
sudo mysql wordpress <<'SQL'
UPDATE ...;
SELECT ...;
SQL- <<‘SQL’ 〜 SQL:
「ここから SQL と書いた行までを、まとめて mysql に渡す」という意味(ヒアドキュメント)。’SQL’ と引用符で囲むと、中の \ や $ をシェルが勝手に書き換えないので、正規表現などをそのまま書ける
場面1:変える前に、控えを取る
データベースを書き換えるコマンドは、WordPressの画面と違って「元に戻す」ボタンがありません。なので、書き換える前に必ず控え(バックアップ)を取っていました。
データベースの控え
sudo mysqldump wordpress > ~/work/backup/wordpress-20261015.sql
sudo mysqldump wordpress wp_posts > ~/work/backup/wp_posts-20261015.sql- mysqldump:
データベースの中身を、作り直せる形のSQLの文字にして書き出すプログラム - wordpress:
控えを取るデータベースの名前。1行目のように名前だけなら、全部のテーブル - wp_posts(2行目):
テーブルの名前を続けると、そのテーブルだけの控えになる。記事の本文だけを書き換えるときは、これで十分で、ファイルも小さくて済む - >:
画面に出る結果を、右のファイルに書き込む
画像ファイルの控え
画像はデータベースではなく、サーバーのフォルダに入っているので、別に控えを取ります。
sudo tar czf ~/work/backup/uploads-20261015.tar.gz -C /var/www/html/wp-content uploads- tar:
複数のファイルやフォルダを1つのファイルにまとめるプログラム - czf:
c(まとめる)、z(圧縮する)、f(次に書いた名前のファイルにする) - -C /var/www/html/wp-content uploads:
「wp-content のフォルダに移動してから、uploads のフォルダをまとめる」という意味。こうすると、控えの中のファイルの場所が uploads/… から始まるので、戻すときに扱いやすい
控えから戻す
全部を戻すときは、控えのSQLをそのまま mysql に流し込みます。
sudo mysql wordpress < ~/work/backup/wp_posts-20261015.sql- <:
右のファイルの中身を、命令として左のプログラムに渡す(> の逆向き)
ただし、全部を戻すと、控えを取ったあとの変更も消えてしまいます。実際に、画像を3枚だけ間違えて消してしまったときは、次のように「一時的な別のデータベースに控えを読み込んで、必要な行だけを書き戻す」方法を使いました。
sudo mysql -e "CREATE DATABASE wp_restore;"
sudo mysql wp_restore < ~/work/backup/wordpress-20261015.sql
sudo mysql -e "
INSERT INTO wordpress.wp_posts SELECT * FROM wp_restore.wp_posts WHERE ID IN (474, 2923, 1197);
INSERT INTO wordpress.wp_postmeta SELECT * FROM wp_restore.wp_postmeta WHERE post_id IN (474, 2923, 1197);
DROP DATABASE wp_restore;"- CREATE DATABASE wp_restore:
控えを読み込むための、空のデータベースを作る - INSERT INTO A SELECT * FROM B WHERE …:
Bの表から条件に合う行を取り出して、Aの表に入れる。wordpress.wp_posts のように「データベース名.テーブル名」と書くと、別のデータベースどうしでやり取りできる - DROP DATABASE wp_restore:
使い終わった一時的なデータベースを消す
場面2:記事を探して、編集画面のURLを出す
「この記事を直したい」というときに、記事のスラッグから、編集画面のURLを出していました。
sudo mysql wordpress -N -e "SELECT CONCAT('https://softdev-learn.cc/wp-admin/post.php?post=', ID, '&action=edit'), post_name FROM wp_posts WHERE post_type = 'post' AND post_status = 'publish' AND post_name IN ('pc-spec','home-server');"- SELECT 列, 列 FROM テーブル:
テーブルから、指定した列を取り出す。SQLの一番基本の形 - CONCAT(…):
文字をつなげる。ここでは、編集画面のURLの前半+記事のID+後半をつなげて、そのまま開けるURLにしている - WHERE 条件:
条件に合う行だけを取り出す。AND でつなぐと「全部の条件に合うもの」 - post_type = ‘post’:
記事だけ(画像や固定ページを除く) - post_status = ‘publish’:
公開中だけ(下書きは draft、非公開は private) - post_name IN (‘…’,’…’):
スラッグが、かっこの中のどれかに当てはまるもの
場面3:本文の中の文字を探す
本文に特定の文字が残っていないかを探すときの形です。例えば、記事の書き直しのメモ「【画像:」が、公開中の記事に残っていないかを探すときは、次のようにします。
sudo mysql wordpress -e "SELECT ID, post_name FROM wp_posts WHERE post_type = 'post' AND post_status = 'publish' AND post_content LIKE '%【画像:%';"- LIKE ‘%…%’:
「この文字を含む」という意味。% は「何でもよい文字が0文字以上」の印で、前後に付けると「途中のどこかに含む」になる
見つかった文字の前後だけを見たいときは、次の形にしました。
sudo mysql wordpress -N -e "SELECT SUBSTRING(post_content, LOCATE('3周年', post_content) - 200, 400) FROM wp_posts WHERE ID = 2563;"- LOCATE(‘文字’, 列):
その文字が、何文字目に出てくるかを返す - SUBSTRING(列, 始め, 長さ):
始めの位置から、指定した長さだけ取り出す。ここでは、見つかった位置の200文字前から400文字を出している
このとき、文字が見つからないと LOCATE は 0 を返すので、記事の一番最後の部分が表示されます。実際に「3周年の文がどこにあるか」を探したときは、記事の最後が出てきたので、もう消えていると分かりました。
場面4:別のテーブルとつなげて見る(アイキャッチのファイル名)
記事のアイキャッチの画像のURLを一覧にしたいとき、1つのテーブルだけでは分かりません。
| テーブル | 分かること |
|---|---|
| wp_postmeta(記事の _thumbnail_id) | 記事に付いているアイキャッチの画像のID |
| wp_postmeta(画像の _wp_attached_file) | その画像のファイルの場所 |
この2つを、JOIN でつなげます。
sudo mysql wordpress -e "
SELECT p.ID, p.post_name, CONCAT('https://softdev-learn.cc/wp-content/uploads/', f.meta_value) AS eyecatch
FROM wp_posts p
JOIN wp_postmeta t ON t.post_id = p.ID AND t.meta_key = '_thumbnail_id'
JOIN wp_postmeta f ON f.post_id = t.meta_value AND f.meta_key = '_wp_attached_file'
WHERE p.post_name IN ('nomu-yoguret-review','vscode-profile');"- wp_posts p:
テーブルに p という短い呼び名を付ける。同じ wp_postmeta を2回使うので、t と f で呼び分けている - JOIN 表 ON 条件:
条件に合う行どうしを横につなげる。1つ目は「記事のID=メタの post_id、かつメタの種類がアイキャッチ」、2つ目は「アイキャッチの画像ID(t.meta_value)=画像のメタの post_id、かつ種類がファイルの場所」 - AS eyecatch:
結果の列に名前を付ける
つまり、「記事 → アイキャッチの画像ID → 画像のファイルの場所」と、2回たどっています。
数える・まとめる
カテゴリーごとの記事の数や、404の多いURLを出すときは、数える命令を使いました。
sudo mysql wordpress -e "
SELECT url, COUNT(*) AS hits, MAX(created) AS last
FROM wp_redirection_404
WHERE created > NOW() - INTERVAL 30 DAY
GROUP BY url HAVING hits >= 2
ORDER BY hits DESC LIMIT 30;"- wp_redirection_404:
プラグイン Redirection が記録している「ページが見つからなかったアクセス」のテーブル - GROUP BY url:
同じURLの行を1つにまとめる - COUNT(*):
まとめた行の数(ここではアクセスの回数) - MAX(created):
まとめた中で一番新しい日時(最後のアクセス) - NOW() – INTERVAL 30 DAY:
今から30日前。それより新しいものだけにする - HAVING hits >= 2:
まとめたあとの条件。2回以上のものだけ(WHERE はまとめる前、HAVING はまとめたあとの条件) - ORDER BY hits DESC LIMIT 30:
回数の多い順(DESC)に並べて、上から30行だけ
場面5:まとめて書き換える(UPDATE)
ALTERNAのカテゴリーの場所を変えたとき、5本の記事の本文に入っていた古いカテゴリーのURLを、新しいURLにまとめて置き換えました。
sudo mysql wordpress -e "
UPDATE wp_posts
SET post_content = REPLACE(post_content, '/category/investment/estate-crowd/alterna/', '/category/investment/digital_securities/alterna/')
WHERE post_type = 'post' AND post_content LIKE '%/category/investment/estate-crowd/alterna/%';
SELECT ROW_COUNT();"- UPDATE テーブル SET 列 = 値 WHERE 条件:
条件に合う行の、列の中身を書き換える。WHERE を付け忘れると、全部の行が書き換わるので一番注意するところ - REPLACE(列, ‘古い文字’, ‘新しい文字’):
列の中の、古い文字を全部、新しい文字に置き換えた結果を返す - WHERE … LIKE ‘%古いURL%’:
古いURLを含む記事だけを対象にする(含まない記事は書き換えない) - SELECT ROW_COUNT():
直前の命令で、何行が変わったかを出す。思った数(このときは5)と合っているかを確かめる
書き換える前に、同じ条件で数える
UPDATE の前には、同じ WHERE の条件で SELECT して、対象が何件かを確かめていました。
sudo mysql wordpress -e "SELECT ID, post_name FROM wp_posts WHERE post_type = 'post' AND post_content LIKE '%/category/investment/estate-crowd/alterna/%';"この一覧が思ったとおりなら、同じ条件で UPDATE します。SELECT と UPDATE で条件を同じにしておけば、「思っていない記事まで書き換えた」ということが起きません。
場面6:別の値を使って書き換える(アイキャッチの一括差し替え)
カテゴリーの共通のアイキャッチを、タイトルを入れた新しい画像に替えたときは、38本の記事のアイキャッチを、1回のコマンドで差し替えました。
sudo mysql wordpress <<'SQL'
SET @n1 = (SELECT post_id FROM wp_postmeta WHERE meta_key = '_wp_attached_file' AND meta_value LIKE '%category-estate-crowd%' ORDER BY post_id DESC LIMIT 1);
SELECT @n1;
UPDATE wp_postmeta SET meta_value = @n1 WHERE meta_key = '_thumbnail_id' AND meta_value = '3669' AND @n1 IS NOT NULL;
SQL- SET @n1 = (SELECT …):
@ で始まる名前は、SQLの中で使える一時的な入れ物(変数)。ここでは、新しくアップロードした画像のIDを、ファイル名から探して入れている。IDを調べて手で書き写さなくて済む - ORDER BY post_id DESC LIMIT 1:
同じ名前のファイルが複数あったときに、一番新しい(IDが大きい)1つにする - SELECT @n1:
見つかったIDを画面に出して、合っているか確かめる - WHERE meta_key = ‘_thumbnail_id’ AND meta_value = ‘3669’:
アイキャッチが古い画像(3669)になっている記事だけを対象にする - AND @n1 IS NOT NULL:
新しい画像が見つからなかったとき(@n1 が空)は、何も書き換えない。アイキャッチが空になる事故を防ぐ
行を消してから入れ直す(メタディスクリプションの一括登録)
メタディスクリプションがない22本に、まとめて登録したときは、記事ごとに次の2行を並べたファイルを作って、流し込みました。
DELETE FROM wp_postmeta WHERE post_id = 704 AND meta_key = 'the_page_meta_description';
INSERT INTO wp_postmeta (post_id, meta_key, meta_value) VALUES (704, 'the_page_meta_description', 'Webページの骨組みを作るHTMLの基本を…');- DELETE FROM … WHERE …:
条件に合う行を消す。空のメタディスクリプションの行が残っていると、2つ並んでしまうので、先に消している - INSERT INTO テーブル (列, 列, 列) VALUES (値, 値, 値):
新しい行を1つ追加する。the_page_meta_description は、テーマ Cocoon がメタディスクリプションを入れておく場所の名前
ファイルにしたSQLは、場面1の「戻す」と同じく < で流し込みます。
言語:bash
sudo mysql wordpress < ~/work/meta-desc-20261015.sql
結果を加工する、シェルの道具
SQLの結果を、そのまま読むのではなく、ほかのコマンドに渡して加工することもよくありました。
sudo mysql wordpress -N -e "SELECT post_content FROM wp_posts WHERE post_name = 'cofo-chair-premium';" | grep -oE "softdev-learn\.cc/[a-z0-9_-]+/" | sort -u- |(パイプ):
左のコマンドの結果を、右のコマンドに渡す - grep -oE “…”:
文字を探す。-o は「見つかった部分だけを出す」、-E は「正規表現(文字の並びの決まりを記号で書く方法)を使う」 - softdev-learn.cc/[a-z0-9_-]+/:
「softdev-learn.cc/」のあとに、英小文字・数字・_・- が1文字以上続いて、/ で終わるもの(つまり、このブログの記事のURL)。. は「本当のピリオド」という意味(. だけだと「何でもよい1文字」になる) - sort -u:
並べ替えて、同じものを1つにまとめる
このほかに、次のような道具を組み合わせました。
| 道具 | 使い方 |
|---|---|
| wc -l | 行の数を数える(何件あったかを確かめる) |
| head -20 | 最初の20行だけを見る |
| for 名前 in A B C; do …; done | A・B・C のそれぞれで、同じコマンドをくり返す(複数の記事を順に調べる) |
| curl -sI URL | ページを開いたときの返事の見出しだけを出す。301(転送)か404(見つからない)かの確認に使った |
安全に操作するために決めていること
コマンドの意味が分かってくると、事故が起きやすい場所も見えてきました。今は、次の5つを守っています。
- 書き換える前に、必ず控えを取る:
mysqldump で、少なくとも書き換えるテーブルの控えを取る - 書き換える前に、同じ条件で SELECT する:
対象が思った記事・思った件数かを確かめてから UPDATE する - WHERE を必ず付ける:
UPDATE や DELETE で WHERE を忘れると、全部の行が変わる - 変わった件数を確かめる:
ROW_COUNT() や、変更後の SELECT で、件数が思ったとおりかを見る - 一部だけ間違えたときは、一部だけ戻す:
控えを別のデータベースに読み込んで、必要な行だけを書き戻す
まとめ
コピペで動かしていたコマンドも、分けてみると、使っていたSQLは SELECT(見る)、UPDATE(書き換える)、INSERT・DELETE(行を足す・消す)の4つがほとんどでした。そこに、WHERE(どの行か)、JOIN(ほかのテーブルとつなぐ)、REPLACE(文字の置き換え)などを組み合わせているだけです。
意味が分かると、AIが出したコマンドでも、「この WHERE で本当にこの記事だけが対象になるか」「控えは取ったか」を、自分で確かめられるようになります。データベースを直接さわるのは便利な反面、元に戻すボタンがないので、控えと確認だけは習慣にするのがおすすめです。
このコマンドを使って、実際に WordPress の困りごとを直した話は、SQL で記事を下書きに戻したら空のカテゴリーが出た件の記事と、Redirection のルールが保存されなかった件の記事に書いています。
自宅サーバーの構成は、自宅サーバー構築メモにまとめています。
この記事は、シリーズ「組み込みエンジニアの Web 開発入門」の1本です。ほかの回は、シリーズの目次からどうぞ。



コメント