とりあえず簡易処理です。
例えば1記事に対してタグが複数つくようなシステムがあるとします。
記事テーブルてきなものに、記事タグテーブルてきなものが1対多になっている感じとします
posts (記事テーブル)
id | title |
---|---|
1 | 夏休みのおすすめスポット |
post_tags (記事に付与されたタグ)
post_id | tag_id | name |
---|---|---|
1 | 34 | 夏休み |
1 | 567 | おすすめ |
1 | 98 | 子供 |
これを諸所の理由により、1クエリしかできない時に記事の1レコードに複数のタグも一緒にまとめて、1行で取得したい!
そんなときは、
SELECT
p.id AS id,
p.title AS title,
t.ids AS tag_ids,
t.names AS tag_names
FROM
posts AS p
LEFT JOIN (
SELECT
pt.post_id,
GROUP_CONCAT(pt.tag_id) AS ids,
GROUP_CONCAT(REPLACE(REPLACE(pt.name, '&', '&'), ',', ',')) AS names
FROM
post_tags AS pt
GROUP BY
pt.post_id
) AS t ON t.post_id = p.id
タグの複数行をGROUP_CONCATを使って1行にまとめます。
GROUP_CONCATで「34,567,98」のように、カンマ区切りで1行になってくれます。
これをphpで
$tagIds = explode(',', $row['tag_ids'])
のようにカンマ区切りで配列にもどせば完了!
しかし、ちょっとだけ注意!
注意したいのがこれがidで中身が数値とわかってる場合のみ。
フリーテキストであるタグの名前「夏休み」とかの場合を考慮しなければいけない。
なぜなら、タグの名前に
「カ,ン,マ,区,切,り,し,て,や,ん,よ」
みたいな意地悪なタグを付けられてしまうかも。
それを考慮すると
GROUP_CONCAT(REPLACE(REPLACE(pt.name, '&', '&'), ',', ','))
htmlのエスケープ処理をちょっとだけ借用
取得時に「,」を「,」に置換してエスケープします。
さらにタグに「,」を含めるいじわるもできるので、「&」を「&」に置換してエスケープします。
そしてphp側でエスケープを戻す処理を足して
function unescape ($str)
{
return str_replace('&', '&', str_replace(',', ',', $str));
}
$tags = [];
$ids = explode(',', $row['tag_ids']);
$names = explode(',', $row['tag_naames']);
foreach ($ids as $index => $id) {
$tags[] = [
'id' => (int)$ids[$index],
'name' => unescape($names[$index]),
];
}
と、すれば1クエリの縛りでも1対多のタグデータもphp上で配列として取り出せます
以上です!