简体   繁体   English

在表值函数中使用CTE的问题

[英]Problem using a CTE in a table valued function

I am trying to avoid using a scalar valued functions in my project, so I decided to try and convert one of them into a table valued function using a CTE. 我试图避免在项目中使用标量值函数,所以我决定尝试使用CTE将其中一个转换为表值函数。

I understand that the performance of scalar valued functions is poor because it they have to be executed for each row, and SQL server cannot optimise it in any way (ie it acts as a black box). 我知道标量值函数的性能很差,因为必须为每一行执行它们,并且SQL Server无法以任何方式对其进行优化(即,它充当黑匣子)。

Here is my first attempt at converting it into a table valued function... 这是我第一次尝试将其转换为表值函数...

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
)

I want to output a table with the job number and average score. 我想输出一张包含工作编号和平均分数的表格。

For jobs that do have the mark, it appears to be OK. 对于确实带有该标记的作业,它似乎可以。 That is, the average is returned along with the jobnumer. 即,平均值与作业编号一起返回。

For jobs that do not have a mark, it seems to go wrong. 对于没有标记的工作,似乎出错了。 The ELSE part of the statement does not execute. 语句的ELSE部分不执行。 That is, I don't get 0.0 returned as a the job average. 也就是说,我没有得到0.0作为工作平均值的返回值。 No records are returned. 没有记录返回。 Am I missing something? 我想念什么吗?

Sorry I am not an experienced SQL developer, so I might have a few glaring mistakes in the above code. 抱歉,我不是一位经验丰富的SQL开发人员,因此上面的代码中可能有一些明显的错误。 However, I am confused why a it doesn't work. 但是,我很困惑为什么它不起作用。

Thanks in advance. 提前致谢。

Not tested but something like this should do what you want. 未经测试,但是类似这样的事情应该做您想要的。

   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

No need to use a CTE. 无需使用CTE。

BTW: What you do is that you check for Exists in the CTE Jobnumber in the case statement. 顺便说一句:您要做的是检查case语句中CTE Jobnumber中是否存在。 If there are no rows in the CTE you will end up in the else part but since you use the CTE Jobnumber in the from clause of the main query you will not get any rows because the CTE Jobnumber did not return any rows. 如果CTE中没有行,您将以 else部分结尾,但是由于您在主查询的from子句中使用了CTE Jobnumber ,因此您将不会获得任何行,因为CTE Jobnumber没有返回任何行。

So to be perfectly clear of what is happening. 因此,要完全清除正在发生的事情。 The case statement will never be executed if there are no rows in the CTE Jobnumber . 如果CTE Jobnumber中没有行, case语句将永远不会执行。

EXISTS(SELECT * FROM JobAverage) means "are there any rows in at all in the whole of JobAverage". EXISTS(SELECT * FROM JobAverage)意思是“整个JobAverage中根本没有行”。

Yes, there are of course because the CASE is executing in the output rows of JobAverage 是的,这当然是因为CASE在JobAverage的输出行中执行

What you want is this I think: 我想您想要的是:

Average of marks per job. 每个作业的平均分数。
Zero where no marks for a job 零,无工作分数

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM