Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Kembalikan peringkat dari beberapa tabel dengan mySQL

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pencegahan Injeksi SQL PHP Dengan Operasi String

  2. Bagaimana saya bisa memeriksa jenis mesin MySQL untuk tabel tertentu?

  3. Format datetime tidak valid:1292 Nilai datetime salah

  4. Pilih * dari table1 yang tidak ada di table2 dengan kondisional

  5. Membandingkan tanggal di MySQL mengabaikan bagian waktu dari bidang DateTime