【问题标题】:How to write a sql query returns list of orders which can be fulfilled with given items如何编写 sql 查询返回可以用给定项目完成的订单列表
【发布时间】:2017-07-13 15:12:41
【问题描述】:

我是 SQL 新手,我需要编写一个查询来返回可以用库存中的物品完成的订单列表。

假设下表显示了订单和完成订单所需的物品。

------------------------------
| OrderID | Required Item No |
------------------------------
| ORD001  |         Item007  |
| ORD001  |         Item008  |
| ORD001  |         Item009  |
| ORD002  |         Item008  |
| ORD002  |         Item009  |
| ORD002  |         Item012  |
| ORD003  |         Item008  |
| ORD003  |         Item014  |

所以为了得到满足,

  • ORD001 需要 Item007,Item008,Item009
  • ORD002 需要 Item008,Item009,Item012
  • ORD003 需要 Item008,Item014

让我们假设这张表是显示我的库存

--------------------------
| Item Unique Id |Item No |
--------------------------
| 001            | Item007|
| 002            | Item008|
| 003            | Item008|
| 004            | Item012|
| 005            | Item009|
| 006            | Item014|
| 007            | Item015|

在这种情况下,查询应该返回 ORD001 和 ORD003。有人可以帮我解决这个问题吗?

我的第一次尝试

以下查询返回我的库存

SELECT ItemNo, COUNT(ItemNo) AS QTY 
FROM InventoryTable 
GROUP BY ItemNo

------------------------------
| ItemNo |        QTY        |
------------------------------
| Item007|         1         |
| Item008|         2         |
| Item009|         1         |
| Item012|         1         |
| Item014|         1         | 
| Item015|         1         |

此查询返回特定订单所需物品的列表

SELECT ItemNo, COUNT(ItemNo) AS QTY 
FROM OrdersTable 
Where OrderID ='ORD003' 
Group By ReqItemNo

------------------------------
| ItemNo  |        QTY        |
------------------------------
| Item008 |         1         |
| Item0014|         1         |

我找不到在这两个表之间减去项目数量并为每个订单进行减法并返回可用订单的方法。

感谢@Gordon Linoff 的建议

select t1.OrderID
from t1 
left join inventory i
    on t.required_item_no = i.item_no
group by t1.OrderId
having count(*) = count(i.item_no)

这个查询看起来是正确的,但是它返回了上面例子的 ORD001,ORD002,ORD003。当 Item009 被分配给 ORD001 时,因为不再有 Item009,所以查询不应该满足 ORD002。

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    基本上,您希望订单的所需物品在库存中。这将提供该列表,但它忽略了其他订单要求。 IOW,如果第一个订单耗尽了第二个订单所需的物品,它将不会接受。

    SELECT 
        t1.OrderID,
        COUNT(DISTINCT t1.required_item_no) as `required_items`,
        COUNT(DISTINCT i.item_no) as `items_on_hand`
    FROM t1 
    LEFT JOIN inventory i
        ON t1.required_item_no = i.item_no
    GROUP BY t1.OrderId
    HAVING `required_items` = `items_on_hand`;
    

    更新

    我看到上面的查询没有考虑每个库存项目的数量,并且会包括数量为零的项目。以下更新应解决此问题。

    由于订单商品和库存的存储方式,我没有直接引用表格,而是在下面使用了子选择。当向表中添加大量项目时,性能将成为问题。您可能需要重新考虑如何存储数量,并为每个库存项目设置一行,并用一列存储手头的数量。订单表也一样。

    SELECT 
        t1.OrderID,
        COUNT(DISTINCT t1.required_item_no) as `required_items`,
        COUNT(DISTINCT i.item_no) as `items_on_hand`
    FROM (
            SELECT 
                OrderID,
                required_item_no,
                COUNT(*) as `QTY`
            FROM OrdersTable
            GROUP BY OrderID, required_item_no
            ) t1 
    
    LEFT JOIN (
                SELECT
                    item_no,
                    COUNT(*) as `QTY`
                FROM inventory
                GROUP BY item_no
            ) i
        ON t1.required_item_no = i.item_no AND 
        i.QTY >= t1.QTY
    GROUP BY t1.OrderId
    HAVING `required_items` = `items_on_hand`;
    

    【讨论】:

    • 感谢您的回复。因为我无法使用新声明的变量名,所以编辑了查询并对其进行了测试。 SELECT t1.OrderID, COUNT(DISTINCT t1.required_item_no) as required_items, COUNT(DISTINCT inventory.item_no) as items_on_hand FROM t1 LEFT JOIN inventory i ON t1.required_item_no = i.item_no GROUP BY t1.OrderId HAVING COUNT(DISTINCT t.required_item_no ) = COUNT(DISTINCT 库存.item_no);但它仍然给了我与 Gordon Linoff 的回应相同的结果。在我的测试数据库中,我只将一项添加到库存中。但它返回了不止一个订单。我做错了吗
    • 你在说什么“新声明的变量名”?我的答案中没有任何变量名。
    • 当我使用这一行时查询出错是什么意思 (required_items = items_on_hand)。我改为使用此 (t1.OrderId HAVING COUNT(DISTINCT t.required_item_no) = COUNT(DISTINCT inventory.item_no))
    • 恐怕更新也行不通。这是因为订单项目和库存的存储方式。取而代之的是,在每个库存项目的一行上,手头有数量,而库存中的每个项目都有一行。订购商品也一样。存储此信息的不寻常方式。要使查询正常工作,它需要使用子选择而不是表引用。
    • 谢谢 Thrasher 先生,感谢您的付出。我会试试你的建议
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    • 2018-06-25
    • 2018-08-17
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多