Предлагам да изградим заявката постепенно, стъпка по стъпка. Проверете дали резултатите от заявката са такива, каквито очакваме на всяка стъпка. Когато нещо "не работи", архивирайте стъпка.
Искаме да върнем три реда, по един за всеки ред в ___Segmentations
, за конкретен hotelid
SELECT r.seg_id
, r.seg_text
FROM ___Segmentations r
WHERE r.seg_hotelid = :hotel_id
ORDER BY r.seg_id
Добавете външното присъединяване към __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
Добавете външното присъединяване към ___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
Ако това са редовете, които ни интересуват, можем да работим върху агрегирането.
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
Сега, за да получите агрегирането с "общо".
Подходът, който бих възприел, би бил да направя "копия" на редовете, използвайки операция CROSS JOIN. Можем да извършим присъединяването към редовете, върнати от първата заявка, която написахме, посочена като вграден изглед. (Псевдоним като q
по-долу.)
Ако имаме пълен набор от редове, повтарящи се за всеки seg_id/seg_text
(тази първа заявка, която написахме), можем да използваме условно агрегиране.
Тази последна заявка, която написахме (точно по-горе), е вграден изглед в заявката по-долу, с псевдоним като c
.
SUM от cnt_bookings
от всички редове е общата сума.
За отделните преброявания можем да включим само редовете, които имат съответстващ seg_id
, общо това подмножество.
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
В SELECT
списък, можем да направим разделянето, за да получим процента:cnt_bookings * 100.0 / tot_bookings
напр.
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
Променете клаузата ORDER BY, за да върнете редовете в реда, който искате
Премахнете от SELECT
избройте изразите, които връщат tot_bookings
и tot_billable
.
РЕДАКТИРАНЕ
Мисля, че пропуснах критериите за дата. Можем да направим външните съединения във вътрешни съединения и да заменим CROSS JOIN с LEFT JOIN. Имаме потенциал да върнем NULL стойности за cnt_bookings
и cnt_billable
, можем да ги обвием във функцията IFNULL() или COALESCE(), за да заменим NULL с нула.
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