Eine schwierige SQL-Abfrage: tag Popularität für Modelle mit komplexen Assoziationen

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

  •  05-07-2019
  •  | 
  •  

Frage

Ich bin nicht einmal sicher, dass dies möglich ist, effizient zu tun, aber hier ist mein Problem:

Ich schreibe, was im Wesentlichen aus einer Blog-Engine, wo eine Blog-Post und alle Antworten auf jeden Blog-Eintrag markiert sind.

Also, ich könnte eine Blog-Post habe "Stack" markiert, und eine Antwort auf diese Stelle markiert "Überlauf".

Im Moment versuche ich, eine Liste der beliebtesten Tags zu erzeugen, wenn ein Benutzer eine spezielle Seite in meiner Anwendung trifft. Es sollte zurückgeben, nicht nur die n beliebtesten Tags nach der Anzahl der Blog-Posts absteigend, sondern auch die Anzahl von Blog-Posts mit jedem Tag zugeordnet, auch wenn eine Antwort in diesem Beitrag nicht aber die Post selbst mit diesem Tag markiert .

Also, wenn Blogpost A mit „foo“ und einer Antwort in Blogpost B markiert mit „foo“ markiert, die beliebten Tag Zusammenfassung, die als zwei Blog-Beiträge insgesamt zählen, wenn auch Blogpost B technisch nicht getaggt .

Hier ist eine Beschreibung der Tabellen / Felder, die relevant sein könnten:

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

Es gibt einige Normalisierungs in Markierungen aus Gründen der Bequemlichkeit. Wenn jemand Blogpost-Tags, füllt es im blog_post_id Feld und blog_comment_id bleibt NULL. Wenn jemand einen Kommentar zu einem Post-Tags, füllt es sowohl in blog_post_id und blog_comment_id.

Gibt es eine Möglichkeit eine sortierte Liste der beliebtesten Tags in einer oder mehreren SQL-Abfragen zurückzukehren? Ich denke, ich brauche vielleicht nur ein rechen teuer Skript die zwischengespeicherte Ausgabe statt Ausführen dieses jemand jedes Mal die Seite alle paar Minuten auf einem Cron-Job ausführen und machen Treffer ...

Danke!

War es hilfreich?

Lösung

Bisher sehe ich nichts kompliziert in Ihrer Anfrage:

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

Wenn Sie nur „betroffene Blog-Posts“ zählen, ich denke, das ist die Art und Weise:

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

Andere Tipps

ich offensichtlich etwas fehlt möglicherweise aber da Sie haben: „Wenn jemand einen Kommentar zu einem Post-Tags, füllt es sowohl in blog_post_id und blog_comment_id“, sollte die folgende SQL den Trick. Ich gehe davon aus, dass hier Tags.name hier einzigartig sein wird.

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

Ich hoffe, das ist das, was Sie suchen.

Ich habe nicht versucht, aber was ist so etwas wie dies:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top