【发布时间】:2016-10-24 13:58:59
【问题描述】:
我是一个相当不错的 C# 程序员,并且在 T-SQL 方面拥有丰富的经验,但是我在组合一个递归 CTE 来解决我的问题时遇到了麻烦。
我需要获取每磅食谱的成本。
食谱由成分组成,但成分也可以是其他食谱。在成分表中,有一个名为 associatedProductID 的字段。如果它为空,那么我们只需使用该成分的 CostPerLb(通过获取最新的成分库存 CostPerLb 来找到。如果它不为空,那么该成分实际上是另一个配方,我们需要首先找到该成分的每磅成本然后我们将该成分的总成本相加(配方中使用的成分数量 * 该成分的 costPerLb),然后最后除以配方的总 Lbs 得到配方的 CostPerLbl
这是一些简化的表格信息。
- 表 [Recipes] 有一个 int ID
- 表 [RecipeIngredints] 具有 int RecipeID、int IngredientID、decimal Quantity
- 表 [Ingredients] 具有 int ID、int AssociatedProductID
- 表 [IngredientStock] 具有 int ID、int IngredientID、十进制 CostPerLb
示例数据:
[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
)
提前致谢!
-大卫
【问题讨论】:
-
您描述餐桌的方式 - 似乎食谱是由成分列表(RecipeIngredints)制成的,而这些(我猜)的成本保存在成分和IngredientStock - 您能否将 4 个表格链接在一起并汇总 Quantity * CostPerLb
-
我知道您说“配料可以成为食谱”——不过,您的餐桌上是如何做到的?
-
拥有一些表格和示例数据将大大有助于改善这个问题。 spaghettidba.com/2015/04/24/… 此外,这些标量函数可能会给您带来一些严重的性能问题。标量函数的表现是出了名的差。您在这里调用它们的方式意味着它们每行运行一次。
-
Andrew,在成分表中,有一个名为 AssociatedProductID 的字段。 (如问题中所述)如果这不为空,则该成分实际上是指另一个配方。就像物料清单是产品清单一样......但可能有另一个组件(物料清单)被引用为物料清单上的产品
-
肖恩,感谢您的评论。这个查询本来是一个函数: [fn_getRecipeCostPerLbs] (因此使其递归)......但这只是假设......并且 fn_FunctionToGetTotalRecipeLbs 仅在总和之后调用一次。我的意图是根本不使用上面的查询……而是寻求帮助构建 CTE。
标签: sql-server recursion common-table-expression