这可能是微不足道的,但我只是在学习CTE(感谢这里的帮助)。
我有一个用于确定总数的程序。
第一部分是总数是他们等级下面的位置的总和。所以我需要一种方法来检索记录(1)确定记录的级别(层次结构)和(2)返回所有记录的位置。有人问过并回答here。
现在想从上面的答案中获取CTE表并在我的程序的第二部分中使用它(获得总数)
CREATE PROCEDURE [dbo].[GetProgramTotals]
@programId nvarchar(10) = null,
@owner int = null,
@totalAmount money OUT,
@usedAmount money OUT,
@remainingAmount money OUT
AS
BEGIN
WITH rCTE AS
(
SELECT
*, 0 AS Level
FROM Forecasting.dbo.Addressbook
WHERE Addressbook = @owner
UNION ALL
SELECT
t.*, r.Level + 1 AS Level
FROM Addressbook t
INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook
)
Select @totalAmount = (Select Sum(Amount) from dbo.Budget where
(@programId IS NULL or (ProgramId = @programId)) and (@owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))
Select @usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where
(@programId IS NULL or (ProgramId = @programId) and (@owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))
if (@totalAmount is null)
set @totalAmount = 0
if (@usedAmount is null)
set @usedAmount = 0
Set @remainingAmount = (@totalAmount - @usedAmount)
END
此过程的想法是基于层次结构中的用户位置动态计算单个(或所有)程序。
因此,区域经理总数将是所有地区和地区代表的总和。
更新:我根据下面的squillman(谢谢)评论对此进行了更新。
现在我有一个不同的问题。当我执行proc时 - 我得到了无效的对象名称rCTE'。
答案 0 :(得分:2)
您无法在查询中使用SET
。将其更改为SELECT
,它可以解决您的语法错误。
CREATE PROCEDURE [dbo].[GetProgramTotals]
@programId nvarchar(10) = null,
@owner int = null,
@totalAmount money OUT,
@usedAmount money OUT,
@remainingAmount money OUT
AS
BEGIN
WITH rCTE AS(
SELECT *, 0 AS Level FROM Forecasting.dbo.Addressbook WHERE Addressbook = @owner
UNION ALL
SELECT t.*, r.Level + 1 AS Level
FROM Addressbook t
INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook)
SELECT @totalAmount = (Select Sum(Amount) from dbo.Budget where
(@programId IS NULL or (ProgramId = @programId)) and (@owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))
, @usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where
(@programId IS NULL or (ProgramId = @programId) and (@owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))
if (@totalAmount is null)
set @totalAmount = 0
if (@usedAmount is null)
set @usedAmount = 0
Set @remainingAmount = (@totalAmount - @usedAmount)
END
一开始CTE可能有点令人困惑,但一旦有意义,它们真的很简单。对我而言,当我开始将它们视为另一种临时表语法时,它会点击它(专业提示:它们实际上不是概念上的)。所以基本上:
正如马丁在下面的评论中提到的那样,CTE仅限于下一个立即声明,并且在此之后不属于范围。
所以,
;WITH cte1 AS
(
SELECT Col1 FROM Table1
),
cte2 AS
(
SELECT Col1 FROM Table2
)
SELECT Col1 FROM cte1 //In scope here
UNION
SELECT Col1 FROM cte1; //Still in scope since we're still in the first statement
SELECT Col1 FROM cte1; //Fails. cte1 is now out of scope (as is cte2)
在您的情况下,您使用递归CTE来形成父/子层次结构,然后根据结果设置变量。在编辑之后,您的CTE语法非常接近,您只需要使用逗号将事物重新组合成一个语句。
//Variable assignment example
;WITH cte1 AS
(
SELECT Col1 FROM Table1
),
cte2 AS
(
SELECT Col1 FROM Table2
)
SELECT @var1 = (SELECT TOP 1 Col1 FROM cte1)
,@var2 = (SELECT TOP 1 Col1 FROM cte2) //You're missing the comma at the start of this line
将Select @usedAmount=...
更改为, @usedAmount=...