我是一个相当不错的C#程序员,并且在T-SQL方面有很多经验,但我无法整理递归CTE来解决我的问题。
我需要获得食谱的每磅成本。
食谱由配料组成,但配料也可以是其他食谱。在Ingredient表中,有一个名为associatedProductID的字段。如果它为null,那么我们只需使用该成分的CostPerLb(通过获取最新的IngredientStock CostPerLb找到。如果它不为空,那么该成分实际上是另一个配方,我们需要首先找到其他成分的每磅成本然后我们总结该成分的总成本(配方中使用的成分的数量*该成分的costPerLb),然后最后除以配方的总Lbs以获得配方的CostPerLbl
这是一些简化的表格信息。
示例数据:
[Recipes]
+------+
| ID |
+------+
| 11 |
+------+
| 465 |
+------+
| 356 |
+------+
| 1617 |
+------+
[Ingredients]
+--------------+--------------------+
| IngredientID | AssociatedPrductId |
+--------------+--------------------+
| 213 | NULL |
+--------------+--------------------+
| 214 | NULL |
+--------------+--------------------+
| 216 | NULL |
+--------------+--------------------+
| 218 | NULL |
+--------------+--------------------+
| 219 | 465 |
+--------------+--------------------+
| 225 | 356 |
+--------------+--------------------+
| 150 | NULL |
+--------------+--------------------+
| 213 | NULL |
+--------------+--------------------+
| 692 | 1617 |
+--------------+--------------------+
| 172 | NULL |
+--------------+--------------------+
| 218 | NULL |
+--------------+--------------------+
| 4 | NULL |
+--------------+--------------------+
| 691 | NULL |
+--------------+--------------------+
[RecipeIngredients]
+----------+--------------+-------------+
| RecipeID | IngredientID | Quanity |
+----------+--------------+-------------+
| 11 | 213 | 2 |
+----------+--------------+-------------+
| 11 | 214 | 1 |
+----------+--------------+-------------+
| 11 | 216 | 4.31494 |
+----------+--------------+-------------+
| 11 | 218 | 10.4125 |
+----------+--------------+-------------+
| 11 | 219 | 10.37085 |
+----------+--------------+-------------+
| 11 | 225 | 3.141971875 |
+----------+--------------+-------------+
| 465 | 150 | 0.0995 |
+----------+--------------+-------------+
| 465 | 213 | 0.25 |
+----------+--------------+-------------+
| 465 | 692 | 6.752298547 |
+----------+--------------+-------------+
| 356 | 172 | 200 |
+----------+--------------+-------------+
| 356 | 218 | 249.9 |
+----------+--------------+-------------+
| 1617 | 4 | 26.59274406 |
+----------+--------------+-------------+
| 1617 | 691 | 0.743192188 |
+----------+--------------+-------------+
在我的脑海中,一般的递归函数可能看起来像这样......(这显然不是CTE,也不起作用......)
FUNCTION [dbo].[fn_getRecipeCostPerLbs]
(@ID INT = 0)
RETURNS DECIMAL(24,12)
AS
BEGIN select
sum(
--get the actual amount of ingredient used in the recipe (in lbs)
ri.Quantity
--get the cost of the ingredient (in $ / lbs)
case
--when associated product id is null then use the latest ingredient stock cost / lbs
--when its not null then use the cost / lbs of the recipe that it relates too
when i.AssociatedProductID is null then
--pull the cost/lbs of the newest stock in warehouse
isNull((select top 1 ist.CostPerLb from IngredientStock ist where ist.IngredientID = i.id order by ist.id desc),0)
else
[dbo].[fn_getRecipeCostPerLbs](@ID)
end
)
/
dbo.fn_FunctionToGetTotalRecipeLbs(@ID) -- divide by total lbs of the recipe to get cost Per Lbs
as CostPerLbs
from RecipeIngredients ri
inner join Ingredients i on i.id = ri.IngredientID
where ri.RecipeID = @ID
)
提前致谢!
-David
答案 0 :(得分:0)
因为您可以在SQL中使用递归函数,所以使用类似这样的东西 - 如果关联产品ID为NOT NULL,则调用查询来评估其成本 - 可能将每磅成本除以/乘以CASE中的内容声明
这是一个递归函数,而不是递归CTE
j==100
我想你也可能需要找到每个食谱的总成本和总重量,然后返回总成本/总重量 - 但这应该是可能的
修改
可能像 -
你熟悉表之间的连接吗?我不确定你的表是如何设计链接在一起的 - 你可能需要进行更改或提供更多信息 - 这样做的一个好方法是给脚本制作一小组样本表(尝试和删除不必要的字段,id太多了,并提供少量的代表性数据
CREATE FUNCTION [dbo].[fn_getRecipeCostPerLbs]
(@ID INT)
RETURNS DECIMAL(24,12)
AS
BEGIN
DECLARE @COST DECIMAL(24,12) = 0;
SELECT @COST = SUM(CASE WHEN IngredientStock.AssociatedProductID IS NULL
THEN
IngredientStock.CostPerLb
ELSE
[dbo].[fn_getRecipeCostPerLbs](IngredientStock.AssociatedProductID)
END
)
FROM RecipeIngredints
join Ingredients
on RecipeIngredints.RecipeID = @ID
AND
Ingredients.id = RecipeIngredints.IngredientID
join IngredientStock
on
IngredientStock.ID = Ingredients.AssociatedProductID
RETURN @COST;
)
答案 1 :(得分:0)
自己解决了。如果有人想改进这一点请告诉我...感谢您的帮助。这也比我的C#/ EF 2 SEC更好地响应8ms。
CREATE FUNCTION [dbo].[fn_getRecipeCostPerPound]
(
@ID INT = 0
)
RETURNS DECIMAL(24,12)
AS
BEGIN
Declare @Ret decimal(24,12) = 0;
Declare @TotalLbs decimal(24,12) = [dbo].[fn_RecipeLbs](@ID)
DECLARE @MyCTETempTable TABLE (RecipeID int,
IngredientID int,
AssociatedProductID int,
Quantity decimal(24,12),
level int,
CostPerLbs decimal(24,12)
)
; with CTE as
(
select
ri.RecipeID
,ri.IngredientID
,i.AssociatedProductID
,dbo.fn_ConvertUomToPounds(ri.Quantity,ri.UnitOfMeasureID,i.specificgravity) as Quantity
,1 as level
from RecipeIngredients ri inner join Ingredients i on i.id = ri.IngredientID
where ri.RecipeID = @ID
union all
select
ri_child.RecipeID
,ri_child.IngredientID
,i_child.AssociatedProductID
,dbo.fn_ConvertUomToPounds(ri_child.Quantity,ri_child.UnitOfMeasureID,i_child.specificgravity) as Quantity
,level + 1
from RecipeIngredients ri_child inner join Ingredients i_child on i_child.id = ri_child.IngredientID --and i_child.AssociatedProductID is null
join CTE parent
on parent.AssociatedProductID = ri_child.RecipeID
)
INSERT INTO @MyCTETempTable (
RecipeID,
IngredientID,
AssociatedProductID,
Quantity,
level,
CostPerLbs
)
select
cte.*, isNull((select top 1 ist.CostPerLb from IngredientStock ist where ist.IngredientID = cte_i.id order by ist.id desc),0)
from CTE
inner join Ingredients cte_i on cte_i.id = CTE.IngredientID
SET @Ret = (select sum(Quantity * CostPerLbs) / @TotalLbs
from @MyCTETempTable tt
where RecipeID = @ID
group by RecipeID)
return @Ret
END