2011-06-22 64 views
0

我試圖避免在我的項目中使用標量值函數,因此我決定嘗試使用CTE將其中的一個轉換爲表值函數。在表值函數中使用CTE的問題

我知道標量值函數的性能很差,因爲它必須針對每一行執行,並且SQL服務器無法以任何方式對其進行優化(即,它充當黑匣子)。

這是我在將其轉換爲表值函數的第一次嘗試......

CREATE FUNCTION [dbo].[fn_get_job_average] (@jobnumber VARCHAR(50)) 
RETURNS TABLE AS RETURN 
( 

    WITH JobAverage AS 
    (
    SELECT job.Jobnumber, CAST(AVG(CAST(jobMark.Mark AS DECIMAL(18,1))) AS DECIMAL(18,1)) AS Average 
    FROM job 
     INNER JOIN jobMark 
     ON job.Guid = jobMark.Guid 
    WHERE job.Jobnumber = @jobnumber 
    GROUP BY job.Jobnumber 
) 
    SELECT Jobnumber, 
    CASE 
     WHEN EXISTS(SELECT * FROM JobAverage) THEN Average 
     ELSE 0.0 -- This never executes???, i.e. for job records that don't have a mark nothing is returned 
    END AS Average 
    FROM JobAverage 
) 

我要輸出與工作數量和平均得分的表。

對於確實有標記的工作,它似乎沒問題。也就是說,平均值與jobnumer一起返回。

對於沒有標記的工作,它似乎出錯了。聲明的ELSE部分不執行。也就是說,我沒有得到0.0作爲工作平均值返回。沒有記錄被返回。我錯過了什麼嗎?

對不起,我不是一個有經驗的SQL開發人員,所以我可能在上面的代碼中有一些明顯的錯誤。然而,我很困惑它爲什麼不起作用。

在此先感謝。

回答

5

無痕跡未經測試,但這樣的事情應該做你想要什麼。

SELECT job.Jobnumber, COALESCE(CAST(AVG(CAST(jobMark.Mark AS DECIMAL(18,1))) AS DECIMAL(18,1)), 0.0) AS Average 
    FROM job 
     LEFT OUTER JOIN jobMark 
     ON job.Guid = jobMark.Guid 
    WHERE job.Jobnumber = @jobnumber 
    GROUP BY job.Jobnumber 

不需要使用CTE。

順便說一句:你要做的是檢查存在於CTE Jobnumbercase聲明。如果CTE中沒有行,則結束於else部分,但由於在主查詢的from子句中使用CTE Jobnumber,因爲CTE Jobnumber未返回任何行,所以不會獲得任何行。

所以要完全清楚發生了什麼。如果CTE Jobnumber中沒有行,則case語句將永遠不會執行。

+0

謝謝。非常感謝。我感覺很傻。我很欣賞所有的評論。 – bobbo

+0

我想這可能會在CTE下工作。 (選擇* FROM JobAverage) ELSE 0.0 END AS平均值 – bobbo

1

EXISTS(SELECT * FROM JobAverage)表示「在整個JobAverage中是否有任何行」。

是的,當然還有因爲案件在JobAverage

的輸出行執行你想這是什麼,我認爲:

每個作業標記的平均值。
零,其中一份工作

SELECT 
    job.Jobnumber, 
    ISNULL(
     CAST(AVG(CAST(jobMark.Mark AS DECIMAL(18,1))) AS DECIMAL(18,1)) 
     ,0) AS Average 
FROM 
     job 
     LEFT JOIN 
     jobMark ON job.Guid = jobMark.Guid 
WHERE job.Jobnumber = @jobnumber 
GROUP BY job.Jobnumber 
+0

這個答案的第一部分是錯誤的 - jobaverage是CTE,並且已經過濾,所以答案不是「是的,當然有」。 – Tao

+0

@Tao:最後一個FROM來自CTE JobAverage。要運行CASE,必須在JobAverage中有行。所以EXISTS(...)將永遠是真實的。當JobAverage中沒有行時,它永遠不會遇到ELSE – gbn

+0

正確,但是OP的問題不是它在「有記錄時總是如此」 - 他的問題是當沒有記錄時它不會返回任何東西;我想我剛剛誤解了你答案的開頭,因爲直接涉及到「沒有記錄被返回,我錯過了什麼嗎?」這個問題。我現在走開,很抱歉打擾。 – Tao