Je suggère que nous construisions la requête progressivement, étape par étape. Vérifiez que les résultats de la requête sont conformes à nos attentes à chaque étape. Lorsque quelque chose "ne fonctionne pas", sauvegardez une étape.
Nous voulons renvoyer trois lignes, une pour chaque ligne dans ___Segmentations
, pour un hotelid
spécifique
SELECT r.seg_id
, r.seg_text
FROM ___Segmentations r
WHERE r.seg_hotelid = :hotel_id
ORDER BY r.seg_id
Ajouter la jointure externe à __Bookings
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
Ajoutez la jointure externe à ___BillableDatas
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
Si ce sont les lignes qui nous intéressent, nous pouvons travailler sur l'agrégation.
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
Maintenant, pour obtenir l'agrégation avec le "total".
L'approche que j'adopterais serait de faire des "copies" des lignes, en utilisant une opération CROSS JOIN. Nous pouvons faire la jointure aux lignes renvoyées par la toute première requête que nous avons écrite, référencée en tant que vue en ligne. (Alias comme q
ci-dessous.)
Si nous avons un ensemble complet de lignes, répété pour chaque seg_id/seg_text
(cette première requête que nous avons écrite), nous pouvons utiliser l'agrégation conditionnelle.
Cette dernière requête que nous avons écrite (juste au-dessus) est une vue en ligne dans la requête ci-dessous, alias c
.
SOMME des cnt_bookings
de toutes les lignes est le total.
Pour les décomptes individuels, nous ne pouvons inclure que les lignes qui ont un seg_id
correspondant , un total de ce sous-ensemble.
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
Dans le SELECT
list, on peut faire la division pour obtenir le pourcentage :cnt_bookings * 100.0 / tot_bookings
ex.
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
Modifiez la clause ORDER BY pour renvoyer les lignes dans l'ordre que vous souhaitez
Supprimer du SELECT
lister les expressions qui renvoient tot_bookings
et tot_billable
.
MODIFIER
Je pense que j'ai raté les critères de date. Nous pouvons transformer les jointures externes en jointures internes et remplacer le CROSS JOIN par un LEFT JOIN. Nous avons la possibilité de renvoyer des valeurs NULL pour cnt_bookings
et cnt_billable
, nous pouvons les envelopper dans la fonction IFNULL() ou COALESCE() pour remplacer NULL par zéro.
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