format_list_bulleted
【MySQL】MySQLでブログで用いるタグ機能のデータベースをテーブル設計から実装まで解説
最終更新日時:2020-05-08 11:22:09



ブログを作成する際にタグ機能を実装するケースは多いと思います。本サイトでもタグ機能を実装しています。タグ機能を実装しようと思った際に、これに関連するデータベースも作成しなければなりません。本サイトでは中間テーブルを用いたテーブル設計の仕方と、その実装方法を紹介します。

タグ機能に必要な要件は何か

タグ機能の実装を考える際にタグ機能がどのように使われるかを考える必要があります。一般的なタグ機能は以下のとおりですね。

  • 個々の記事にどんなタグ(複数)がついているのかを確認できる
  • タグのCRUD(追加, 読込, 変更, 削除)ができる
  • タグで記事を検索できるようにする

特にタグで検索ができるようになることが大きな特徴です。本記事ではこのような要件を満たすタグ機能を作成します。

中間テーブルを用いたテーブル設計

要件をもとにテーブルの設計をしましょう。前提として以下のようなブログの内容についてのテーブルがあるとします。

blogs
カラム名idtitlecontentcreated_atupdated_at
intvarchar(30)textdatetimedatetime
内容記事のID記事のタイトル記事の内容記事の作成日記事の最終更新日

まずは、タグのCRUD処理をする必要があるのでtagsというテーブルを作成します。

tags
カラム名idnamecreated_atupdated_at
intvarchar(30)datetimedatetime
内容タグのIDタグの名前タグの作成日タグの最終更新日

次にブログのidとタグのidを紐付けるblogs_tagsというテーブル(中間テーブル)を作成します。この中間テーブルを作成することでタグがついているブログの記事を検索することができます。

blogs_tags
カラム名idblog_idtag_id
intint
int
内容IDブログのIDタグのID

例えばid=5のタグがついたブログを検索するときにはblogs_tagsテーブルでtag_id=5のものに関連づいているblog_idを特定することでblogsテーブルtag=5のタグがついているブログを全て特定できます。

テーブルの実装(コマンド付き)

それでは実際にデータベースを作成してみましょう。MySQLで作成します。今回使用したコマンドはddlファイルでcode-databaseのgithubにアップロードしてあるので、手元で確認したい方は活用してみてください!

事前準備とblogsデータの確認

まずは、データベースの作成とblogsテーブルを作成してblogの初期状態を準備しましょう。このデータを用いない場合はidカラムの値ををblogs_tagsテーブルで使用するので、必ず一意のブログが特定できるidを設定しましょう。

CREATE DATABASE sample_blog;
USE sample_blog
CREATE TABLE blogs(
    id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    title varchar(30) NOT NULL,
    content text NOT NULL,
    created_at datetime NOT NULL,
    updated_at datetime
);
INSERT INTO blogs 
(title, content, created_at)
VALUES 
('今日の出来事', 'hogehoge', now()),
('昨日の出来事', 'fugafuga', now()),
('一昨日の出来事', 'ほげほげフガフガ', now());

テーブルが正しくできているか確認してみましょう。

mysql> SELECT * FROM blogs;
+----+-----------------------+--------------------------+---------------------+------------+
| id | title                 | content                  | created_at          | updated_at |
+----+-----------------------+--------------------------+---------------------+------------+
|  1 | 今日の出来事            | hogehoge                 | 2020-04-26 21:13:49 | NULL       |
|  2 | 昨日の出来事            | fugafuga                 | 2020-04-26 21:13:49 | NULL       |
|  3 | 一昨日の出来事          | ほげほげフガフガ            | 2020-04-26 21:13:49 | NULL       |
+----+-----------------------+--------------------------+---------------------+------------+
3 rows in set (0.01 sec)

このように3つのデータを持つテーブルが表示されれば大丈夫です。

tagsテーブルの作成

続いて設計に則りtagsテーブルを作成しましょう。

CREATE TABLE tags(
    id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name varchar(30) NOT NULL,
    created_at datetime NOT NULL,
    updated_at datetime
);

idはblogs_tagsテーブルで起用するので必ず一意のタグが特定できるidを設定しましょう。tagsの他のカラムには用途に応じた物を作っても構いません。

tagsテーブルへの初期値の代入

今回は以下のように二つのタグを作成します。

INSERT INTO tags
(name, created_at)
VALUES
('日記', now()),
('日本語', now());

正しくデータが入っているか確認してみましょう。

mysql> SELECT * FROM tags;
+----+-----------+---------------------+------------+
| id | name      | created_at          | updated_at |
+----+-----------+---------------------+------------+
|  1 | 日記       | 2020-04-26 21:13:50 | NULL       |
|  2 | 日本語     | 2020-04-26 21:13:50 | NULL       |
+----+-----------+---------------------+------------+
2 rows in set (0.00 sec)

上のように'日記'と'日本語'というタグがついていれば大丈夫です。

blogs_tagsテーブルの作成

中間テーブルであるblogs_tagsを作成しましょう。

CREATE TABLE blogs_tags(
    id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    blog_id int NOT NULL,
    tag_id int NOT NULL
);

blog_idとtag_idをセットにして多対多の関係のブログとタグの関連を保存していきます。

blogs_tagsテーブルへの初期値の代入

今回は’日記’タグを全てのブログに、'日本語'タグをcontentが日本語で書かれているid=3のブログにつけます。実際の実装ではブログを投稿する際にタグをつける場合が多いので、その際にblogsテーブルへのデータの変更とともにblogs_tagsへのデータの変更もするようにしましょう。

INSERT INTO blogs_tags
(blog_id, tag_id)
VALUES
(1, 1),
(2, 1),
(3, 1),
(3, 2);

これまで同様適切にデータが入っているかを確認してみましょう。

mysql> SELECT * FROM blogs_tags;
+----+---------+--------+
| id | blog_id | tag_id |
+----+---------+--------+
|  1 |       1 |      1 |
|  2 |       2 |      1 |
|  3 |       3 |      1 |
|  4 |       3 |      2 |
+----+---------+--------+
4 rows in set (0.01 sec)

上のようなデータが入っていれば大丈夫です。これで中間テーブルを用いたタグ機能の実装が完了しました。

動作確認

最後に適切にタグ機能が使えるかを確認してみます。ここで、最初に設定したタグ機能の要件を確認してみましょう。

  • 個々の記事にどんなタグ(複数)がついているのかを確認できる
  • タグのCRUD(追加, 読込, 変更, 削除)ができる
  • タグで記事を検索できるようにする

タグのCRUD機能ができるのはtagsテーブルがあることから自明と言えるので、個々の記事でついているタグを確認できるかと、タグで記事を検索できるかを確認してみましょう。

個々の記事でタグを確認する

INNER JOIN句を用いることで中間テーブルを介した検索が一行でできます。

まずはid=1のblogsの記事についているタグを確認してみましょう。id=1のブログには'日記'タグのみがついているはずです。

SELECT tags.name
FROM tags
INNER JOIN blogs_tags 
ON blogs_tags.tag_id = tags.id 
WHERE blogs_tags.blog_id = 1;

(クエリの結果)

+--------+
| name   |
+--------+
| 日記   |
+--------+
1 row in set (0.01 sec)

続いてid=3のblogsの記事についているタグを確認してみましょう。id=3のブログには'日記'タグと'日本語'タグがついているはずです。

SELECT tags.name
FROM tags
INNER JOIN blogs_tags 
ON blogs_tags.tag_id = tags.id 
WHERE blogs_tags.blog_id = 3;

(クエリの結果)

+-----------+
| name      |
+-----------+
| 日記      |
| 日本語     |
+-----------+
2 rows in set (0.01 sec)

それぞれの記事に対して正しく機能しています!

タグで記事を検索する

続いてタグを指定してそのタグがついている記事を検索してみましょう。前項と同様にINNER JOIN句を使用します。

まずはid=1,name='日記'のタグがついた記事を検索します。これには全ての記事がヒットするはずです。

mysql> SELECT blogs.id, blogs.title, blogs.content
    -> FROM blogs
    -> INNER JOIN blogs_tags
    -> ON blogs_tags.blog_id = blogs.id
    -> WHERE blogs_tags.tag_id = 1;
+----+-----------------------+--------------------------+
| id | title                 | content                  |
+----+-----------------------+--------------------------+
|  1 | 今日の出来事            | hogehoge                 |
|  2 | 昨日の出来事            | fugafuga                 |
|  3 | 一昨日の出来事          | ほげほげフガフガ            |
+----+-----------------------+--------------------------+
3 rows in set (0.01 sec)

続いて、id=2,name='日本語'のタグがついている記事を検索してみましょう。これにはid=3の記事のみがヒットするはずです。

mysql> SELECT blogs.id, blogs.title, blogs.content
    -> FROM blogs
    -> INNER JOIN blogs_tags
    -> ON blogs_tags.blog_id = blogs.id
    -> WHERE blogs_tags.tag_id = 2;
+----+-----------------------+--------------------------+
| id | title                 | content                  |
+----+-----------------------+--------------------------+
|  3 | 一昨日の出来事          | ほげほげフガフガ            |
+----+-----------------------+--------------------------+
1 row in set (0.02 sec)

それぞれのタグに対して適切に検索が行えていることを確認できました!これでタグ機能の検証はバッチリです。

この記事のまとめ

本記事では中間テーブルを用いたタグ機能の実装を紹介しました。最後に要点をまとめます。

  • タグ検索には中間テーブルを用いると良い
  • 中間テーブルを介したクエリの実行ではINNER JOIN句が便利である

データベースを駆使してWebアプリを作りましょう!