简体   繁体   中英

How to allocate quantities from one table to another in a query? e.g. picked order item quantities against actual order item quantities

I am working on an order management system at the moment where orders are received and then picked. Order items are received with quantity of 1 always - eg if two items are in an order for the same product, there will be two lines. These are stored in the OrderItems table. Order items are picked by product and are stored in the PickedItems table, ie

CREATE TABLE OrderItems
(
  OrderID int,
  Reference int,
  ProductCode varchar(20),
  Quantity int
);

CREATE TABLE PickedItems
(
  OrderID int,
  ProductCode varchar(20),
  Quantity int,
  Location varchar(20) DEFAULT NULL 
);

So for example the following inserts create an order with 6 line items, 3 of which are for the same product, another 2 for a different product and finally a single line for a 3rd product.

INSERT INTO OrderItems VALUES (1, 1, 'BOOK', 1);
INSERT INTO OrderItems VALUES (1, 2, 'BOOK', 1);
INSERT INTO OrderItems VALUES (1, 3, 'BOOK', 1);
INSERT INTO OrderItems VALUES (1, 4, 'PEN', 1);
INSERT INTO OrderItems VALUES (1, 5, 'PEN', 1);
INSERT INTO OrderItems VALUES (1, 6, 'CHAIR', 1);

If 2 of the product "BOOK" are picked and 1 of product "CHAIR", then the following will create those entries in the PickedItems table:

INSERT INTO PickedItems (OrderID, ProductCode, Quantity) VALUES (1, 'BOOK', 2);
INSERT INTO PickedItems (OrderID, ProductCode, Quantity) VALUES (1, 'CHAIR', 1);

The following query is currently used to find which Order Items have been picked successfully:

SELECT 
    OrderItems.Reference,
    OrderItems.ProductCode,
    OrderItems.Quantity,
    CASE
        WHEN SUM(OrderItemsCumulative.Quantity) <= PickedItems.Quantity THEN 1
        WHEN (SUM(OrderItemsCumulative.Quantity) - 1) < PickedItems.Quantity THEN PickedItems.Quantity - (SUM(OrderItemsCumulative.Quantity) - 1)
        ELSE 0
    END AS QuantityPicked
FROM
    OrderItems INNER JOIN
    OrderItems OrderItemsCumulative ON (OrderItems.OrderID = OrderItemsCumulative.OrderID) AND (OrderItems.ProductCode = OrderItemsCumulative.ProductCode) AND (OrderItems.Reference >= OrderItemsCumulative.Reference) LEFT JOIN
    PickedItems ON (OrderItems.OrderID = OrderItemsCumulative.OrderID) AND (OrderItems.ProductCode = PickedItems.ProductCode)
WHERE
    OrderItems.OrderID = 1
GROUP BY
    OrderItems.Reference,
    OrderItems.ProductCode,
    OrderItems.Quantity,
    PickedItems.Quantity

This all works fine, but I'd like to extend this so that PickedItems may have multiple locations associated with it (using the Location column in the PickedItems table), and thus there could be more than entry for an Order/Product in the PickedItems table, eg 2 BOOKs picked at "Location A" and 1 BOOK picked at "Location B", would have the following entries.

INSERT INTO PickedItems (OrderID, ProductCode, Quantity, Location) VALUES (1, 'BOOK', 2, 'Location A');
INSERT INTO PickedItems (OrderID, ProductCode, Quantity, Location) VALUES (1, 'BOOK', 1, 'Location B');

So the query above isn't taking the location into account.

Ideally I'd want the following returned in the above scenario, but I can't seem to get it fit with the query. Would I be best off rewriting the query using a stored procedure and allocating the data on an individual basis?

+-----------+-------------+-----------------+----------------+------------+
| Reference | ProductCode | QuantityOrdered | QuantityPicked |  Location  |
+-----------+-------------+-----------------+----------------+------------+
|         1 | Book        |               1 |              1 | Location A |
|         2 | Book        |               1 |              1 | Location A |
|         3 | Book        |               1 |              1 | Location B |
|         4 | Pen         |               1 |              0 | NULL       |
|         5 | Pen         |               1 |              0 | NULL       |
|         6 | Chair       |               1 |              0 | NULL       |
+-----------+-------------+-----------------+----------------+------------+

SQL Fiddle

Ideally you would adapt the schema to reflect the changes.

You may need to relate order reference to the location either by adding location to orderitems, or by adding reference to pickeditems, otherwise there'll always be a Cartesian on orderid/productid because they won't be unique in any of the tables.

With a stored procedure you could in theory work around the Cartesian but that would only mask the actual issue with the data model.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM