0

這可能是微不足道的,但我只是瞭解CTE(感謝這裏的幫助)。存儲過程語法與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'。

回答

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的起初可能有點混亂,但一旦它們有意義,它們確實很簡單。對於我來說,當我開始將它們想象成另一個臨時表語法(pro-tip:它們不是現實中的,僅僅是概念上的)時,它就被點擊了。所以基本上:

  1. 創建一個或多個「臨時表」。這些是你的CTE表達式,可以有多個表達式。
  2. 使用一個或多個緊接在CTE後面的語句中的一個或多個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=...

+0

也許值得一提的是明確的CTE僅在範圍爲立即爲OP以下可能不知道的聲明。 –

+1

@MartinSmith是的,有幾件事情需要改進。我正在解剖它,並且會擴展我的答案。 – squillman

+0

@squillman我剛更新了謝謝。出現了一個新問題,而且很可能是馬丁史密斯所說的。因爲我需要兩次使用這個rCTE表 - 關於如何重用第二個Select的數據的任何想法? – JDBennett