質問
これが効率的に行えるかどうかはわかりませんが、ここに私の問題があります:
私は、ブログ投稿と各ブログ投稿へのすべての返信にタグを付けることができる、本質的にブログエンジンとは何かを書いています。
つまり、「スタック」というタグの付いたブログ投稿と、「オーバーフロー」というタグの付いたその投稿への返信を作成できます。
今、ユーザーがアプリケーションの特別なページにアクセスしたときに最も人気のあるタグのリストを生成しようとしています。ブログ投稿の数が多い順にn個の最も人気のあるタグだけでなく、各タグに関連付けられているブログ投稿の数も返す必要があります。 / strong>。
したがって、BlogPost Aに" foo"のタグが付けられ、BlogPost Bの返信に" foo"のタグが付けられている場合、BlogPost Bはそうではありませんが、人気のあるタグの要約では合計2つのブログ投稿としてカウントされます技術的にタグ付けされています。
関連するテーブル/フィールドの説明は次のとおりです。
BlogPosts
| id # Primary key for all tables, Rails-style
BlogComments
| id
| blog_post_id
Tags
| id
| name # 'foo'
Taggings
| id
| tag_id
| blog_post_id
| blog_comment_id
便宜上、タグ付けには非正規化がいくつかあります。誰かがBlogPostにタグを付けると、blog_post_idフィールドが埋められ、blog_comment_idはNULLのままです。誰かがコメントを投稿にタグ付けすると、blog_post_idとblog_comment_idの両方が記入されます。
1つまたは複数のSQLクエリで最も人気のあるタグのソートされたリストを返す方法はありますか?誰かがページをヒットするたびにこれを実行するのではなく、cronジョブで数分ごとに計算コストの高いスクリプトを実行し、キャッシュされた出力をレンダリングする必要があるかもしれないと考えています...
ありがとう!
解決
これまでのところ、あなたのリクエストには複雑なものは何もありません:
SELECT
tag_id,
COUNT(blog_post_id) + COUNT(blog_comment_id) tag_count
FROM
Taggings
GROUP BY
tag_id
ORDER BY
COUNT(blog_post_id) + COUNT(blog_comment_id) DESC
「影響を受けたブログの投稿」をカウントする場合のみ、私はそれが方法だと思う:
SELECT
t.id tag_id,
t.name tag_name,
COUNT(DISTINCT COALESCE(x.blog_post_id, c.blog_post_id)) tag_count
FROM
Tags t
INNER JOIN Taggings x ON x.tag_id = t.id
LEFT JOIN BlogComments c ON c.id = x.blog_comment_id
GROUP BY
t.id,
t.name
ORDER BY
COUNT(DISTINCT COALESCE(x.blog_post_id, c.blog_post_id)) DESC
他のヒント
明らかな何かを見逃しているかもしれませんが、「誰かがコメントを投稿にタグ付けすると、blog_post_idとblog_comment_id"の両方を埋めるので、次のSQLでうまくいくはずです。ここでは、Tags.nameは一意であると想定しています。
SELECT MIN(ts.tag_id), t.name, COUNT(ts.blog_post_id) as rank
FROM Taggings ts
INNER JOIN Tags t ON ts.tag_id = t.id
GROUP BY t.name
ORDER BY COUNT(ts.blog_post_id) DESC
あなたが探しているものを期待してください。
試しませんでしたが、このようなものはどうですか?:
select t.Id,
t.Name,
count(*)
from Taggings tings
inner join Tags t
on (t.id = tings.blog_post_id or t.id = tings.blog_comment_id)
group by t.Id, t.Name
order by count(*) desc