2009-08-09 15 views
3

Im Versuch, eine Tabelle mit mehreren Joins, eins für die Anzahl der Kommentare mit COUNT und eins, um den gesamten Wert der Abstimmung mit SUM wählen, ist das Problem, dass die beiden Joins einander beeinflussen, statt Angezeigt:mysql: multiple Join Problem

3 Stimmen 2 Kommentare

ich 3 * 2 = 6 Stimmen und 2 * 3 Kommentare

Dies ist die Abfrage ich verwende:

SELECT t.*, COUNT(c.id) as comments, COALESCE(SUM(v.vote), 0) as votes 
FROM (topics t) 
LEFT JOIN comments c ON c.topic_id = t.id 
LEFT JOIN votes v ON v.topic_id = t.id 
WHERE t.id = 9 

Antwort

3

Was Sie tun, ist eine SQL-Antipattern, die ich Goldberg-Maschine nennen. Warum wird das Problem dadurch erschwert, dass es in einer einzigen SQL-Abfrage ausgeführt wird?

Hier ist, wie ich würde wirklich dieses Problem lösen:

SELECT t.*, COUNT(c.id) as comments 
FROM topics t 
LEFT JOIN comments c ON c.topic_id = t.id 
WHERE t.id = 9; 

SELECT t.*, SUM(v.vote) as votes 
FROM topics t 
LEFT JOIN votes v ON v.topic_id = t.id 
WHERE t.id = 9; 

Wie Sie gefunden haben, diese beiden in einer Abfrageergebnisse in einem cartesianischen Produkt kombiniert. Es kann clevere und subtile Wege geben, um es zu zwingen, Ihnen die richtige Antwort in einer Abfrage zu geben, aber was passiert, wenn Sie eine dritte Statistik benötigen? Es ist viel einfacher, es in zwei Abfragen zu tun.

+0

Führt das nicht zu mehr Lade- und mehr Arbeit für die Datenbank oder ist es für die Datenbank schwieriger, mit mehreren Joins zu arbeiten und sie dann zu trennen? – Dennis

+0

Die meisten Datenbanken verfügen über internes Caching für Daten- und Indexseiten. Daher ist dies möglicherweise kein Problem. Auch die Arbeit, die notwendig ist, um das kartesische Produkt zu kompensieren, kann schlechter sein. Teilweise kommt es auf Ihr spezifisches System und Ihre Daten an, so dass die genaueste Antwort das Testen in * Ihrer * Umgebung erfordert. –

0
SELECT t.*, COUNT(DISTINCT c.id) as comments, COALESCE(SUM(v.vote), 0) as votes 
FROM (topics t) 
LEFT JOIN comments c ON c.topic_id = t.id 
LEFT JOIN votes v ON v.topic_id = t.id 
WHERE t.id = 9 
+0

Ich bekomme jetzt die korrekte Anzahl von Kommentaren, aber ich bekomme immer noch eine falsche Summe der Stimmen, ich habe versucht, DISTINCT zu v.vote hinzuzufügen, aber das hat nicht funktioniert. – Dennis

1
SELECT t.*, COUNT(c.id) as comments, COALESCE(SUM(v.vote), 0) as votes 
FROM (topics t) 
LEFT JOIN comments c ON c.topic_id = t.id 
LEFT JOIN votes v ON v.topic_id = t.id 
WHERE t.id = 9 
GROUP BY t.id 

oder vielleicht

SELECT `topics`.*, 
(
    SELECT COUNT(*) 
    FROM `comments` 
    WHERE `topic_id` = `topics`.`id` 
) AS `num_comments`, 
(
    SELECT IFNULL(SUM(`vote`), 0) 
    FROM `votes` 
    WHERE `topic_id` = `topics`.`id` 
) AS `vote_total` 
FROM `topics` 
WHERE `id` = 9