2010-03-12 15 views
39

Ich suche Hilfe bei der Verwendung sum() in meiner SQL-Abfrage:MYSQL sum() für verschiedene Reihen

SELECT links.id, 
     count(DISTINCT stats.id) as clicks, 
     count(DISTINCT conversions.id) as conversions, 
     sum(conversions.value) as conversion_value 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
GROUP BY links.id 
ORDER BY links.created desc; 

Ich benutze DISTINCT, weil ich „von der Gruppe“ mache und dies sorgt für die gleiche Zeile wird nicht mehr als einmal gezählt.

Das Problem ist, dass SUM (conversions.value) zählt den „Wert“ für jede Zeile mehr als einmal (aufgrund der Gruppe von)

ich im Grunde SUM(conversions.value) für jede einzelne conversions.id tun will.

Ist das möglich?

+1

Das Posten der vollständigen Abfrage wäre hilfreich. Wie duplizierst du Werte mit einer GROUP BY? – Matthew

+0

Machst du ein Join? Sie sollten Ihre Anfrage posten. Es gibt ein paar Optionen, die Sie je nach Abfrage verwenden können. –

+0

Ich aktualisierte meine Frage mit der vollständigen Abfrage – makeee

Antwort

58

ich falsch sein kann, aber von dem, was ich

  • conversions.id verstehen, ist die Primärschlüssel Ihrer Tabelle Conversions
  • stats.id ist der Primärschlüssel Ihrer Tabelle Statistiken

So für jede conversions.id haben Sie höchstens ein links.id beeinflusst.

Sie Anfrage ist ein bisschen wie das Kreuzprodukt von 2 Sets tun:

[clicks] 
SELECT * 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 

[conversions] 
SELECT * 
FROM links 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 

und für jeden Link, erhalten Sie sizeof ([Klicks]) x sizeof ([Umbauten]) Linien

wie Sie die Anzahl der eindeutigen Umwandlungen in Ihrer Anfrage darauf hingewiesen, kann über ein

count(distinct conversions.id) = sizeof([conversions]) 

verschieden diese verwalten die alle zu entfernen, erhalten wird [Klicks] Linien im kartesischen Produkt

aber deutlich

sum(conversions.value) = sum([conversions].value) * sizeof([clicks]) 

In Ihrem Fall, da

count(*) = sizeof([clicks]) x sizeof([conversions]) 
count(*) = sizeof([clicks]) x count(distinct conversions.id) 

Sie

sizeof([clicks]) = count(*)/count(distinct conversions.id) 

haben, so würde ich Ihre Anfrage testen mit

SELECT links.id, 
    count(DISTINCT stats.id) as clicks, 
    count(DISTINCT conversions.id) as conversions, 
    sum(conversions.value)*count(DISTINCT conversions.id)/count(*) as conversion_value 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
GROUP BY links.id 
ORDER BY links.created desc; 

Halten Sie mich auf dem Laufenden! Jerome

+5

Sie sind ein Genie! Ich dachte fast, es gäbe keine Lösung, bis ich deine Antwort gefunden habe. –

+1

Großartig, diese Lösung ist perfekt und ziemlich universell, wenn Sie nicht mit abhängigen Unterabfragen Lösungen umgehen wollen, die für große Datenmengen nicht akzeptabel sind. –

+0

Jeromes Lösung ist eigentlich falsch und kann falsche Ergebnisse produzieren !! Siehe meine Antwort unten. –

3

Ich benutze eine Unterabfrage, um dies zu tun. Es beseitigt die Probleme mit der Gruppierung. Also die Abfrage würde so etwas wie:

SELECT COUNT(DISTINCT conversions.id) 
... 
    (SELECT SUM(conversions.value) FROM ....) AS Vals 
+0

Aktualisierte Frage mit meiner vollständigen Abfrage. Ich bin mir nicht sicher, wie ich eine Unterabfrage in das, was ich habe, integrieren würde und wie es die Leistung beeinflussen würde. – makeee

+0

Unterabfragen beeinträchtigen normalerweise die Leistung negativ. Um die Auswirkungen zu minimieren, stellen Sie sicher, dass jede Unterabfrage auf einen Index wirkt. – Dave

4

Verwenden Sie die folgende Abfrage:

SELECT links.id 
    , (
    SELECT COUNT(*) 
    FROM stats 
    WHERE links.id = stats.parent_id 
) AS clicks 
    , conversions.conversions 
    , conversions.conversion_value 
FROM links 
LEFT JOIN (
    SELECT link_id 
    , COUNT(id) AS conversions 
    , SUM(conversions.value) AS conversion_value 
    FROM conversions 
    GROUP BY link_id 
) AS conversions ON links.id = conversions.link_id 
ORDER BY links.created DESC 
2

Wie wäre es etwa so:

select l.id, count(s.id) clicks, count(c.id) clicks, sum(c.value) conversion_value 
from (SELECT l.id id, l.created created, 
       s.id clicks, 
       c.id conversions, 
       max(c.value) conversion_value      
     FROM links l LEFT 
     JOIN stats s ON l.id = s.parent_id LEFT 
     JOIN conversions c ON l.id = c.link_id 
     GROUP BY l.id, l.created, s.id, c.id) t 
order by t.created 
6

Für eine Erklärung, warum Sie falsche Zahlen sahen, read this.

Ich denke, Jerome hat einen Griff auf, was Ihren Fehler verursacht. Die Abfrage von Bryson würde funktionieren, obwohl diese Unterabfrage in SELECT möglicherweise ineffizient ist.

+0

+1 für eine gute Referenz zur Verwendung von Unterabfragen. – kta

5

Jeromes Lösung ist eigentlich falsch und kann falsche Ergebnisse produzieren !!

sum(conversions.value)*count(DISTINCT conversions.id)/count(*) as conversion_value 

lassen Sie uns die folgende Tabelle für verschiedene IDs

conversions 
id value 
1 5 
1 5 
1 5 
2 2 
3 1 

die richtige Summe Wert annehmen würde 8. Jeromes Formel erzeugt:

sum(conversions.value) = 18 
count(distinct conversions.id) = 3 
count(*) = 5 
18*3/5 = 9.6 != 8 
+0

und die richtige Antwort ist ..? – kleopatra

+1

Angenommen, dass Konvertierungen.id ist ein eindeutiges Feld, es gibt keine Möglichkeit, dass ein JOIN 3 Zeilen mit conversions.id = 1 und nur 1 Zeile mit conversions.id = 2 erzeugt. Die Annahme, dass conversions.id eindeutig ist, ist implizit und sollte wahrscheinlich gemacht werden explizit, aber ansonsten ist die Formel solide. – Jonathan

1

Dies wird den Trick tun, nur Teilen Sie die Summe mit der Anzahl der Konversations-IDs, die doppelt vorhanden sind.

SELECT a.id, 
     a.clicks, 
     SUM(a.conversion_value/a.conversions) AS conversion_value, 
     a.conversions 
FROM (SELECT links.id, 
     COUNT(DISTINCT stats.id) AS clicks, 
     COUNT(conversions.id) AS conversions, 
     SUM(conversions.value) AS conversion_value 
     FROM links 
     LEFT OUTER JOIN stats ON links.id = stats.parent_id 
     LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
     GROUP BY conversions.id,links.id 
     ORDER BY links.created DESC) AS a 
GROUP BY a.id