MySQL:引用子查询列

时间:2016-04-29 12:21:35

标签: mysql subquery

我目前正在为电子商务系统制作一些报告,需要显示订单延迟的时间。我有订单的预计交货日期日志,并且能够获得初始和最后日期,但是做更复杂的事情,例如比较预计日期,证明是有问题的。

我的查询的简化版本如下:

SELECT orders.order_id,
       orders.date_dispatched AS actual_dispatch_date,
       (
           SELECT projected_date 
           FROM order_delivery_projections
           WHERE order_id = orders.order_id
           ORDER BY order_delivery_projection_id ASC
           LIMIT 1
       ) AS initial_delivery_projection,
       (
           SELECT projected_date 
           FROM order_delivery_projections
           WHERE order_id = orders.order_id
           ORDER BY order_delivery_projection_id DESC
           LIMIT 1
       ) AS final_delivery_projection
FROM orders
-- and some other joins here for additional report data

(仅供参考,我在这里按ID而不是日期排序,因为调度预测可以向前和向后移动,例如,如果库存货物提前进入)。

这适用于提取有关订单的预计交货历史的一些原始数据,但我想对数据进行一些额外的分析,例如,在初始预计发货日期与最终预计之间存在多少天差异发货日期和实际发货日期。这是我遇到麻烦的地方。

我尝试在我的SELECT子句中添加一个DATEDIFF(final_delivery_projection, initial_delivery_projection)列,以便查看给定传递预测已经过多少天,但MySQL不会拥有它。

SELECT orders.order_id,
       orders.date_dispatched AS actual_dispatch_date,
       (
           SELECT projected_date 
           FROM order_delivery_projections
           WHERE order_id = orders.order_id
           ORDER BY order_delivery_projection_id ASC
           LIMIT 1
       ) AS initial_delivery_projection,
       (
           SELECT projected_date 
           FROM order_delivery_projections
           WHERE order_id = orders.order_id
           ORDER BY order_delivery_projection_id DESC
           LIMIT 1
       ) AS final_delivery_projection,
       DATEDIFF(final_delivery_projection - initial_delivery_projection) AS projection_days_revised
FROM orders
-- and some other joins here for additional report data
  

字段列表中的未知列final_delivery_projection

如果别名引用同一语句中的子选择,则可能无法在select语句中使用别名。

我还希望能够根据投影结果排除WHERE子句中的订单。例如,我想排除最终预计发货日期在初始预计日期之前的所有订单,理由是我只对那些被搁置的订单感兴趣,而不是对那些已提前发货的订单感兴趣时间表。

正在提取和处理数据我试图尽可能地获得相同的声明,还是我必须在客户端进行一些后期处理来处理这样的事情?如果在SQL中可行,那怎么办呢?

3 个答案:

答案 0 :(得分:1)

我相信select的值是同时生成的。因此,可能无法计算日期差异,因为当时可能不知道别名值。如果您重构Select,您可能会得到您正在寻找的结果。此外,这还可以访问您可能需要的其他表值,以便对子查询/数据集进行额外分析。

SELECT orders.order_id,
       orders.date_dispatched AS actual_dispatch_date,
       First.Projected_Date AS initial_delivery_projection,
       Current.Projected_Data AS final_delivery_projection,
       dateDiff(Current.Projected_date,First.Projected_date)
FROM orders O
LEFT JOIN (SELECT projected_date, Order_ID 
           FROM order_delivery_projections
           ORDER BY order_delivery_projection_id ASC
           LIMIT 1) First
    ON First.order_id = O.order_id
LEFT JOIN (SELECT projected_date, Order_ID
           FROM order_delivery_projections
           ORDER BY order_delivery_projection_id DESC
           LIMIT 1)
    ON Current.Order_ID = O.Order_ID

订单中的Order_ID可能不存在于order_Delivery_projections中吗?如果是这样,那么null值上的date diff也可能导致错误......

答案 1 :(得分:0)

浏览一下你需要使用派生表来访问select查询中的别名。从更多信息中查看here

尝试此查询:

SELECT orders.order_id,
       orders.date_dispatched AS actual_dispatch_date,
       initial_delivery_projection,
       final_delivery_projection,
       DATEDIFF(final_delivery_projection - initial_delivery_projection) AS projection_days_revised
FROM (
    SELECT orders.order_id,
       orders.date_dispatched AS actual_dispatch_date,
       (
           SELECT projected_date 
           FROM order_delivery_projections
           WHERE order_id = orders.order_id
           ORDER BY order_delivery_projection_id ASC
           LIMIT 1
       ) AS initial_delivery_projection,
       (
           SELECT projected_date 
           FROM order_delivery_projections
           WHERE order_id = orders.order_id
           ORDER BY order_delivery_projection_id DESC
           LIMIT 1
       ) AS final_delivery_projection
   FROM orders) z

答案 2 :(得分:0)

我花了很多时间研究这个问题,问题是MySQL的一个基本问题,这意味着如果内部查询位于查询的FROM部分,则无法在内部查询中引用外部查询,即使你可以引用外部查询,如果内部查询是在SELECT部分​​。

至于从交货日期历史记录中获取第一个和最后一个记录,我发现这个查询产生的结果是正确的,并且性能可接受。

SELECT odr.order_id,
    first_change.projected_date AS initial_projected_dispatch_date,
    last_change.projected_date AS final_projected_dispatch_date
FROM order AS odr
LEFT JOIN (
    SELECT 
        order_id, 
        MIN(order_delivery_projection_id) AS first_id, 
        MAX(order_delivery_projection_id) AS last_id
    FROM order_delivery_projections
    GROUP BY order_id
) AS change_record_finder ON change_record_finder.order_id = odr.order_id
LEFT JOIN order_delivery_projections AS first_change ON first_change.order_delivery_projection_id = change_record_finder.first_id
LEFT JOIN order_delivery_projections AS last_change ON last_change.order_delivery_projection_id = change_record_finder.last_id
WHERE -- where clauses go here

Matt的解决方案可以用于其他SQL版本,但MySQL缺乏必要的功能,以允许他的正确答案工作。