【MySQL】タグ付け機能の実装にオススメなテーブル設計(TOXI法)その2

プログラミング

どうも、コウイチです。

前回の記事で、MySQLでタグ付け機能を実装してみました。

【MySQL】タグ付け機能の実装にオススメなテーブル設計(TOXI法)その1
どうも、コウイチです。 今回は、MySQLでタグ付け機能を実装してみます。 今回タグ機能の実装を初めてやることになり、色々調査していたところ、なんとか法という名前がついた設計が色々あるみたいなので、それを有り難く使わせてもらいま...

今回は、前回作ったTOXI法によるテーブル設計を使用して、記事のデータを、それに紐づけられたタグ名とともに抽出してみたいと思います。

テーブル設計のおさらい

前回、以下の3つのテーブルを作成しました。

entryテーブル

id title detail
1 PHP記事 これはPHPに関する記事です。
2 C#記事 これはC#に関する記事です。
3 PHP&MySQL記事 これはPHPとMySQLに関する記事です。
4 雑記 これは雑記です。

tagテーブル(タグのマスタ)

id name
1 Java
2 PHP
3 MySQL
4 JavaScript
5 C#

tag_mapテーブル(どの記事にどのタグが紐づいているかを繋ぐテーブル)

id entry_id tag_id (説明)
1 1 2 entry_id=1(PHP記事)に対してtag_id=2(PHP)のタグを紐づけ
2 2 5 entry_id=2(C#記事)に対してtag_id=5(C#)のタグを紐づけ
3 3 2 entry_id=3(PHP&MySQL記事)に対してtag_id=2(PHP)のタグを紐づけ
4 3 3 entry_id=3(PHP&MySQL記事)に対してtag_id=3(MySQL)のタグを紐づけ

記事の情報をSELECTしてみよう

この記事のゴールは、以下のように、エントリーID、記事タイトル、記事内容、タグ名(複数紐づいている場合はカンマ区切りで)をSELECTすることです。

エントリーID 記事タイトル 記事内容 タグ名
1 PHP記事 これはPHPに関する記事です。 PHP
2 C#記事 これはC#に関する記事です。 C#
3 PHP&MySQL記事 これはPHPとMySQLに関する記事です。 PHP,MySQL
4 雑記 これは雑記です。 NULL

外部結合を使ってみる

今回、テーブルはentry、tag、tag_mapの3つありますので、これらを外部結合で結合して、SELECTしてみましょう。

記事ID 記事タイトル 記事内容 タグ名
1 PHP記事 これはPHPに関する記事です。 PHP
2 C#記事 これはC#に関する記事です。 C#
3 PHP&MySQL記事 これはPHPとMySQLに関する記事です。 PHP
3 PHP&MySQL記事 これはPHPとMySQLに関する記事です。 MySQL
4 雑記 これは雑記です。 NULL
SELECT 
	entry.id AS 記事ID, 
	entry.title AS 記事タイトル, 
	entry.detail AS 記事内容, 
	tag.name AS タグ名 
FROM 
	entry LEFT OUTER JOIN tag_map ON entry.id  = tag_map.entry_id 
	      LEFT OUTER JOIN tag     ON tag.id    = tag_map.tag_id 
ORDER BY entry.id;

と、こうなります。

しかしこれでは、タグが複数紐づいている記事は2重に表示されてしまいますね。

そこでグループ化です。

グループ化してみる

entry.idでグループ化してみます。

記事ID 記事タイトル 記事内容 タグ名
1 PHP記事 これはPHPに関する記事です。 PHP
2 C#記事 これはC#に関する記事です。 C#
3 PHP&MySQL記事 これはPHPとMySQLに関する記事です。 PHP
4 雑記 これは雑記です。 NULL
SELECT 
	entry.id     AS 記事ID, 
	entry.title  AS 記事タイトル, 
	entry.detail AS 記事内容, 
	tag.name     AS タグ名 
FROM
	entry LEFT OUTER JOIN tag_map ON entry.id = tag_map.entry_id 
	      LEFT OUTER JOIN tag     ON tag.id   = tag_map.tag_id 
GROUP BY entry.id 
ORDER BY entry.id;

おっと、これでは今度は、タグが複数紐づいている記事は、タグ名がひとつしか表示されません。グループ化してまとまってしまった複数のタグ名を、カンマ区切りで表示したいんですが、めんどくさそうですね。

しかし、便利な関数があります!

GROUP_CONCAT関数を使えば一発

GROUP_CONCAT関数は、区切り文字を指定すると、グループ化されてまとまった各値を、区切り文字で連結して吐き出してくれます。

GROUP_CONCAT(MySQL 5.6 リファレンスマニュアル)

この関数は、グループから連結された非 NULL 値を含む文字列の結果を返します。

記事ID 記事タイトル 記事内容 タグ名
1 PHP記事 これはPHPに関する記事です。 PHP
2 C#記事 これはC#に関する記事です。 C#
3 PHP&MySQL記事 これはPHPとMySQLに関する記事です。 PHP,MySQL
4 雑記 これは雑記です。 NULL
SELECT 
	entry.id     AS 記事ID, 
	entry.title  AS 記事タイトル, 
	entry.detail AS 記事内容, 
	GROUP_CONCAT(tag.name SEPARATOR ',') AS タグ名 
FROM
	entry LEFT OUTER JOIN tag_map ON entry.id = tag_map.entry_id 
	      LEFT OUTER JOIN tag     ON tag.id   = tag_map.tag_id 
GROUP BY entry.id 
ORDER BY entry.id;

これで、複数タグはカンマ区切りで出力することに成功しました。

便利ですね!

最後に

これで、TOXI法によるタグ付け機能の実装の基本はご理解いただけたかと思います。

今後、記事にタグを追加したり、記事からタグを削除したりなどの操作も扱っていけたらと思います。

それでは、ありがとうございました。

コメント