将一个表中的项目数分配给另一个表中的可用空间

时间:2017-09-07 20:02:28

标签: sql sql-server tsql sql-server-2016

我有两张桌子:

#shelves(id INT, shelve_size INT);
id shelve_size
1   5
2   19
3   64
4   9

#palettes(id INT, number_of_items INT)
id number_of_items
1   3
2   9
3   32

我需要一个显示类似内容的查询,而不使用while循环:

id shelve_size number_of_items used available
1  5           3               3    2
1  5           9               2    0
2  19          9               7    12
2  19          32              12   0 
3  64          32              20   44      
4  9           0               0    9 <- not necesary row

以Id顺序解压缩调色板并按ID顺序将它们存储在货架上。如果在打开一个调色板后货架未满,则下一个调色板使用任何剩余容量。

第一个货架尺寸的容量为5,因此从第一个货盘获得3个货物,从第二个货盘获得2个货物。这留下了7件托盘2,它们存放在架子2上。之后,架子2有20个物品的空间。等等。

1 个答案:

答案 0 :(得分:1)

让我们从一个简单的例子开始。有4个架子S1,S2,S3,S4 - 所有可容纳5件物品。

三个托盘P1(3个单位),P2(13个单位)和P3个(3个单位)。

很容易想象到最后的结果将是如下所示的货架。

+----+--------+--------+--------+--------+--------+
|    | Slot 1 | Slot 2 | Slot 3 | Slot 4 | Slot 5 |
+----+--------+--------+--------+--------+--------+
| S1 | P1     | P1     | P1     | P2     | P2     |
| S2 | P2     | P2     | P2     | P2     | P2     |
| S3 | P2     | P2     | P2     | P2     | P2     |
| S4 | P2     | P3     | P3     | P3     |        |
+----+--------+--------+--------+--------+--------+

为了在SQL中执行此操作,我在两个表中添加了几个正在运行的总列。

保质

+----------+------+---------------------+---------------------+
| shelf_id | size | cume size exclusive | cume size inclusive |
+----------+------+---------------------+---------------------+
| S1       |    5 |                   0 |                   5 |
| S2       |    5 |                   5 |                  10 |
| S3       |    5 |                  10 |                  15 |
| S4       |    5 |                  15 |                  20 |
+----------+------+---------------------+---------------------+

托盘

+------------+------------+---------------------------+---------------------------+
| pallet_id  | item count | cume item count exclusive | cume item count inclusive |
+------------+------------+---------------------------+---------------------------+
| P1         |          3 |                         0 |                         3 |
| P2         |         13 |                         3 |                        16 |
| P3         |          3 |                        16 |                        19 |
+------------+------------+---------------------------+---------------------------+

如果

,托盘将(至少部分地)搁置在货架上
  • 货架有空间 - 即货架(以及所有以前的货架)的容量大于所有先前调色板已经使用的空间。 cume size inclusive > cume item count exclusive
  • 托盘尚未完全拆开包装。 - 即所有先前货架的容量小于拆包所有货盘所需的空间,包括当前货盘。 cume size exclusive < cume item count inclusive

可以很容易地计算available,方法是在托盘完全解压后查看货架是否已满,如果是,则返回0,否则返回cume_size_inclusive - cume_item_count_inclusive

used的计算方法是查看托盘项目计数并扣除先前或后续货架上存储的项目。

这应该这样做。 Demo

WITH S
     AS (SELECT *,
                SUM(size) OVER (ORDER BY shelf_id ROWS UNBOUNDED PRECEDING) - size AS cume_shelf_capacity_exclusive,
                SUM(size) OVER (ORDER BY shelf_id ROWS UNBOUNDED PRECEDING)        AS cume_shelf_capacity_inclusive
         FROM   #shelves),
     P
     AS (SELECT *,
                SUM(item_count) OVER (ORDER BY pallet_id ROWS UNBOUNDED PRECEDING) - item_count AS cume_items_exclusive,
                SUM(item_count) OVER (ORDER BY pallet_id ROWS UNBOUNDED PRECEDING)              AS cume_items_inclusive
         FROM   #palettes)
SELECT S.shelf_id,
       S.size,
       number_of_items = ISNULL(P.item_count, 0),
       used = ISNULL(item_count, 0) - IIF(cume_items_inclusive > cume_shelf_capacity_inclusive, cume_items_inclusive - cume_shelf_capacity_inclusive, 0) --overspill to next shelves
            - IIF(cume_shelf_capacity_exclusive > cume_items_exclusive, cume_shelf_capacity_exclusive - cume_items_exclusive, 0), --stocked on previous shelves
       available = IIF(cume_shelf_capacity_inclusive < cume_items_inclusive, 0, ISNULL(cume_shelf_capacity_inclusive - cume_items_inclusive, S.size))
FROM   S
       LEFT JOIN P
         ON S.cume_shelf_capacity_inclusive > P.cume_items_exclusive
            AND S.cume_shelf_capacity_exclusive < P.cume_items_inclusive
ORDER BY shelf_id, 
         pallet_id;