2014-09-05 124 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