難しいSQLクエリ:複雑な関連付けを持つモデルのタグの人気度

StackOverflow https://stackoverflow.com/questions/620788

  •  05-07-2019
  •  | 
  •  

質問

これが効率的に行えるかどうかはわかりませんが、ここに私の問題があります:

私は、ブログ投稿と各ブログ投稿へのすべての返信にタグを付けることができる、本質的にブログエンジンとは何かを書いています。

つまり、「スタック」というタグの付いたブログ投稿と、「オーバーフロー」というタグの付いたその投稿への返信を作成できます。

今、ユーザーがアプリケーションの特別なページにアクセスしたときに最も人気のあるタグのリストを生成しようとしています。ブログ投稿の数が多い順に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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top