SQL Server具有Deferred Name Resolution
功能,请阅读此处了解详细信息:
https://msdn.microsoft.com/en-us/library/ms190686(v=sql.105).aspx
在该页面中,它所说的都是存储过程,因此看起来Deferred Name Resolution
仅适用于存储过程而不适用于函数,我做了一些测试。
create or alter function f2(@i int)
returns table
as
return (select fff from xxx)
go
请注意,表xxx
不存在。当我执行上面的CREATE
语句时,我收到以下消息:
Msg 208,Level 16,State 1,Procedure f2,Line 4 [Batch Start line 22]
无效的对象名称' xxx'。
似乎SQL Server立即找到了不存在的表xxx
,并证明Deferred Name Resolution
对functions
不起作用。但是当我稍微改变它时如下:
create or alter function f1(@i int)
returns int
as
begin
declare @x int;
select @x = fff from xxx;
return @x
end
go
我可以成功执行它:
Commands completed successfully.
执行以下声明时:
select dbo.f1(3)
我收到了这个错误:
Msg 208,Level 16,State 1,Line 34
无效的对象名称' xxx'。
所以这里似乎推迟了表xxx
的分辨率。这两种情况最重要的区别是返回类型。但是,我无法解释Deferred Name Resolution
何时适用于函数,何时不适用。任何人都可以帮我理解这个吗?提前致谢。
答案 0 :(得分:6)
感觉您正在寻找理解为什么您的特定示例无法正常工作。 Quassnoi的回答是正确的,但没有提供理由,所以我去搜索并找到了Erland Sommarskog的MSDN Social answer。有趣的部分:
但是,它不会扩展到视图和内联表函数。对于 存储过程和标量函数,所有SQL Server存储在 database是模块的文本。但对于视图和内联表 函数(由另一个名称参数化的视图)SQL Server 存储有关列等的元数据。如果是,则无法实现 桌子不见了。
希望有助于理解原因: - )
编辑:
我确实花了一些时间来确认Quassnoi的评论sys.columns
以及其他几个表确实包含有关内联函数的一些元数据,所以我不确定是否有其他元数据没有写入。但是我想我会添加一些其他可以帮助解释的其他注释。
在MTVF中,您只看到一个名为“表值函数”的操作。它所做的一切本质上都是一个黑盒子 - 正在发生的事情,并返回数据。对于MTVF,SQL无法“看到”MTVF正在执行的操作,因为它在单独的上下文中运行。这意味着SQL必须在编写时运行MTVF,而无法在查询计划中进行任何优化以优化它。
然后从SQL Server 2016 Exam 70-761 by Itzik Ben-Gan (Skill 3.1):
它被称为内联函数的原因是因为SQL Server内联或扩展了内部查询定义,并直接针对基础表构造内部查询。
所以看起来内联函数本质上返回一个查询,并且能够使用外部查询对其进行优化,不允许使用黑盒方法,因此不允许延迟名称解析。
答案 1 :(得分:5)
第一个示例中的内容是内联函数(它没有BEGIN/END
)。
内联函数只能是表值。
如果您为第一个示例使用了多语句表值函数,请执行以下操作:
CREATE OR ALTER FUNCTION
fn_test(@a INT)
RETURNS @ret TABLE
(
a INT
)
AS
BEGIN
INSERT
INTO @ret
SELECT a
FROM xxx
RETURN
END
,它会在运行时编译正常并失败(如果xxx
不存在),与存储过程或标量UDF相同。
所以是的,DNR适用于所有多语句函数(具有BEGIN/END
的函数),无论它们的返回类型如何。