2011-06-22 19 views
0

私は自分のプロジェクトでスカラー値関数を使用しないようにしようとしていますので、そのうちの1つを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 
) 

ジョブ数と平均スコアのテーブルです。

マークが付いているジョブの場合はOKと思われます。つまり、平均値が求人情報と共に返されます。

マークが付いていないジョブについては、間違っているようです。ステートメントの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を使用する必要はありません。

ところで:あなたは、caseステートメントのCTE JobnumberのExistsをチェックします。 CTEに行がない場合はelse部分になりますが、メインクエリのfrom句にCTE Jobnumberを使用しているため、CTE Jobnumberは行を返さなかったため、行は取得されません。

何が起こっているのかを完全にはっきりさせること。 CTE Jobnumberに行がない場合、caseステートメントは実行されません。

+0

ありがとうございました。どうもありがとう。私はむしろ馬鹿だと感じます。私はすべてのコメントを感謝します。 – bobbo

+0

これはCTEを下回るとうまくいくと思います。 SELECTジョブ番号、実行時(SELECT * FROM JobAverage)THEN(SELECT平均FROMジョブ平均) ELSE 0.0 END AS平均 – bobbo

1

EXISTS(SELECT * FROM JobAverage)は、「JobAverage全体には何も行がありません」という意味です。ジョブごとのマークの

平均を:

CASEが何をしたい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

関連する問題