2012-06-25 67 views
4

我想要做這樣的事情CTE內部SQL IF-ELSE結構

declare @a int=1 
if (@a=1) 
with cte as 
(
select UserEmail from UserTable 
) 
else 
with cte as 
(
select UserID from UserTable 
) 
select * from cte 

這僅僅是一個例子,我實際的查詢要複雜得多。所以我不想在CTE之後兩次在IFELSE聲明中寫出SELECT聲明。

回答

11

如果可能的CTE「定義」,找到一種方式來完全避免if聲明。

E.g.在這樣一個簡單的例子,如你的問題:

;with CTE as (
     select UserEmail from UserTable where @a = 1 
     union all 
     select UserID from UserTable where @a != 1 or @a is null 
) 
select /* single select statement here */ 

應該通常可以組成一個或多個不同的查詢到最終UNION ALL CTE,而是採用if - 畢竟,無論是查詢被混合的絕無論如何都有兼容的結果集,對於你原來的問題是有道理的。

+0

Damien的一個非常好的解決方法,使用'Union ALL'並在where子句中添加'if'條件過濾器 對於性能,我建議使用過濾器作爲第一個條款在'Where' –

+0

@Damien_The_Unbeliever,你能否詳細說明爲什麼我們應該避免'IF'? –

+1

@NikitaSilverstruk - 這不是一個絕對的禁止,更多的是一般指南 - 如果你試圖產生一個結果集,你應該嘗試制定如何在單個查詢中生成結果集,然後讓優化器計算出最佳結果生成它,而不是手動將查詢分解爲塊。正如你可以從marc_s的答案中看到的那樣,使用if的替代方法最終有兩個查詢,它們之間有重複。 –

6

你不能這麼做 - CTE 必須在之後緊跟一個恰好一個可引用它的SQL語句。您不能從使用它的語句中拆分CTE的「定義」。

所以,你需要做的是這樣的:

declare @a int=1 

if (@a=1) 
    with cte as 
    (
     select UserEmail from UserTable 
    ) 
    select * from cte 

else 

    with cte as 
    (
     select UserID from UserTable 
    ) 
    select * from cte 

不能拆分爲它的使用(select * from cte

+0

@MartinSmith:我害怕的是(但無法找到的文檔一個明確的說法):-(因此打消了我的部分。 –

+0

我知道CTE必須緊跟一個sql語句,但我正在尋找一種解決方法,我不想編寫重複的select語句。 – MegaMind

+1

@MegaMind:there **沒有辦法解決這個問題* * - 這是CTE定義的工作方式 –

3

with cte (...) select from cte ...單個語句。不是'遵循'的聲明,它是聲明的一部分。你要求將陳述分成兩部分,這顯然是不可能的。

作爲一般規則,SQL對DRY和避免代碼重複等事情來說是非常不友好的語言。試圖使代碼更易於維護,更具可讀性,或者只是簡單地嘗試保存一些按鍵就可以(並且通常會)導致嚴重的運行時性能損失(例如,試圖將CTE移動到表值函數UDF中)。最簡單的事情就是咬下子彈(這次和未來......)並寫出CTE兩次。有時將CTE物化爲#temp表格,然後在#temp表格中運行,但只有有時是

status-quo is unfortunate,但你可以從design by committee期望的一切......