2011-09-05 26 views
6

這個問題被問一些其他的時間,但我還是沒能理清正確答案或正確的方式做到這一點:如何巢CTE正確

...

;WITH CTE AS 
(
    SELECT * FROM ... 
) 
SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss' 
FROM CTE 
WHERE (Loss >= @MinRetention) 

這不起作用,我不能創建存儲過程,顯然我不能在WHERE中使用Loss,因爲在該範圍中不存在。

我想用另一個CTE來包裝這一塊,所以我可以把WHERE在外之一,但不是似乎並沒有工作,嘗試這樣做:

;WITH CTE AS 
(
    SELECT * FROM ... 
) 
SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss' 
FROM CTE, 
RESULTS AS 
(SELECT * FROM CTE) 
    SELECT * 
    FROM RESULTS 
    WHERE (Loss >= @MinRetention) 

但它不能在SQL編譯服務器,我得到一個錯誤,'('錯位多行上面,但無關,如果我刪除第二個CTE它工作正常。

我只想避免代碼重複,不想打電話給我[ udf_BetaInv]兩次在選擇和也在哪裏。

+0

你是指'[Loss]'(列名)而不是'Loss'(一個字符串)?不知道是否會導致錯誤,儘管 – Rup

回答

13

你有一箇中間的SELECT,你不應該有。這應該工作:

;WITH CTE AS 
(
    SELECT * FROM ... 
), 
RESULTS AS 
(
    SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss' 
    FROM CTE 
) 
SELECT * 
FROM RESULTS 
WHERE (Loss >= @MinRetention) 
+0

謝謝,工作也很好,沒有意識到我有太多的SELECTs:D –

+1

這不是必要的,而是一個很好的實踐來明確命名列在你的CTE名稱中,即....結果([來自CTE的列名],損失)....稍後你會感謝你自己:P。 – deutschZuid

7

顯然問題em與第一個查詢是'損失'只是列別名,不能在WHERE子句中使用。你說得對,在CTE中使用它會避免重複表達。以下是你如何做到這一點;

WITH CTE AS 
( 
    SELECT * FROM ... 
), 
CteWithLoss AS ( 
    SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss' 
    FROM CTE 
) 
SELECT * 
FROM CteWithLoss 
WHERE (Loss >= @MinRetention); 

在一個側面說明:看看你是否可以打破開始;WITH您的CTE定義的習慣,轉而進入終止與分號的所有SQL語句的習慣。它更具可讀性和更好的實踐。

+0

感謝現在完美:) –

+0

我需要第一個CTE內的第二個CTE,查詢取決於它。有什麼辦法可以做到嗎? – Akbari

+0

加一個「打破開始CTE定義的習慣; WITH」 – DaveBoltman

0

下面是嵌套CTE的示例。

with cte_data as 
(
    Select * from [HumanResources].[Department] 
),cte_data1 as 
(
    Select * from cte_data 
) 

select * from cte_data1 
+0

這不是嵌套的,只是另一個引用前一個的CTE。 – DaveBoltman

+0

這是嵌套戴夫。事實上,它幾乎是嵌套CTE的定義。你是否想過遞歸CTE的?這是一個全新的球賽,更有趣,但不是OP要求的。 –