Une requête SQL difficile: la popularité des balises pour les modèles avec des associations complexes

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

  •  05-07-2019
  •  | 
  •  

Question

Je ne suis même pas sûr que ce soit possible, mais voici mon problème:

J'écris ce qui est essentiellement un moteur de blog dans lequel un article de blog et toutes les réponses à chaque article de blog peuvent être étiquetés.

Je pourrais donc avoir un article de blog étiqueté "pile" et une réponse à cet article étiqueté "débordement".

Pour le moment, j'essaie de générer une liste des balises les plus populaires lorsqu'un utilisateur clique sur une page spéciale de mon application. Il doit renvoyer non seulement les n balises les plus populaires classées par nombre décroissant de publications sur le blog, mais également le nombre de publications associées à chaque balise, même si une réponse dans cette publication mais pas dans la publication elle-même est marquée avec cette balise .

Ainsi, si BlogPost A est étiqueté avec "foo", et qu'une réponse dans BlogPost B est étiquetée avec "foo", le résumé de balise populaire doit compter cela comme deux articles de blog au total, même si BlogPost B n'est pas étiquetés techniquement.

Voici une description des tables / champs pouvant être pertinents:

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

Il existe une certaine dénormalisation dans Taggings pour des raisons de commodité. Si quelqu'un taggue BlogPost, il renseigne le champ blog_post_id et blog_comment_id reste NULL. Si quelqu'un associe un commentaire à une publication, il remplit blog_post_id et blog_comment_id.

Existe-t-il un moyen de renvoyer une liste triée des balises les plus populaires dans une ou plusieurs requêtes SQL? Je pense que je devrais peut-être simplement exécuter un script coûteux toutes les quelques minutes sur un travail cron et afficher la sortie en cache au lieu de l'exécuter à chaque fois que quelqu'un clique sur la page ...

Merci!

Était-ce utile?

La solution

Jusqu'à présent, je ne vois rien de compliqué dans votre demande:

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

Si vous souhaitez compter les "posts de blog concernés" " seulement, je pense que c'est comme ça:

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

Autres conseils

Il se peut que quelque chose d’évident me manque, mais comme vous avez " si quelqu'un associe un commentaire à un message, il remplit blog_post_id et blog_comment_id " ;, le code SQL suivant devrait faire l'affaire. Je suppose ici que Tags.name sera unique ici.

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

J'espère que c'est ce que vous cherchez.

Je n'ai pas essayé, mais qu'en est-il de quelque chose comme ça?:

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top