Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Zwróć ranking z wielu tabel za pomocą mySQL

Proponuję budować zapytanie przyrostowo, krok po kroku. Sprawdź, czy wyniki zapytania są zgodne z oczekiwaniami na każdym kroku. Jeśli coś „nie działa”, wykonaj kopię zapasową kroku.

Chcemy zwrócić trzy wiersze, po jednym dla każdego wiersza w ___Segmentations , dla konkretnego hotelid

 SELECT r.seg_id
      , r.seg_text
   FROM ___Segmentations r
  WHERE r.seg_hotelid = :hotel_id
  ORDER BY r.seg_id

Dodaj złącze zewnętrzne do __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

Dodaj sprzężenie zewnętrzne do ___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

Jeśli to są wiersze, które nas interesują, możemy popracować nad agregacją.

 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

Teraz uzyskaj agregację z „suma”.

Podejście, które bym przyjął, polegałoby na wykonaniu „kopii” wierszy za pomocą operacji CROSS JOIN. Możemy wykonać sprzężenie z wierszami zwróconymi przez pierwsze zapytanie, które napisaliśmy, odwołując się do widoku wbudowanego. (Znaczony jako q poniżej.)

Jeśli mamy pełny zestaw wierszy, powtórzonych dla każdego seg_id/seg_text (pierwsze zapytanie, które napisaliśmy), możemy użyć agregacji warunkowej.

To ostatnie zapytanie, które napisaliśmy (tuż powyżej) jest widokiem wbudowanym w poniższym zapytaniu, aliasem c .

SUMA cnt_bookings ze wszystkich rzędów jest sumą.

W przypadku indywidualnych zliczeń możemy uwzględnić tylko wiersze, które mają pasujący seg_id , łącznie tego podzbioru.

 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

W SELECT listy, możemy dokonać podziału, aby uzyskać procent:cnt_bookings * 100.0 / tot_bookings

np.

 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

Zmodyfikuj klauzulę ORDER BY, aby zwracać wiersze w żądanej kolejności

Usuń z SELECT wymień wyrażenia, które zwracają tot_bookings i tot_billable .

EDYTUJ

Chyba przegapiłem kryterium daty. Możemy przekształcić zewnętrzne łączenia w wewnętrzne i zastąpić CROSS JOIN LEFT JOIN. Mamy potencjał do zwrócenia wartości NULL dla cnt_bookings i cnt_billable , możemy owinąć je w funkcję IFNULL() lub COALESCE(), aby zastąpić NULL zerem.

 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. ZAMÓW WEDŁUG DATY I GODZINY PRZED GRUPOWANIEM WEDŁUG nazwy w mysql

  2. Konwersja tabeli z MyISAM do INNODB

  3. Wybierz rekordy bieżącego miesiąca mysql z kolumny sygnatury czasowej

  4. Podejście Ajax do wypełniania drugiego dynamicznego menu rozwijanego na podstawie wyboru w pierwszym

  5. Homebrew MySQL 8.0.18 na macOS 10.15 Catalina nie będzie działać jako usługa