SQL Server 2008中的CTE:如何递归计算小计 [英] CTE in SQL Server 2008: how to calculate subtotals recursively

查看:143
本文介绍了SQL Server 2008中的CTE:如何递归计算小计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一张桌子,其中汽车的某些零件与层次结构相关,而且我还要花每一行制造这些零件的成本。这是表的简化:

I've got a table where some parts of a car are related hierarchically and I also have the cost of manufacturing those parts in each one of the rows. This is a simplification of the table:

parentId  Id description qty manufacturingCost costDescripcion
-------- --- ----------- --- ----------------- ---------------
NULL      1  Car          1  100               Assembly the car
NULL      2  Motorcycle   1  100               Assembly the motrocycle
 1       11  Wheel        4   20               Assembly the wheel
11      111  Rim          1   50               Manufacture the rim
11      112  Tire         1   60               Manufacture the tire
 1       12  Door+Window  4   30               Assembly the door and the window
12      121  Door         1   30               Manufacture the door
12      122  Window       2   10               Manufacture the window
 2       11  Wheel        2   15               Assembly the wheel

我需要让整个家谱开始在汽车中显示总数量和总费用ts每个分支。更好地解释:一辆汽车有4个轮子,每个轮子有1个轮辋和1个轮胎,所以我应该得到1个汽车,4个轮子,4个轮胎,4个轮辋。成本稍微复杂一点:组装汽车的成本为100美元,但我必须增加这一成本,即组装4个车轮(4x20)和制造4个轮圈(4x50)和4个轮胎的成本(4x60),门和窗户也一样。

I need to get the whole family tree starting in 'Car' and showing the total quantities and the total costs for each branch. Better explained: a car has 4 wheels and each wheel has 1 rim and 1 tire, so I should get 1 Car, 4 Wheels, 4 Tires, 4 Rims. A little bit more complicated for the costs: Assembling a car costs 100$, but I have to add to this cost, the one of assembling the 4 wheels (4x20) and the cost of manufacturing the 4 rims (4x50) and the 4 tires (4x60), and the same for the doors and windows.

这是预期的结果:

parentId  Id description qty manufacturingCost   recLevel
-------- --- ----------- --- -----------------   ---------------
NULL       1  Car          1 940 (100+4*130+4*80) 0
 1        11  Wheel        4 130 (20+50+60)       1
 1        12  Door+Window  4 80  (30+30+2*10)     1
12       121  Door         4 30                   2
12       122  Window       8 10                   2
11       111  Rim          4 50                   2
11       112  Tire         4 60                   2

我可以使用递归函数或存储过程轻松实现这一目标,但是使用更多函数却很慢复杂的结构,因此我尝试使用通用表表达式来实现。但是我没有找到合计费用的方法。我使用的是递归CTE,从最高层开始,一直到下降,我得到了数量的总和,但是我应该从结构的内部到外部进行总和,我该怎么做?

I can easily reach this one using a recursive Function or Stored Procedure but it is very slow with more complex structures, so I am trying to do it using Common Table Expressions. But I didn´t find the way to sum the costs. I use a recursive CTE starting in the top level and going down and I get the sum of the quantities, but I should go from inside to outside in the structure to sum the costs, how can I do that?

这是创建表的代码:

CREATE TABLE #Costs 
(
  parentId int, 
  Id int, 
  description varchar(50),
  qty int, 
  manufacturingCost int,
  costDescripcion varchar(150)
)

INSERT INTO #Costs VALUES (NULL , 1, 'Car', 1, 100, 'Assembly the car')
INSERT INTO #Costs VALUES (NULL , 2, 'Motorcycle', 1, 100, 'Assembly the motrocycle')
INSERT INTO #Costs VALUES (1 , 11, 'Wheel', 4, 20, 'Assembly the wheel')
INSERT INTO #Costs VALUES (11 , 111, 'Rim', 1, 50, 'Manufacture the rim')
INSERT INTO #Costs VALUES (11 , 112, 'Tire', 1, 60, 'Manufacture the tire')
INSERT INTO #Costs VALUES (1 , 12, 'Door+Window', 4, 30, 'Assembly the door and the window')
INSERT INTO #Costs VALUES (12 , 121, 'Door', 1, 30, 'Manufacture the door')
INSERT INTO #Costs VALUES (12 , 122, 'Window', 2, 10, 'Manufacture the window')
INSERT INTO #Costs VALUES (2 , 11, 'Wheel', 2, 15, 'Assembly the wheel')

这是我写的CTE:

with CTE(parentId, id, description, totalQty, manufacturingCost, recLevel)
as
(
  select c.parentId, c.id, c.description, c.qty, c.manufacturingCost, 0
  from #Costs c
  where c.id = 1

  union all

  select c.parentId, c.id, c.description, c.qty * ct.totalQty, c.manufacturingCost, ct.recLevel + 1
  from #Costs c
  inner join CTE ct on ct.id = c.parentId 
)
select * from CTE

这是我得到的结果,如您所见,不是预期的结果(未添加成本):

And this is the result I get that, as you can see, is not the expected one (the costs are not being added):

parentId  Id description qty manufacturingCost recLevel
-------- --- ----------- --- ----------------- ---------------
NULL       1  Car          1 100                0
 1        11  Wheel        4 20                 1
 1        12  Door+Window  4 30                 1
12       121  Door         4 30                 2
12       122  Window       8 10                 2
11       111  Rim          4 50                 2
11       112  Tire         4 60                 2

是否可以做我想使用的东西CTE?如果是这样,我该怎么办?

Is it possible to do what I want using CTE? If so, how can I do it?

非常感谢

安东

推荐答案

您可以尝试这样的事情

DECLARE @Table TABLE(
        parentId INT,
        Id INT,
        description VARCHAR(50),
        qty FLOAT,
        manufacturingCost FLOAT,
        costDescripcion VARCHAR(50)
)

INSERT INTO @Table SELECT NULL,1,'Car',1,100,'Assembly the car' 
INSERT INTO @Table SELECT NULL,2,'Motorcycle',1,100,'Assembly the motrocycle' 
INSERT INTO @Table SELECT 1,11,'Wheel',4,20,'Assembly the wheel' 
INSERT INTO @Table SELECT 11,111,'Rim',1,50,'Manufacture the rim' 
INSERT INTO @Table SELECT 11,112,'Tire',1,60,'Manufacture the tire' 
INSERT INTO @Table SELECT 1,12,'Door+Window',4,30,'Assembly the door and the window' 
INSERT INTO @Table SELECT 12,121,'Door',1,30,'Manufacture the door' 
INSERT INTO @Table SELECT 12,122,'Window',2,10,'Manufacture the window' 
INSERT INTO @Table SELECT 2,11,'Wheel',2,15,'Assembly the wheel'

;WITH Vals AS (
        SELECT  *,
                qty Level_Qty,
                CAST(id AS VARCHAR(MAX)) + '\' AS [LEVEL]
        FROM    @Table
        WHERE   parentId IS NULL
        UNION ALL
        SELECT  t.*,                
                p.qty * t.qty Level_Qty,
                CAST(p.[LEVEL] AS VARCHAR(MAX))  + CAST(t.id AS VARCHAR(MAX)) + '\' AS [LEVEL]
        FROM    @Table t INNER JOIN
                Vals p  ON  p.Id = t.parentId
)
SELECT  *,
        (SELECT SUM(Level_Qty * manufacturingCost) FROM Vals WHERE [Level] LIKE v.[LEVEL] + '%') / Level_Qty
FROM    Vals v
ORDER BY [LEVEL]

这篇关于SQL Server 2008中的CTE:如何递归计算小计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆