在“存在”函数中具有 cte 和前 1 的标量值函数

Posted

技术标签:

【中文标题】在“存在”函数中具有 cte 和前 1 的标量值函数【英文标题】:scalar valued function having cte and top 1 within 'Exist' function 【发布时间】:2016-05-11 13:38:28 【问题描述】:

我的查询使用 'exists' 函数作为过滤器,其中包含标量值函数。标量值函数包含 cte 和“(select top 1 1)”。当我使用存在时,它根本不会过滤。相反,当我使用“where 1 =(svf)”时,它似乎有效。我在存在查询中错过了什么或任何错误吗?


SELECT * FROM TBL1
WHERE EXISTS (SELECT SVF(1,2))
--where SVF is my scalar valued from which returns bit and looks like as shown below.

CREATE FUNCTION SVF ( @x int, @y int ) RETURNS bit AS BEGIN declare @result bit ;WITH T1 AS ( SELECT * from tbl2 ) SELECT @result= (select top 1 1 FROM t1 ) return isnull(@result,0) END GO

--the following query works SELECT * FROM TBL1 WHERE 1=(SELECT SVF(1,2))

【问题讨论】:

这个标量函数的意义何在?它似乎过于复杂。为什么不放弃这个标量函数而简单地使用“where exists (select * from tbl2)”呢?标量函数效率极低,在这种情况下似乎完全没有必要。 另外,阅读EXISTS:“如果子查询包含任何行,则返回 TRUE。”并注意它没有说明行的 contents 。您有一个子查询(因为它缺少FROM 子句)总是只生成一行。它总是能轻松满足EXISTS 测试。 看这个有点接近整个功能是完全没有意义的。它总是会返回一个值,因此存在检查总是会成功。 不能删除标量函数。它里面有很多脚本。这只是脚本的样本,不是真实的。 @SeanLange @bill - 一个由SELECT 组成但没有FROM 子句的查询总是产生恰好一行。 EXISTS 检查特定子查询是否产生任何行。它不检查行中的 what,因此 what svf 返回无关紧要(实际上可以通过 1、0、NULL、任何东西) 【参考方案1】:

EXISTS() 运算符

如果子查询包含任何行,则返回 TRUE。

强调

这很重要,因为您的 Scalar 函数将返回一个值,1 或 0(正如 Damien 指出的那样,即使 NULL 也会满足)但 它会返回一个值

因为它返回一个值,EXISTS 总是会返回 TRUE。

你基本上是在问 SQL Server:

-- Doesn't matter what my function returns as it's always going to return a row...
BEGIN 
-- then run this query
SELECT * FROM TBL1;
END;

尝试重写您的查询以不使用该函数,因为标量函数通常不是基于集合的,因此通常是性能杀手。

【讨论】:

它甚至不需要返回一个值 - 它可以返回 NULL 并且存在测试会仍然成功,因为它所关心的只是一个 行. 所以,如果我坚持使用 svf,那么我必须像上次查询一样检查 1,对吗?更好地改变 svf ?但是更改 svf 对我来说似乎不可行,因为它包含太多的表格和逻辑。 我不确定我是否同意您的“基本要求”重写,因为它仍然给人一种错误的印象,即从SVF 返回的值是相关的。它更接近于询问 SQL Server——“SELECT COUNT(*) FROM (SELECT <select clause only>) t 会产生值 0 吗?”我们只是不关心 <select clause> 中的内容。 @Damien_The_Unbeliever 我再次向您的逻辑低头,因为快速阅读会给人留下深刻印象。在那里编辑 @Shaneis 您忘记在脚本中计数 (select count(*))。【参考方案2】:

如前所述,exists 函数将始终评估为 true,因为您的标量函数返回一个值。 Exists 只有在函数调用最终没有返回值时才会起作用。

例如,您可以使用交叉应用:

SELECT * 
FROM TBL1 as T1
CROSS APPLY (SELECT svf = dbo.SVF(T1.x,T2.y)) c
WHERE svf = 1

编辑: 请记住,标量函数在大多数情况下都是性能杀手,因为它们不是 sargable。

【讨论】:

它和我上一个脚本有什么不同? 如果我使用 SELECT * FROM TBL1 WHERE 1=(SELECT SVF(1,2)) @bill 您的脚本基本上没有区别。您可以检查每个查询的执行计划,但这两种方法都不好。为了提高性能,您需要忘记 UDF。 @Shaneis NULL 在元组匹配但值为 NULL 时满足存在条件。正如我所说,“函数调用最终可能不返回任何值”不会满足存在。为了避免混淆,我删除了帖子中的 (null)。

以上是关于在“存在”函数中具有 cte 和前 1 的标量值函数的主要内容,如果未能解决你的问题,请参考以下文章

具有标量值函数的可变长度 NVARCHAR

NHibernate 中的标量值函数

如何使用sql server数据库中的标量值函数

为什么 "where "子句中的标量值函数会变慢?

从 C# 调用时,来自 SQL Server 的标量值函数不返回值

具有 CTE 的 T-SQL 窗口函数,使用先前计算的值