在“存在”函数中具有 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 的标量值函数的主要内容,如果未能解决你的问题,请参考以下文章