编辑-问题是同一项目在BOM表的不同位置多次显示,然后为每个实例而不是一个实例生成一个结果行。此问题已解决。谢谢
我有以下代码
WITH tBomCTE (ParentItem, ChildItem, WorkCentre, Operation, Quantity, ActualQuantity, ParentUnitWeight, ParentWeightUnitOfMeasure, ChildUnitWeight, ChildWeightUnitOfMeasure, BomLevel, MaterialClass, ParentItemSource) AS
(
SELECT
id.parentitem, id.ChildItem, id.WorkCentre, id.Operation,
id.Quantity, id.Quantity, id.ParentUnitWeight,
id.ParentWeightUnitOfMeasure, id.ChildUnitWeight,
id.ChildWeightUnitOfMeasure,
0 as BomLevel, id.MaterialClassCode, ParentItemSource
FROM
@tItemDenomalized id
WHERE
id.parentitem = '10054471'
UNION ALL
SELECT
id.parentitem, id.ChildItem, id.WorkCentre, id.Operation,
id.Quantity, CAST((id.Quantity * b.ActualQuantity) AS DECIMAL(19,8)), id.ParentUnitWeight,
id.ParentWeightUnitOfMeasure, id.ChildUnitWeight,
id.ChildWeightUnitOfMeasure,
BomLevel + 1,
id.MaterialClassCode, id.ParentItemSource
FROM
tBomCTE b
JOIN
@tItemDenomalized id ON b.ChildItem = id.parentitem
)
SELECT DISTINCT
'T1', ParentItem, ChildItem, WorkCentre, Operation, Quantity,
ActualQuantity,
COALESCE(ParentUnitWeight, 0), ParentWeightUnitOfMeasure,
COALESCE(ChildUnitWeight, 0), ChildWeightUnitOfMeasure, BomLevel,
MaterialClass, ParentItemSource
FROM
tBomCTE
问题在于此代码产生了多个结果行。我已将其隔离到cast((id.Quantity * b.ActualQuantity) as decimal(19,8))
行。
基本上,我正在尝试构建材料明细表(BOM),但我们遇到了数量未正确加总的问题。例如,如果我们需要2个父项目,则子项目数量仅反映我们对1个项目的需求。
因此添加了这一行。它从来没有引起问题,但是我们只是进行了测试,现在正在引起问题。
特别是。我有一个父项,然后是子项1,然后是子项2。运行此代码时,我得到了3个关于子项2的结果,这些结果都具有与父项相同的路径。所以那没有道理。然后3个子2项目的数量分别是22、44、66。
如果我不得不猜测看起来发生了什么,那就是数量确实乘以父代。然后变成22。然后我乘以下一个父级,而不是乘以,而是完全创建一个新行。
现在,我的解决方案是使用代码更新数量,然后删除所有重复的行以消除多余的行。但这是不好的做法。
为什么会产生多行而不是将父项乘以当前项?
编辑。
这是导致问题的整个存储过程:
IF EXISTS (SELECT *
FROM sysobjects
WHERE id = object_id(N'[dbo].[spSAL_BomRecursive]')
AND OBJECTPROPERTY(id, N'IsProcedure') = 1 )
BEGIN
DROP PROCEDURE [dbo].[spSAL_BomRecursive];
END
GO
CREATE PROCEDURE [dbo].[spSAL_BomRecursive]
(
@SessionId varchar(50)
,@Item [dbo].[ItemType] = NULL
,@DebugLevel BIT = 0
,@CurrentOrStandardBOM nvarchar(1) = 'C'
)
AS
BEGIN
SET NOCOUNT ON;
--declare @Item varchar(30);
--set @item = '10029554';
Declare @tItemDenomalized TABLE (ParentItem nvarchar(30),
ChildItem nvarchar(30),
WorkCentre nvarchar(30) ,
Operation nvarchar(30),
Quantity decimal(19,8),
ParentUnitWeight decimal(18,9),
ParentWeightUnitOfMeasure nvarchar(3),
ChildUnitWeight decimal(18,9),
ChildWeightUnitOfMeasure nvarchar(3),
MaterialClassCode nvarchar(30),
ParentItemSource nvarchar(30));
Declare @CurrentOrStandardSuffix int
Set @CurrentOrStandardSuffix = Case when @CurrentOrStandardBOM = 'C' then 0 else 1 end
-- populate a table with all of the items, merging data to make the recursive SQL easier
Insert into @tItemDenomalized
select distinct i.item, coalesce(jm.item, ''), jr.wc, jr.oper_num, coalesce(jm.matl_qty, 0) as qty ,i.unit_weight as ParentUnitWeight, i.weight_units as ParentWeightUnitOfMeasure, i2.unit_weight as ChildUnitWeight, i2.weight_units as ChildWeightUnitOfMeasure, i.Uf_SalMaterialClassCode as MaterialClass, i.p_m_t_code
from item_mst i
left join jobroute_mst jr on i.job = jr.job and jr.suffix = @CurrentOrStandardSuffix
left join jobmatl_mst jm on jr.job = jm.job and jr.oper_num = jm.oper_num and jr.suffix = jm.suffix
left join item_mst i2 on coalesce(jm.item, '') = i2.item;
WITH tBomCTE ( ParentItem, ChildItem, WorkCentre, Operation, Quantity, ActualQuantity, ParentUnitWeight, ParentWeightUnitOfMeasure, ChildUnitWeight, ChildWeightUnitOfMeasure, BomLevel, MaterialClass, ParentItemSource )
AS
(
select id.parentitem, id.ChildItem, id.WorkCentre, id.Operation, id.Quantity, id.Quantity, id.ParentUnitWeight, id.ParentWeightUnitOfMeasure, id.ChildUnitWeight, id.ChildWeightUnitOfMeasure, 0 as BomLevel, id.MaterialClassCode, ParentItemSource
from @tItemDenomalized id
where id.parentitem = @item
UNION ALL
select id.parentitem, id.ChildItem, id.WorkCentre, id.Operation, id.Quantity, cast((id.Quantity * b.ActualQuantity) as decimal(19,8)) , id.ParentUnitWeight, id.ParentWeightUnitOfMeasure, id.ChildUnitWeight, id.ChildWeightUnitOfMeasure, BomLevel+1, id.MaterialClassCode, id.ParentItemSource
from tBomCTE b
join @tItemDenomalized id on b.ChildItem = id.parentitem
)
insert into tSAL_Bom
([SessionId],[ParentItem],[ChildItem],[WorkCentre],[Operation],[Quantity],[ActualQuantity],[ParentUnitWeight],[ParentWeightUnitOfMeasure],[ChildUnitWeight],[ChildWeightUnitOfMeasure],[BomLevel],[MaterialClassCode],[ParentItemSource])
SELECT distinct @SessionId, ParentItem, ChildItem, WorkCentre, Operation, Quantity, ActualQuantity, coalesce(ParentUnitWeight, 0), ParentWeightUnitOfMeasure, coalesce(ChildUnitWeight, 0), ChildWeightUnitOfMeasure, BomLevel, MaterialClass, ParentItemSource
FROM tBomCTE
-- cleanup the table from yesterday
delete from tSAL_Bom
where CreatedOn < Getdate()-1
RETURN 0;
END
GO
有问题的数据行如下
SortingOrder DepthLevel ItemOrWorkCenterNumber BaseQuantity Quantity
[10054471] 0 10054471 1 1
[10054471][1605][10008773] 1 10008773 1 2
[10054471][1605][10008773][1100][10024306] 2 10024306 2 4
[10054471][1605][10008773][1100][10024306][1005][10030273] 3 10030273 11 22
[10054471][1605][10008773][1100][10024306][1005][10030273] 3 10030273 11 44
[10054471][1605][10008773][1100][10024306][1005][10030273] 3 10030273 11 66
因此您可以看到。应该有1行看起来像这样
[10054471][1605][10008773][1100][10024306][1005][10030273] 3 10030273 11 88
因为主要的父母需要1。第一个孩子需要2。所以我们的乘数是2。我们的下一个父母通常需要2,但是乘数需要4,这使我们现在的乘数8。这行是正确的。然后,下一行应该是11乘以8的乘数的基数。所以是88。但是我得到的是一行乘以2、4和6的行。
答案 0 :(得分:1)
这实际上不是您问题的答案,而是试图将大量逻辑分解为可重复的东西。
我写了一个非常快速的自封装查询,“某种”可以执行我认为您要尝试执行的操作。也许您可以做一些类似的事情来解释我的逻辑与您的逻辑之间的区别?
WITH Base AS (
SELECT 1 AS id, NULL AS parent, 1 AS multiplier
UNION ALL
SELECT 2 AS id, 1 AS parent, 2 AS multiplier
UNION ALL
SELECT 3 AS id, 2 AS parent, 4 AS multiplier),
Recurs AS (
SELECT
id,
1 AS depth,
multiplier
FROM
Base
WHERE
id = 1
UNION ALL
SELECT
b.id,
depth + 1 AS depth,
b.multiplier * r.multiplier AS multiplier
FROM
Base b
INNER JOIN Recurs r ON r.id = b.parent),
SecondRecurs AS (
SELECT
id,
depth,
multiplier
FROM
Recurs
UNION ALL
SELECT
p.parent,
s.depth,
s.multiplier
FROM
SecondRecurs s
INNER JOIN Base b ON b.id = s.id
INNER JOIN Base p ON p.id = b.parent),
Ordered AS (
SELECT
*,
ROW_NUMBER() OVER (ORDER BY depth DESC, id) AS order_id
FROM
SecondRecurs)
SELECT
id,
depth,
multiplier
FROM
Ordered
WHERE
order_id = 1;
那么这是如何工作的?
首先,我进行一些测试数据:
id parent multiplier
1 NULL 1
2 1 2
3 2 4
然后,我使用递归CTE来获取深度/乘数,使用与您的示例类似的逻辑:
id depth multiplier
1 1 1
2 2 2
3 3 8
但是我故意让它运行而不必担心让孩子们成父母,所以现在我进入了第二阶段,将其整理成某种顺序:
id depth multiplier order_id
1 3 8 1
3 3 8 2
NULL 2 2 3
2 2 2 4
1 1 1 5
最后,我可以选择想要的行,而忽略您似乎在查询中得到的“部分”结果吗?
id depth multiplier
1 3 8
这完全有帮助吗?