どうも、コウイチです。
前回の記事で、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 |
1 2 3 4 5 6 7 8 9 |
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 |
1 2 3 4 5 6 7 8 9 10 |
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 |
1 2 3 4 5 6 7 8 9 10 |
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法によるタグ付け機能の実装の基本はご理解いただけたかと思います。
今後、記事にタグを追加したり、記事からタグを削除したりなどの操作も扱っていけたらと思います。
それでは、ありがとうございました。
コメント