我试图避免在我的项目中使用标量值函数,所以我决定尝试使用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开发人员,所以我在上面的代码中可能会有一些明显的错误。但是,我很困惑,为什么它不起作用。
提前致谢。
答案 0 :(得分: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。
顺便说一句:你所做的就是在Jobnumber
声明中检查CTE case
中的存在。如果CTE中没有行,则 会在else部分中结束,但由于您在主查询的Jobnumber
子句中使用CTE from
,因此您将无法获得任何行,因为CTE Jobnumber
没有返回任何行。
所以要完全清楚发生了什么。如果CTE case
中没有行,则永远不会执行Jobnumber
语句。
答案 1 :(得分: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