SQL查询以获取多个订单状态的产品

时间:2020-08-27 22:07:43

标签: mysql sql join left-join greatest-n-per-group

我们有一个产品,订单,order_items,order_status模式,如下所示。 订单表状态字段,取值;按照order_status表中的定义进行订购,接收,接收和取消。

Schema for products and orders.

与此数据进行交互的UI确实具有“产品视图”,其中每个产品都有行。当用户选择产品时,下面的另一个视图(按订单显示)列出了所选产品所在的订单。

用户应该能够根据产品订单状态过滤产品视图。特别是,带有“ On Order”(按订单)按钮应过滤产品视图,以仅显示在In Orders视图中具有记录的产品记录,状态为“ ORDERED”。

以下查询返回多个产品行,原因是一个产品存在多个订单。

SELECT products.*,        
orders.`id` AS orderID,
orders.`status`    
FROM products 
LEFT JOIN order_items
 ON products.`id` = order_items.`product_id`
JOIN orders
 ON orders.`id` = order_items.`order_id`;

Result from above query

我们希望上述结果在订单状态上设置为“ coalesce”。也就是说,对于每个不同的订单状态,结果集应仅具有一个产品记录。然后,我们可以在“状态”字段中过滤产品视图。

下面的图像根据上述结果显示了我们想要的结果集。红色表示不应包含在结果中。

Desired result

如上图所示;

  • ID为18的产品以相同状态重复3次。我们只想要这些行之一。
  • ID为19的产品分为3行,其中两行状态相同。保持状态相同的两行之一,状态为1的行。
  • ID为20的产品以相同的状态重复两次,保留其中一个。

如何实现?

2 个答案:

答案 0 :(得分:1)

如果运行的是MySQL 8.0,则可以使用row_number()进行过滤。我想您想要的逻辑是:

select *
from (
    select 
        p.*,        
        o.id as orderid,
        o.status    ,
        row_number() over(partition by p.id, o.status order by o.id) rn
    from products p
    inner join order_items oi on p.id = oi.product_id
    inner join orders o on o.id = oi.order_id
) t
where rn = 1

我认为混合inner joinleft join在这里是没有道理的。要么使用两个inner join(如上面的查询中所述),要么使用两个left join(如果要保留没有任何订单的产品)。

答案 1 :(得分:1)

使用GROUP BY将多行折叠为一。使用MIN(o.id)获取每个组中定义明确的订单ID。

SELECT p.*, MIN(o.id) AS orderID, o.status
FROM products AS p
JOIN order_items AS oi ON oi.product_id = p.id
JOIN orders AS o ON o.id = oi.order_id
GROUP BY p.id, o.status

在这种情况下,使用LEFT JOIN没有意义。您永远不想按LEFT JOIN表中的列进行分组,因为所有不匹配的行都将分组在一起。而且,如果您要过滤订单状态,显然您只需要订单中的产品。