2016-06-04 11 views
0

Ich ging durch mehrere Themen hier darüber reden, aber ich konnte es nicht zum Laufen bringen. Für jeden "Topf" möchte ich die Anzahl der Zahlungen sowie die volle Provision (Summe aller Zahlungsprovisionen) in Bezug auf diesen Topf erhalten.Mysql Abfrage - Operand sollte 1 Spalte enthalten

SELECT id, id_user, 
     (SELECT IFNULL(SUM(amount), 0) AS collectedA, 
       IFNULL(SUM(commission), 0) AS commission 
       FROM payment AS pay WHERE pay.id_pot = pot.id AND pay.stat = 1) FROM pot 

Oben gibt mir den Fehler im Titel erwähnt. Ich verstehe, dass wir zwei Spalten mit dieser Art von Unterabfrage nicht auswählen können. Ich habe versucht, durch LEFT OUTER JOIN zu gehen, konnte es aber nicht zur Arbeit bringen.

SELECT id, id_user, 
     IFNULL(SUM(payment.amount), 0) AS collectedA, 
     IFNULL(SUM(payment.commission), 0) AS commission 
FROM pot LEFT OUTER JOIN payment ON payment.id_pot = pot.id AND payment.stat = 1 

Aber das gibt mir seltsame Ergebnisse ...

Antwort

1

Ihre LEFT JOIN ist korrekt, aber Sie haben vergessen, GROUP BY zu verwenden.

SELECT pot.id, id_user, 
     IFNULL(SUM(payment.amount), 0) AS collectedA, 
     IFNULL(SUM(payment.commission), 0) AS commission 
FROM pot 
LEFT OUTER JOIN payment ON payment.id_pot = pot.id AND payment.stat = 1 
GROUP BY pot.id 

Wenn Sie eine WHERE Klausel müssen nur einige der Töpfe wählen, setzen Sie es nach LEFT OUTER JOIN.

SELECT pot.id, id_user, 
     IFNULL(SUM(payment.amount), 0) AS collectedA, 
     IFNULL(SUM(payment.commission), 0) AS commission 
FROM pot 
LEFT OUTER JOIN payment ON payment.id_pot = pot.id AND payment.stat = 1 
WHERE ... 
GROUP BY pot.id 
+0

Danke Barma r. Wie viel besser ist das im Vergleich zu Giorgos 'Lösung? Ich muss sagen, ich bin ein bisschen besorgt darüber, zu viel für nur einen kleinen Teil der Liste zu berechnen. – gotye

+1

Wenn Sie eine 'WHERE'-Klausel haben, sollten Sie die Berechnung der Beträge für nicht zusammenhängende Zahlungen vermeiden. – Barmar

2

Sie müssen LEFT JOIN zu einem bereits aggregiert abgeleitete Tabelle, wie folgt aus:

SELECT id, id_user, collectedA, commission 
FROM pot 
LEFT JOIN (
    SELECT id_pot, 
      IFNULL(SUM(amount), 0) AS collectedA, 
      IFNULL(SUM(commission), 0) AS commission 
    FROM payment 
    WHERE stat = 1 
    GROUP BY id_pot 
) AS pay pay.id_pot = pot.id 

Die GROUP BY in der Unterabfrage garantiert durchgeführt dass Sie erhalten genau einen Datensatz pro pot.id.

+0

Dank Giorgos.Dies würde alle Töpfe auswählen.Wenn ich eine Where-Klausel hätte, um nur einen Teil von ihnen auszuwählen, wo würde Ich lege es, um es effizient zu machen? Auf beiden Unterabfragen? Ich möchte verhindern, dass es die Summe für jeden einzelnen Topf berechnet, wenn ich nur ein paar wenige brauche ... Jede Hilfe geschätzt. – gotye

+0

Ok. Macht Sinn. Sehr geschätzt. – gotye

1

Die effizienteste Methode zwei Unterabfragen sein kann, vor allem, wenn Sie Filter auf dem pot Tisch haben wollen:

select pot.id, pot.id_user, 
     (select sum(pay.amount) 
     from payment pay 
     where pay.id_pot = pot.id and pay.stat = 1 
     ) as amount, 
     (select sum(pay.commission) 
     from payment pay 
     where pay.id_pot = pot.id and pay.stat = 1 
     ) as commission 
from pot; 

Damit dies effizient arbeiten müssen Sie auf payment(id_pot, stat, amount, commission) einen Index. Dies ist ein abdeckender Index für beide Abfragen. Dies bedeutet, dass alle Spalten im Index enthalten sind.

Es mag widersprüchlich erscheinen, dass dies schneller ist, aber keine globale Aggregation erfordert - die gesamte Aggregation kann mithilfe von Indexscans gehandhabt werden. Das ist oft schneller.Zusätzliche Filter auf potreduzieren den Arbeitsbedarf auf der payment Tabelle.