2014-09-05 123 views
1

我需要SQL查詢(MySQL)的「小」幫助。加入幾個表的SQL查詢(MySQL)

我有以下表格:

COURIERS表:

+------------+ 
    | COURIER_ID | 
    +------------+ 

DELIVERIES表:

+-------------+------------+------------+ 
    | DELIVERY_ID | COURIER_ID | START_DATE | 
    +-------------+------------+------------+ 

ORDERS表:

+----------+-------------+-------------+ 
    | ORDER_ID | DELIVERY_ID | FINISH_DATE | 
    +----------+-------------+-------------+ 

COORDINATES表:

+-------------+-----+-----+------+ 
    | DELIVERY_ID | LAT | LNG | DATE | 
    +-------------+-----+-----+------+ 

在真實的數據庫我在每個表中的列多,但在本例以上列是不夠的。

我需要什麼?

  • 一個SQL查詢,返回所有快遞公司的[COURIER_ID],他們最後 交運[DELIVERY_ID(基於最後START_DATE),該 交付的最後一個座標[LATLNG](基於最後DATE)和剩餘訂單數量(沒有FINISH_DATE的最後一次交貨的訂單總數)。

  • 快遞員可以沒有交付,在這種情況下,我想DELIVERY_ID = NULL ,LAT = NULL和結果LNG = NULL。

  • 一個投遞可以沒有座標,在這種情況下,我想要LAT = NULL 和LNG = NULL結果。

我能做什麼?

SELECT c.`COURIER_ID`, 
     d.`DELIVERY_ID`, 
     r.`LAT`, 
     r.`LNG`, 
    (SELECT COUNT(DISTINCT `ORDER_ID`) 
    FROM `ORDERS` 
    WHERE `DELIVERY_ID` = d.`DELIVERY_ID` 
    AND `FINISH_DATE` IS NULL) AS REMAINING_ORDERS 

FROM `COURIERS` AS c 
LEFT JOIN `DELIVERIES` AS d USING (`COURIER_ID`) 
LEFT JOIN `COORDINATES` AS r ON r.`DELIVERY_ID` = d.`DELIVERY_ID` 

WHERE (CASE WHEN 
     (SELECT MAX(`START_DATE`) 
      FROM `DELIVERIES` 
      WHERE `COURIER_ID` = c.`COURIER_ID`) IS NULL THEN d.`START_DATE` IS NULL ELSE d.`START_DATE` = 
     (SELECT MAX(`START_DATE`) 
      FROM `DELIVERIES` 
      WHERE `COURIER_ID` = c.`COURIER_ID`) END) 
    AND (CASE WHEN 
     (SELECT MAX(`DATE`) 
      FROM `COORDINATES` 
      WHERE `DELIVERY_ID` = d.`DELIVERY_ID`) IS NULL THEN r.`DATE` IS NULL ELSE r.`DATE` = 
     (SELECT MAX(`DATE`) 
      FROM `COORDINATES` 
      WHERE `DELIVERY_ID` = d.`DELIVERY_ID`) END) 
GROUP BY c.`COURIER_ID` 
ORDER BY d.`START_DATE` DESC 

的問題是,這個查詢是很慢的(5〜20秒)時,我有過5K COORDINATES,它有時不返回所有快遞員。

非常感謝你的解決方案。

+0

你還沒有真的問過一個問題。看起來您正在尋找優化您已經編寫的查詢的幫助。你應該澄清你的問題。如果你正在尋求幫助來優化查詢,你應該指定你想要的結果。 – axiopisty 2014-09-05 04:27:35

+0

我相信這是一個問題,因爲這個查詢不像我需要的那樣工作,無論它的性能如何。性能只是其中一個問題。謝謝。 – 2014-09-05 04:31:27

+0

您必須在單個數據庫查詢中返回所有結果嗎?或者,只要最終結果是正確的數據集,您是否可以向數據庫發出幾個查詢? – axiopisty 2014-09-05 04:36:34

回答

1

我一直無法與該模式和樣本數據來檢驗這個查詢,因爲我沒有一個MySQL數據庫建立,現在做的,要少得多。但我認爲這將適用於你:

select 
    c.courier_id 
    , d.delivery_id 
    , co.lat 
    , co.lng 
    , oc.cnt as remaining_orders 
from 
    couriers c 
    left join (
    select 
     d.delivery_id 
     , d.courier_id 
    from 
     deliveries d 
     inner join (
     select 
      d.delivery_id 
      , max(d.start_date) as start_date 
     from 
      deliveries d 
     group by 
      d.delivery_id 
    ) dmax on dmax.delivery_id = d.delivery_id and dmax.start_date = d.start_date 
) d on d.courier_id = c.courier_id 
    left join (
    select 
     c.delivery_id 
     , c.lat 
     , c.lng 
    from 
     coordinates c 
     inner join (
     select 
      c.delivery_id 
      , max(c.date) as date 
     from 
      coordinates c 
     group by 
      c.delivery_id 
    ) cmax on cmax.delivery_id = c.delivery_id and cmax.date = c.date 
) co on co.delivery_id = d.delivery_id 
    left join (
    select 
     o.delivery_id 
     , count(o.order_id) as cnt 
    from 
     orders o 
    where 
     o.finish_date is null 
    group by 
     o.delivery_id 
) oc on oc.delivery_id = d.delivery_id 
+0

謝謝,我會嘗試你的答案,我回來告訴它是否工作。 – 2014-09-05 05:29:05

+0

沒問題,謝謝。 – 2014-09-05 05:32:29

2

試試這個:

SELECT C.COURIER_ID, D.DELIVERY_ID, D.START_DATE, D.FINISH_DATE, 
     B.LAT, B.LNG, B.DATE, C.NoOfOrders 
FROM COURIERS C 
LEFT JOIN (SELECT * 
      FROM (SELECT * 
        FROM DELIVERIES D 
        ORDER BY D.COURIER_ID, D.START_DATE DESC 
       ) A 
      GROUP BY COURIER_ID 
     ) AS A ON C.COURIER_ID = A.COURIER_ID 
LEFT JOIN (SELECT * 
      FROM (SELECT * 
        FROM COORDINATES CO 
        ORDER BY CO.DELIVERY_ID, CO.DATE DESC 
       ) B 
      GROUP BY CO.DELIVERY_ID 
     ) AS B ON A.DELIVERY_ID = B.DELIVERY_ID 
LEFT JOIN (SELECT O.DELIVERY_ID, COUNT(1) NoOfOrders 
      FROM ORDERS O WHERE FINISH_DATE IS NULL 
      GROUP BY O.DELIVERY_ID 
     ) AS C ON A.DELIVERY_ID = C.DELIVERY_ID; 
+0

謝謝,我會嘗試你的回答,我回來告訴它是否有效。 – 2014-09-05 05:20:16