2016-04-11 9 views
0

Ich stelle mir vor, ich vermisse etwas ziemlich offensichtlich hier.MySQL Vergleich Ergebnis in WHERE-Klausel

Ich versuche, eine Liste von "Buchungen" anzuzeigen, bei denen die Gesamtkosten höher sind als die gesamten Zahlungen für die Buchung. Die Gebühren und Zahlungen werden in separaten Tabellen gespeichert, die mit Fremdschlüsseln verknüpft sind.

Meine Anfrage so weit ist:

SELECT `booking`.`id`, 
SUM(`booking_charge`.`amount`) AS `charges`, 
SUM(`booking_payment`.`amount`) AS `payments` 

FROM `booking` 
LEFT JOIN `booking_charge` ON `booking`.`id` = `booking_charge`.`booking_id` 
LEFT JOIN `booking_payment` ON `booking`.`id` = `booking_payment`.`booking_id` 

WHERE `charges` > `payments` ///this is the incorrect part 

GROUP BY `booking`.`id` 

Meine Tabellen wie folgt aussehen:

Booking (ID) 

Booking_Charge (Booking_ID, Amount) 

Booking_Payment (Booking_ID, Amount) 

MySQL scheint nicht die Ergebnisse aus diesen beiden Tabellen mögen zu vergleichen, Ich bin mir nicht sicher, was ich vermisse, aber ich bin mir sicher, dass es möglich ist.

+0

keine Fehler ?, Namen sind nicht mehrdeutig? – Saikios

+0

Das dachte ich auch, deshalb habe ich die Tabellennamen 'booking_charge' ... und' booking_payment' vor die 'Menge' gesetzt. Aber das scheint nicht in beide Richtungen zu helfen. SQL beschwert sich über Unbekannte Spalte 'Gebühren' in 'Where-Klausel' ... was wahrscheinlich ist, weil 'Gebühren' als eine Spalte während der Abfrage selbst erstellt wird. –

+0

versuchen Sie, die 'WHERE Gebühren> Zahlungen zu entfernen und fügen Sie' HAVING Gebühren> Zahlungen am Ende. –

Antwort

1

Eines der Probleme mit der Abfrage der Kreuzung zwischen Reihen von `_charge` und Reihen von` _payment` verbinden ist. Es ist eine halb-kartesische Verbindung. Jede von '_charge' zurückgegebene Zeile wird mit jeder Zeile verglichen, die von `_payment` für eine gegebene 'booking_id` zurückgegeben wird.

Betrachten wir ein einfaches Beispiel:

ist eine einzelne Zeile in `_charge` für $ 40 für eine bestimmte` booking_id` setzen lassen.

Und setzen Sie zwei Zeilen in `_payment` für jeweils $ 20, für die gleiche` booking_id`.

Die Abfrage würde Gesamtkosten von $ 80 zurückgeben. (= 2 x $ 40). Wenn stattdessen fünf Zeilen in \ '_ payment \' für jeweils $ 10 vorhanden wären, würde die Abfrage eine Gesamtgebühr von $ 200 (= 5 x $ 40) liefern.

Es gibt ein paar Ansätze, um dieses Problem anzugehen. Ein Ansatz besteht darin, die Aggregation in einer Inline-Ansicht durchzuführen und die Summe der Gebühren und Zahlungen als einzelne Zeile für jede Buchungs-ID zurückzugeben und diese dann der Buchungstabelle hinzuzufügen. Mit höchstens einer Zeile pro Buchungs-ID verursacht die Querverknüpfung nicht das Problem der "Duplizierung" von Zeilen aus der Gebühr und/oder der Zahlung.

Zum Beispiel:

SELECT b.id 
     , IFNULL(c.amt,0) AS charges 
     , IFNULL(p.amt,0) AS payments 
    FROM booking b 
    LEFT 
    JOIN (SELECT bc.booking_id 
       , SUM(bc.amount) AS amt 
      FROM booking_charge bc 
      GROUP BY bc.booking_id 
     ) c 
     ON c.booking_id = b.id 
    LEFT 
    JOIN (SELECT bp.booking_id 
       , SUM(bp.amount) AS amt 
      FROM booking_payment bp 
      GROUP BY bp.booking_id 
     ) p 
     ON p.booking_id = b.id 
    WHERE IFNULL(c.amt,0) > IFNULL(p.amt,0) 

Wir Verwendung einer HAVING-Klausel anstelle der WHERE machen könnte.


Die Abfrage in dieser Antwort ist nicht der einzige Weg, um das Ergebnis zu erhalten, noch ist es die effizienteste. Es gibt andere Abfrage-Muster, die ein äquivalentes Ergebnis zurückgeben.

+0

Vielen Dank für Ihre Hilfe zu diesem Thema. Ich bin Ihnen dankbar, dass Sie bemerkt haben, dass meine Tests die vorherige Ausgabe, die Sie erwähnt haben, nicht bemerkt haben. Ich habe es mit einer Reihe von Werten getestet und es scheint perfekt zu funktionieren. Danke noch einmal! –

1

versuchen HAVING statt WHERE wie diese

SELECT `booking`.`id`, 
SUM(`booking_charge`.`amount`) AS `charges`, 
SUM(`booking_payment`.`amount`) AS `payments` 
FROM `booking` 
LEFT JOIN `booking_charge` ON `booking`.`id` = `booking_charge`.`booking_id` 
LEFT JOIN `booking_payment` ON `booking`.`id` = `booking_payment`.`booking_id` 
GROUP BY `booking`.`id` 
HAVING `charges` > `payments` 
+0

Ich hatte keine Ahnung, dass es überhaupt existiert hat, hat perfekt funktioniert. Ich danke dir sehr! –

+0

Dies betrifft nicht das schädliche Problem der Kreuzverbindung (partielles kartesisches Produkt) zwischen _charge und _booking. Und es wird nicht auf den Fall eingegangen, wenn es keine Zeilen in _payment (mit einem Wert ungleich null) für eine gegebene booking_id gibt (diese Abfrage gibt diese Zeile nicht zurück). – spencer7593

+0

Dank @ Spencer7593 - Ich stieß auch tatsächlich auf dieses Problem, ich habe es in der Aufregung irgendwie vergessen. war meine Abhilfe verwenden, nur: IFNULL (SUM ('booking_charge'.'amount'), 0) AS' charges', IFNULL (SUM ('booking_payment'.'amount'), 0) AS' payments' , –