Ich schlage vor, dass wir die Abfrage Schritt für Schritt inkrementell erstellen. Überprüfen Sie bei jedem Schritt, ob die Abfrageergebnisse unseren Erwartungen entsprechen. Wenn etwas "nicht funktioniert", sichern Sie einen Schritt.
Wir möchten drei Zeilen zurückgeben, eine für jede Zeile in ___Segmentations
, für eine bestimmte hotelid
SELECT r.seg_id
, r.seg_text
FROM ___Segmentations r
WHERE r.seg_hotelid = :hotel_id
ORDER BY r.seg_id
Fügen Sie den äußeren Join zu __Bookings
hinzu
SELECT r.seg_id
, r.seg_text
, b.boo_id
FROM ___Segmentations r
LEFT
JOIN ___Bookings b
ON b.boo_segmentation = r.seg_id
WHERE r.seg_hotelid = :hotel_id
ORDER
BY r.seg_id
, b.boo_id
Fügen Sie den äußeren Join zu ___BillableDatas
hinzu
SELECT r.seg_id
, r.seg_text
, b.boo_id
, d.bil_id
FROM ___Segmentations r
LEFT
JOIN ___Bookings b
ON b.boo_segmentation = r.seg_id
LEFT
JOIN `___BillableDatas` d
ON d.bil_bookingid = b.boo_id
WHERE r.seg_hotelid = :hotel_id
ORDER
BY r.seg_id
, b.boo_id
, d.bil_id
Wenn das die Zeilen sind, an denen wir interessiert sind, können wir an der Aggregation arbeiten.
SELECT r.seg_id
, r.seg_text
, COUNT(DISTINCT b.boo_id) AS cnt_bookings
, COUNT(DISTINCT d.bil_id) AS cnt_billable
FROM ___Segmentations r
LEFT
JOIN ___Bookings b
ON b.boo_segmentation = r.seg_id
LEFT
JOIN `___BillableDatas` d
ON d.bil_bookingid = b.boo_id
WHERE r.seg_hotelid = :hotel_id
GROUP
BY r.seg_id
, r.seg_text
ORDER
BY r.seg_text
Jetzt erhalten Sie die Aggregation mit der "Gesamtsumme".
Der Ansatz, den ich wählen würde, wäre, "Kopien" der Zeilen mit einer CROSS JOIN-Operation zu erstellen. Wir können die Zeilen verknüpfen, die von der allerersten von uns geschriebenen Abfrage zurückgegeben wurden, die als Inline-Ansicht referenziert wird. (Alasname q
unten.)
Wenn wir einen vollständigen Satz von Zeilen haben, wird dies für jeden seg_id/seg_text
wiederholt (diese erste Abfrage, die wir geschrieben haben), können wir die bedingte Aggregation verwenden.
Die letzte Abfrage, die wir geschrieben haben (direkt oben), ist eine Inline-Ansicht in der Abfrage unten, mit dem Alias c
.
SUMME von cnt_bookings
aus allen Zeilen ist die Summe.
Für die einzelnen Zählungen können wir nur die Zeilen einbeziehen, die eine übereinstimmende seg_id
haben , insgesamt dieser Teilmenge.
SELECT q.seg_id
, q.seg_text
, SUM(IF(c.seg_id=q.seg_id,c.cnt_bookings,0)) AS cnt_bookings
, SUM(c.cnt_bookings) AS tot_bookings
, SUM(IF(c.seg_id=q.seg_id,c.cnt_billable,0)) AS cnt_billable
, SUM(c.cnt_billable) AS tot_billable
FROM ( SELECT t.seg_id
, t.seg_text
FROM ___Segmentations t
WHERE t.seg_hotelid = :hotel_id_1
ORDER BY t.seg_id
) q
CROSS
JOIN ( SELECT r.seg_id
, COUNT(DISTINCT b.boo_id) AS cnt_bookings
, COUNT(DISTINCT d.bil_id) AS cnt_billable
FROM ___Segmentations r
LEFT
JOIN ___Bookings b
ON b.boo_segmentation = r.seg_id
LEFT
JOIN `___BillableDatas` d
ON d.bil_bookingid = b.boo_id
WHERE r.seg_hotelid = :hotel_id
GROUP
BY r.seg_id
) c
GROUP
BY q.seg_id
, q.seg_text
ORDER
BY q.seg_text
Im SELECT
list, können wir dividieren, um den Prozentsatz zu erhalten:cnt_bookings * 100.0 / tot_bookings
z. B.
SELECT q.seg_id
, q.seg_text
, SUM(IF(c.seg_id=q.seg_id,c.cnt_bookings,0)) AS cnt_bookings
, SUM(c.cnt_bookings) AS tot_bookings
, SUM(IF(c.seg_id=q.seg_id,c.cnt_bookings,0))
* 100.0 / SUM(c.cnt_bookings) AS pct_bookings
, SUM(IF(c.seg_id=q.seg_id,c.cnt_billable,0)) AS cnt_billable
, SUM(c.cnt_billable) AS tot_billable
, SUM(IF(c.seg_id=q.seg_id,c.cnt_billable,0))
* 100.0 / SUM(c.cnt_billable) AS pct_billable
Ändern Sie die ORDER BY-Klausel, um die Zeilen in der gewünschten Reihenfolge zurückzugeben
Aus SELECT
entfernen listen Sie die Ausdrücke auf, die tot_bookings
zurückgeben und tot_billable
.
BEARBEITEN
Ich glaube, ich habe die Datumskriterien übersehen. Wir können die äußeren Joins in innere Joins umwandeln und den CROSS JOIN durch einen LEFT JOIN ersetzen. Wir haben die Möglichkeit, NULL-Werte für cnt_bookings
zurückzugeben und cnt_billable
, können wir diese in die Funktion IFNULL() oder COALESCE() einschließen, um NULL durch Null zu ersetzen.
SELECT q.seg_id
, q.seg_text
, SUM(IF(c.seg_id=q.seg_id,c.cnt_bookings,0)) AS cnt_bookings
, SUM(c.cnt_bookings) AS tot_bookings
, SUM(IF(c.seg_id=q.seg_id,c.cnt_bookings,0))
* 100.0 / SUM(c.cnt_bookings) AS pct_bookings
, SUM(IF(c.seg_id=q.seg_id,c.cnt_billable,0)) AS cnt_billable
, SUM(c.cnt_billable) AS tot_billable
, SUM(IF(c.seg_id=q.seg_id,c.cnt_billable,0))
* 100.0 / SUM(c.cnt_billable) AS pct_billable
FROM ( SELECT t.seg_id
, t.seg_text
FROM ___Segmentations t
WHERE t.seg_hotelid = :hotel_id_1
ORDER BY t.seg_id
) q
LEFT
JOIN ( SELECT r.seg_id
, COUNT(DISTINCT b.boo_id) AS cnt_bookings
, COUNT(DISTINCT d.bil_id) AS cnt_billable
FROM ___Segmentations r
JOIN ___Bookings b
ON b.boo_segmentation = r.seg_id
JOIN `___BillableDatas` d
ON d.bil_bookingid = b.boo_id
AND d.bil_date BETWEEN '2017-02-21' AND '2017-02-28'
WHERE r.seg_hotelid = :hotel_id
GROUP
BY r.seg_id
) c
ON 1=1
GROUP
BY q.seg_id
, q.seg_text
ORDER
BY q.seg_text