我创建了2个具有库存信息(项目,位置,数量)的表。其中NeedInv
个项目/项目中需要X
个项目。另一个HaveInv
的项目/位置的项目数超过X
。
我正在尝试合并或组合这两个表以输出应在哪些位置之间转移哪些项目。我有针对单个分发位置执行此操作的代码,并且我尝试对其进行修改并添加逻辑以使其可用于多个分发位置,但是在某些情况下仍然失败。
我已经创建了[sqlfiddle] 1,但是示例数据如下:
CREATE TABLE NeedInv
(item int, location varchar(1), need int)
INSERT INTO NeedInv
(item, location, need)
VALUES
(100, 'A', 4), (100, 'B', 0), (100, 'C', 2), (200, 'A', 0), (200, 'B', 1), (200, 'C', 1), (300, 'A', 3), (300, 'B', 5), (300, 'C', 0)
CREATE TABLE HaveInv
(item int, location varchar(1), have int)
INSERT INTO HaveInv
(item, location, have)
VALUES
(100, 'A', 0), (100, 'B', 3), (100, 'C', 0), (100, 'D', 3), (200, 'A', 1), (200, 'B', 0), (200, 'C', 0), (200, 'D', 1), (300, 'A', 0), (300, 'B', 0), (300, 'C', 20), (300, 'D', 5)
CREATE TABLE DesiredOutput
(item int, SourceLocation varchar(1), TargetLocation varchar(1), Qty int)
INSERT INTO DesiredOutput
(item, SourceLocation, TargetLocation, Qty)
VALUES
(100, 'B', 'A', 3), (100, 'D', 'A', 1), (100, 'D', 'C', 2), (200, 'A', 'B', 2), (200, 'A', 'C', 3), (200, 'D', 'C', 1), (300, 'C', 'A', 3), (300, 'C', 'B', 3)
由于连接表,我试图输出类似以下内容的内容:
+------+----------------+----------------+-----+
| item | SourceLocation | TargetLocation | Qty |
+------+----------------+----------------+-----+
| 100 | B | A | 3 |
| 100 | D | A | 1 |
| 100 | D | C | 2 |
| 200 | A | B | 2 |
| 200 | A | C | 3 |
| 200 | D | C | 1 |
| 300 | C | A | 3 |
| 300 | C | B | 3 |
+------+----------------+----------------+-----+
我当前连接两个表的查询如下:
select
n.*,
(case when Ord <= Remainder and (RemaingNeed > 0 and RemaingNeed < RemainingInv) then Allocated + RemaingNeed else case when RemaingNeed < 0 then 0 else Allocated end end) as NeedToFill
from (
select
n.*,
row_number() over(partition by item order by RN, (case when need > Allocated then 0 else 1 end)) as Ord,
n.TotalAvail - sum(n.Allocated) over (partition by item) as Remainder
from (
select
n.*,
n.TotalAvail - sum(n.Allocated) over (partition by item order by RN) as RemainingInv,
n.need - sum(n.Allocated) over (partition by item, location order by RN) as RemaingNeed
from (
select
n.*,
case when Proportional > need then need else Proportional end as Allocated
from (
select
row_number() over(order by need desc) as RN,
n.*,
h.location as Source,
h.have,
h.TotalAvail,
convert(int, floor(h.have * n.need * 1.0 / n.TotalNeed), 0) as Proportional
from (
select n.*, sum(need) over (partition by item) as TotalNeed
from NeedInv n) n
join (select h.*, sum(have) over (partition by item) as TotalAvail from HaveInv h) h
on n.item = h.item
and h.have > 0
) n
) n
) n
) n
where n.need > 0
除了Allocated
设置为零之外,它似乎在大多数情况下都有效,但是仍然有可以传输的项目。对于项目200
1可以看到这一点,其中位置B
仅需要1
但将要接收2
个项目,而位置C
还需要1
的商品将收到0
。
任何帮助/指导将不胜感激!
答案 0 :(得分:1)
IMO,您的查询看起来有点复杂。
据我所知,这只是使用运行中的库存总数将逻辑构建到查询中的简单问题。从本质上讲,这只是构建规则的问题,如果可以从源位置获取所需内容,则可以接受,否则,请尽可能多地使用。
例如,我相信以下查询包含所需的逻辑:
SELECT N.Item,
SourceLocation = H.Location,
TargetLocation = N.Location,
Qty =
CASE
WHEN N.TotalRunningRequirement <= H.TotalRunningInventory -- If the current source location has enough stock to fill the request.
THEN
CASE
WHEN N.TotalRunningRequirement - N.Need < H.TotalRunningInventory - H.Have -- If stock required has already been allocated from elsewhere.
THEN N.TotalRunningRequirement - (H.TotalRunningInventory - H.Have) -- Get the total running requirement minus stock allocated from elsewhere.
ELSE N.Need -- Otherwise just take how much is needed.
END
ELSE N.Need - (N.TotalRunningRequirement - H.TotalRunningInventory) -- Current source doesn't have enough stock to fulfil need, so take as much as possible.
END
FROM
(
SELECT *, TotalRunningRequirement = SUM(need) OVER (PARTITION BY item ORDER BY location)
FROM NeedInv
WHERE need > 0
) AS N
JOIN
(
SELECT *, TotalRunningInventory = SUM(have) OVER (PARTITION BY item ORDER BY location)
FROM HaveInv
WHERE have > 0
) AS H
ON H.Item = N.Item
AND H.TotalRunningInventory - (N.TotalRunningRequirement - N.need) > 0 -- Join if stock in source location can be taken
AND H.TotalRunningInventory - H.Have - (N.TotalRunningRequirement - N.need) < N.TotalRunningRequirement
;
注意:据我所知,您想要的输出似乎与项目200的样本数据不匹配。
答案 1 :(得分:1)
我想知道是否可以将递归CTE用于分配。
但是事实却更加复杂。
结果与问题中的预期结果不完全一致。
但是由于其他答案返回的结果相同,所以我想很好。
因此,它只是一种额外的方法。
在 db <>小提琴here
上进行测试基本上,它按照计算出的row_numbers的顺序遍历需求。
并根据需要分配可用的东西。
declare @HaveNeedInv table (
item int,
rn int,
loc varchar(1),
have int,
need int,
primary key (item, rn, loc, have, need)
);
insert into @HaveNeedInv (item, loc, have, need, rn)
select item, location, sum(have), 0 as need,
row_number() over (partition by item order by sum(have) desc)
from HaveInv
where have > 0
group by item, location;
insert into @HaveNeedInv (item, loc, have, need, rn)
select item, location, 0 as have, sum(need),
row_number() over (partition by item order by sum(need) desc)
from NeedInv
where need > 0
group by item, location;
;with ASSIGN as
(
select h.item, 0 as lvl,
h.rn as hrn, n.rn as nrn,
h.loc as hloc, n.loc as nloc,
h.have, n.need,
iif(h.have<=n.need,h.have,n.need) as assign
from @HaveNeedInv h
join @HaveNeedInv n on (n.item = h.item and n.need > 0 and n.rn = 1)
where h.have > 0 and h.rn = 1
union all
select t.item, a.lvl + 1,
iif(t.have>0,t.rn,a.hrn),
iif(t.need>0,t.rn,a.nrn),
iif(t.have>0,t.loc,a.hloc),
iif(t.need>0,t.loc,a.nloc),
iif(a.have>a.assign,a.have-a.assign,t.have),
iif(a.need>a.assign,a.need-a.assign,t.need),
case
when t.have > 0
then case
when t.have > (a.need - a.assign) then a.need - a.assign
else t.have
end
else case
when t.need > (a.have - a.assign) then a.have - a.assign
else t.need
end
end
from ASSIGN a
join @HaveNeedInv t
on t.item = a.item
and iif(a.have>a.assign,t.need,t.have) > 0
and t.rn = iif(a.have>a.assign,a.nrn,a.hrn) + 1
)
select
item,
hloc as SourceLocation,
nloc as TargetLocation,
assign as Qty
from ASSIGN
where assign > 0
order by item, hloc, nloc
option (maxrecursion 1000);
结果:
100 B A 3
100 D A 1
100 D C 2
200 A B 1
200 D C 1
300 C A 3
300 C B 5
在row_numbers中更改顺序(以填充@NeedHaveInv)将更改优先级,并可能返回不同的结果。