Tôi đề nghị chúng ta xây dựng truy vấn tăng dần, từng bước. Xác minh rằng kết quả truy vấn như chúng tôi mong đợi ở mỗi bước. Khi một cái gì đó "không hoạt động", hãy sao lưu một bước.
Chúng tôi muốn trả về ba hàng, mỗi hàng một trong ___Segmentations
, cho một hotelid
cụ thể
SELECT r.seg_id
, r.seg_text
FROM ___Segmentations r
WHERE r.seg_hotelid = :hotel_id
ORDER BY r.seg_id
Thêm liên kết bên ngoài vào __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
Thêm liên kết bên ngoài vào ___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
Nếu đó là những hàng mà chúng tôi quan tâm, chúng tôi có thể làm việc trên việc tổng hợp.
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
Bây giờ để có được tổng hợp với "tổng số".
Cách tiếp cận mà tôi sẽ thực hiện là tạo "bản sao" của các hàng, sử dụng thao tác CROSS JOIN. Chúng ta có thể thực hiện việc nối các hàng được trả về bởi truy vấn đầu tiên mà chúng ta đã viết, được tham chiếu dưới dạng một dạng xem nội tuyến. (Bí danh là q
bên dưới.)
Nếu chúng ta có một tập hợp các hàng hoàn chỉnh, được lặp lại cho mỗi seg_id/seg_text
(truy vấn đầu tiên mà chúng tôi đã viết), chúng tôi có thể sử dụng kết hợp có điều kiện.
Truy vấn cuối cùng mà chúng tôi đã viết (ngay ở trên) là một dạng xem nội tuyến trong truy vấn bên dưới, có bí danh là c
.
SUM trong số cnt_bookings
từ tất cả các hàng là tổng số.
Đối với các số lượng riêng lẻ, chúng tôi chỉ có thể bao gồm các hàng có seg_id
phù hợp , tổng số của tập hợp con đó.
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
Trong SELECT
danh sách, chúng ta có thể thực hiện phép chia để lấy phần trăm:cnt_bookings * 100.0 / tot_bookings
ví dụ:
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
Sửa đổi mệnh đề ORDER BY để trả về các hàng theo thứ tự bạn muốn
Xóa khỏi SELECT
liệt kê các biểu thức trả về tot_bookings
và tot_billable
.
CHỈNH SỬA
Tôi nghĩ rằng tôi đã bỏ lỡ tiêu chí ngày. Chúng ta có thể biến các phép nối bên ngoài thành các phép nối bên trong và thay thế CROSS JOIN bằng LEFT JOIN. Chúng tôi có khả năng trả về giá trị NULL cho cnt_bookings
và cnt_billable
, chúng ta có thể bọc chúng trong hàm IFNULL () hoặc COALESCE () để thay thế NULL bằng không.
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