2012-04-05 5 views
2

Ich habe zwei Tabellen, Blogs und Beiträge, mit der erwarteten Beziehung zwischen ihnen. Beiträge können veröffentlicht oder verfasst werden. Ich möchte alle Blogs mit den Zählungen für veröffentlichte Beiträge und Entwürfe auswählen. Wie kann ich es tun?Wie erhalten Sie Zählungen von verschiedenen Joins zur selben Tabelle in SQL?

Ich habe versucht, diese Anfrage:

SELECT blogs.*, 
     COUNT(published_posts.*) AS published_post_count, 
     COUNT(draft_posts.*) AS draft_post_count 
FROM blogs 
JOIN posts AS published_posts ON published_posts.blog_id=blogs.id AND 
           published_posts.state = "published" 
JOIN posts AS draft_posts ON draft_posts.blog_id=blogs.id AND 
          draft_posts.state = "draft" 
GROUP BY blogs.id 

aber ich am Ende für beide published_post_count und draft_post_count mit der gleichen Anzahl und für beide falsch sind.

Dann habe ich verzweifelt und Trie:

SELECT blogs.*, 
     COUNT(published_posts.*) AS published_post_count, 
     COUNT(draft_posts.*) AS draft_post_count 
FROM blogs 
JOIN (SELECT * FROM posts WHERE posts.state="published") AS published_posts 
    ON published_posts.blog_id=blogs.id 
JOIN (SELECT * FROM posts WHERE posts.state="draft") AS draft_posts 
    ON draft_posts.blog_id=blogs.id 
GROUP BY blogs.id 

aber in beiden Fällen hatte ich die gleichen falschen Ergebnissen.

Was ist der richtige Weg, dies zu tun?

Danke.

Antwort

4

Wenn Sie nur an der COUNT interessiert sind und Sie sind auch JOIN in den Tabellen. Es muss also einen oder mehrere post geben, die published und eine oder mehrere draft sind. Vielleicht dies wird Ihnen helfen:

SELECT blogs.*, 
     (
      SELECT COUNT(*) 
      FROM posts 
      WHERE posts.blog_id=blogs.id 
      AND posts.state = "published" 
     ) AS published_post_count, 
     (
      SELECT COUNT(*) 
      FROM posts 
      WHERE posts.blog_id=blogs.id 
      AND posts.state = "draft" 
     ) AS draft_post_count, 
FROM blogs 
+0

Dies funktioniert. Aber ist das nicht das Gleiche wie viele Abfragen? (N + 1) – Pablo

+0

Nein. Da es sich um Unterabfragen handelt, die von den äußeren Abfragen abhängen. Und COUNT (*) ist nicht so ineffektiv. – Arion

+0

Wenn Sie mit der Antwort zufrieden sind, können Sie die Antwort akzeptieren. – Arion

1

Versuchen:

GROUP BY blogs.id,published_posts.[theKeyOfThisTable],draft_posts.[theKeyOfThisTable] 

wie Sie die Spalten der „select“ an Ihrer „Gruppe von“ -Klausel

1

Sie könnten zählen verschiedene Zustände enthalten sollte und beitreten zurück zu blogs:

SELECT blogs.*, p.published_post_count, p.draft_post_count 
FROM blogs 
JOIN 
(
    SELECT posts.blog_id, 
     SUM(case when posts.state = 'published' then 1 end) 
      AS published_post_count, 
     SUM(case when posts.state = 'draft' then 1 end) 
      AS draft_post_count 
    FROM posts 
    GROUP BY blog_id 
) p 
ON p.blog_id=blogs.id 
+0

Auf großen Tabellen würde ich erwarten, dass dies viel schneller ist als der Ansatz der korrelierten Unterabfragen, obwohl es sich lohnen würde beide zu testen, um dies zu bestätigen. Ich war überrascht, dass die CASE-Prädikate keine "else 0" -Klauseln hatten, aber ein schneller Test legt nahe, dass es ohne sie gut läuft. – kgrittn