Проблема с использованием CTE в табличной функции - PullRequest
0 голосов
/ 22 июня 2011

Я стараюсь избегать использования скалярных функций в моем проекте, поэтому я решил попробовать преобразовать одну из них в табличную функцию с помощью 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, поэтому у меня может быть несколько вопиющих ошибок в приведенном выше коде. Однако я не понимаю, почему это не работает.

Заранее спасибо.

Ответы [ 2 ]

5 голосов
/ 22 июня 2011

Не проверено, но что-то вроде этого должно делать то, что вы хотите.

   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 Jobnumber в операторе case.Если в CTE нет строк, вы окажетесь в остальной части, но поскольку вы используете CTE Jobnumber в предложении from основного запроса, вы не получите никаких строк, потому что CTEJobnumber не вернул ни одной строки.

Таким образом, чтобы быть совершенно ясно, что происходит.Оператор case никогда не будет выполнен, если в CTE Jobnumber.

нет строк.
1 голос
/ 22 июня 2011

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...