分割数量以履行订单 - 基于集合的查询

时间:2014-05-27 18:32:52

标签: sql sql-server database

我正在尝试找到一个基于集合的方法来执行以下操作:

我的仓库中只有一种产品。此产品有不同尺寸的盒子。我必须使用我的库存来完成订单,根据需要拆分容器以达到确切的订购数量。订单和库存项目都必须处理FIFO。

作为一个例子,这里有一些值和解决方案(手工计算)。

+---------+-------+  +-----------+-------+
| OrderId | OQtty |  | Container | CQtty |
+---------+-------+  +-----------+-------+
|       1 | 87000 |  |         1 | 10000 |
|       2 | 26500 |  |         2 | 10000 |
|       3 | 12000 |  |         3 | 10000 |
|       4 | 43600 |  |         4 | 10000 |
|       5 |  3000 |  |         5 | 10000 |
|         |       |  |         6 |  5000 |
|         |       |  |         7 | 10000 |
|         |       |  |         8 | 10000 |
|         |       |  |         9 | 10000 |
|         |       |  |        10 | 10000 |
|         |       |  |        11 | 10000 |
|         |       |  |        12 | 10000 |
|         |       |  |        13 | 10000 |
|         |       |  |        14 |  2500 |
|         |       |  |        15 |  2500 |
|         |       |  |        16 | 10000 |
|         |       |  |        17 | 10000 |
|         |       |  |        18 | 10000 |
|         |       |  |        19 | 10000 |
|         |       |  |        20 | 10000 |
+---------+-------+  +-----------+-------+

+---------+-----------+-------+---------+
| OrderId | Container | CQtty | Running |
+---------+-----------+-------+---------+
|       1 |         1 | 10000 |   10000 |
|       1 |         2 | 10000 |   20000 |
|       1 |         3 | 10000 |   30000 |
|       1 |         4 | 10000 |   40000 |
|       1 |         5 | 10000 |   50000 |
|       1 |         6 |  5000 |   55000 |
|       1 |         7 | 10000 |   65000 |
|       1 |         8 | 10000 |   75000 |
|       1 |         9 | 10000 |   85000 |
|       1 |        10 |  2000 |   87000 |
|       2 |        10 |  8000 |    8000 |
|       2 |        11 | 10000 |   18000 |
|       2 |        12 |  8500 |   26500 |
|       3 |        12 |  1500 |    1500 |
|       3 |        13 | 10000 |   11500 |
|       3 |        14 |   500 |   12000 |
|       4 |        14 |  2000 |    2000 |
|       4 |        15 |  2500 |    4500 |
|       4 |        16 | 10000 |   14500 |
|       4 |        17 | 10000 |   24500 |
|       4 |        18 | 10000 |   34500 |
|       4 |        19 |  9100 |   43600 |
|       5 |        19 |   900 |     900 |
|       5 |        20 |  2100 |    3000 |
+---------+-----------+-------+---------+

编辑:我忘了提到这是绿色字段sql server 2012.谢谢

2 个答案:

答案 0 :(得分:1)

WITH
  O AS (SELECT *,SUM(OQtty) OVER(ORDER BY OrderId) Ort FROM @Orders),
  C AS (SELECT *,SUM(CQtty) OVER(ORDER BY Container) Crt FROM @Containers)
SELECT
  OrderId, Container, CQtty,
  CASE WHEN Crt < Ort THEN Crt-Ort+OQtty ELSE Oqtty END AS Running
FROM O
INNER JOIN C ON Crt > Ort-OQtty AND Crt < Ort+CQtty
ORDER BY OrderId, Container

演示:http://sqlfiddle.com/#!6/cb038/1

这是分区对齐问题。与试图将北美和南美国家与欧洲和非洲国家相匹配的问题是相同类型的问题,因为哪些国家的大西洋海岸线彼此直接东西方。解决方案应该与哪个组实际上是东方以及哪个组实际上是West是不可知的。所需要的只是这个逻辑:

如果两个国家的南极纬度之间的差异小于纬度的高度&#39;任何一个国家,然后他们重叠

同样,在这个问题中,容器&#39;和&#39;订单&#39;是完全可以互换的。唯一重要的是运行总数之间的差异。如果ABS(Crt-Ort)&lt; MAX(OQtty,CQtty),然后该容器与该订单配对。

答案 1 :(得分:0)

这可以使用窗口函数来完成,但它有点棘手。可以这样做的原因是因为你在计算总量。在您的示例中,容器8的一部分进入订单1并且部分进入订单2.信不信由你,这比容器8的一部分进入订单1要容易得多。 。 。其余的都浪费了。

这个想法很简单。对容器和订单进行累计求和。然后使用非等值线来查找每个订单使用的容器 - 这是累积总和重叠的地方。然后再做一些处理界限。以下是如何执行此操作的想法:

with oq as (
      select o.*,
             sum(oqty) over (order by orderid) - oqty as sumoqty_start,
             sum(oqty) over (order by orderid) as sumoqty_end
      from orders o
     ),
     cq as (
      select c.*,
             sum(cqty) over (order by container) - cty as sumcqty_start, 
             sum(cqty) over (order by container) as sumcqty_end
      from contains c
     ),
     oc as (
      select o.orderid, o.sumoqty_start, o.sumoqty_end,
             c.container, c.sumcqty_start, c.sumcty_end
      from oq join
           cq
           on oc.sumoqty_start < sumcqty_end and
              oc.sumoqty_end > sumcqty_start
     )
select o.orderid, c.containerid,
       ((case when sumcqty_end < sumoqty_end then sumcqty_end else sumoqty_end end) -
        (case when sumcqty_start > sumoqty_start then sumcqty_start else sumoqty_start end)
       ) as OrderContainerAmount
from oc
order by 1, 2;

我认为这是对的。没有SQL小提琴,我无法测试它。