sql >> データベース >  >> RDS >> Mysql

mySQLを使用して複数のテーブルからランキングを返す

    クエリを段階的に作成することをお勧めします。クエリ結果が各ステップで期待どおりであることを確認します。何かが「機能しない」場合は、ステップをバックアップします。

    ___Segmentationsの各行に1つずつ、合計3つの行を返します。 、特定の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
    

    次に、「合計」を含む集計を取得します。

    私が採用するアプローチは、CROSSJOIN操作を使用して行の「コピー」を作成することです。インラインビューとして参照される、最初に作成したクエリによって返された行に結合を行うことができます。 (別名q 以下。)

    行の完全なセットがある場合は、seg_id/seg_textごとに繰り返されます (最初に作成したクエリ)、条件付き集計を使用できます。

    私たちが書いた最後のクエリ(すぐ上)は、以下のクエリのインラインビューであり、エイリアスはcです。 。

    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

    編集

    私は日付基準を逃したと思います。外部結合を内部結合にし、CROSSJOINをLEFTJOINに置き換えることができます。 cnt_bookingsに対してNULL値を返す可能性があります および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
    


    1. MYSQL現在までの営業日を追加

    2. TEXTまたはVARCHARを使用するのに適したDATATYPEはどれですか?

    3. hibernateを使用してSpringBootでMySQLストアドプロシージャを呼び出す方法は?

    4. GPS座標半径の計算