Saya sarankan kita membangun kueri secara bertahap, langkah demi langkah. Verifikasi bahwa hasil kueri seperti yang kami harapkan di setiap langkah. Ketika sesuatu "tidak berfungsi", buat cadangan satu langkah.
Kami ingin mengembalikan tiga baris, satu untuk setiap baris di ___Segmentations
, untuk hotelid
specific tertentu
SELECT r.seg_id
, r.seg_text
FROM ___Segmentations r
WHERE r.seg_hotelid = :hotel_id
ORDER BY r.seg_id
Tambahkan gabungan luar ke __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
Tambahkan gabungan luar ke ___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
Jika itu baris yang kami minati, kami dapat mengerjakan agregasi.
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
Sekarang untuk mendapatkan agregasi dengan "total".
Pendekatan yang akan saya ambil adalah membuat "salinan" dari baris, menggunakan operasi CROSS JOIN. Kita dapat melakukan penggabungan ke baris yang dikembalikan oleh kueri pertama yang kita tulis, direferensikan sebagai tampilan sebaris. (Alias sebagai q
di bawah.)
Jika kita memiliki satu set baris yang lengkap, diulang untuk setiap seg_id/seg_text
(permintaan pertama yang kami tulis), kami dapat menggunakan agregasi bersyarat.
Kueri terakhir yang kami tulis (tepat di atas) adalah tampilan sebaris dalam kueri di bawah, alias sebagai c
.
SUM dari cnt_bookings
dari semua baris adalah totalnya.
Untuk jumlah individu, kami hanya dapat menyertakan baris yang memiliki seg_id
matching yang cocok , total dari subset tersebut.
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
Dalam SELECT
daftar, kita bisa melakukan pembagian untuk mendapatkan persentase:cnt_bookings * 100.0 / tot_bookings
misalnya
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
Ubah klausa ORDER BY untuk mengembalikan baris dalam urutan yang Anda inginkan
Hapus dari SELECT
daftar ekspresi yang mengembalikan tot_bookings
dan tot_billable
.
EDIT
Saya pikir saya melewatkan kriteria tanggal. Kita bisa membuat outer join menjadi inner join, dan mengganti CROSS JOIN dengan LEFT JOIN. Kami memiliki potensi untuk mengembalikan nilai NULL untuk cnt_bookings
dan cnt_billable
, kita dapat membungkusnya dalam fungsi IFNULL() atau COALESCE() untuk mengganti NULL dengan nol.
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