SQL Server成功创建了一个调用不存在函数的存储过程

SQL Server成功创建了一个调用不存在函数的存储过程,sql,sql-server,function,stored-procedures,compilation,Sql,Sql Server,Function,Stored Procedures,Compilation,在SQL Server 2017上测试。如果我创建了一个过程(在SSMS或sqlcmd中),其中包含引用不存在函数的静态SQL命令: CREATE PROCEDURE mytest AS BEGIN DECLARE @tableVar TABLE(FIELD_1 INT, FIELD_2 VARCHAR(10)) -- I am referencing a function that does not exist INSERT @tableVar SE

在SQL Server 2017上测试。如果我创建了一个过程(在SSMS或sqlcmd中),其中包含引用不存在函数的静态SQL命令:

CREATE PROCEDURE mytest
AS
BEGIN
    DECLARE @tableVar TABLE(FIELD_1 INT, FIELD_2 VARCHAR(10))

    -- I am referencing a function that does not exist
    INSERT @tableVar 
        SELECT * FROM dbo.I_DO_NOT_EXISTS()
END
GO
返回信息为:

命令已成功完成

这是很奇怪的行为

只有当我尝试运行
mytest
时,我才会得到错误:

exec dbo.mytest
Msg 208,第16级,状态1,程序dbo.mytest,第10行[批次开始第16行]
无效的对象名称“dbo.I\u不存在”

而如果我试图用
exec
编译一个调用不存在函数的过程:

CREATE PROCEDURE mytest
AS
BEGIN
    -- I am executing a function that does not exist
    EXEC dbo.I_DO_NOT_EXISTS
END
GO
我在编译时收到一条警告

模块“mytest”依赖于缺少的对象“dbo.I\u不存在”。模块仍将被创建;但是,在对象存在之前,它无法成功运行

对我来说,后一种反应似乎是正确的


是否可以选择对SQL命令引用的函数执行存在性检查?

如果SP验证是您的目标。您可以在创建SP后执行此操作。创建SP后,查找SP引用的所有对象。然后检查引用的对象是否存在

创建SP后运行以下查询,并检查referenced_id是否为NULL。如果为null,则该特定对象不存在,并且您将在SP执行过程中得到object not exists错误。希望这有帮助!我做了一个小测试,请查找下面的代码:

CREATE PROC TestSP
AS
BEGIN
    -- SPLIT function does not exists in the Database
    select * from  dbo.SPLIT('a,b,c,d',',')
    --Salary Table exists in the Database
    SELECT [Name],[salary]  FROM [dbo].[salary]
END

SELECT OBJECT_NAME(d.referencing_id) AS referencing_name, o.type_desc referencing_object_type,
 d.referenced_entity_name, d.referencing_id,d.referenced_id
FROM sys.sql_expression_dependencies d 
JOIN sys.objects o ON d.referencing_id = o.[object_id]
Where OBJECT_NAME(d.referencing_id) like '%TestSP%'

这就是它的工作方式;在SQL Server中创建存储过程并不是“编译”它,而是创建DB对象。只有当您第一次执行它时,SQL Server中的查询优化器才会尝试“编译”它(例如,为它创建一个执行计划),并且只有到那时才会检查它调用的函数或其他过程是否存在。创建存储过程不会“编译”它……这种行为称为。这是诅咒还是祝福取决于用例。但是如果我用EXEC调用一个不存在的函数,我会得到一个警告(至少)。这意味着在我创建存储过程时,SQL Server会执行检查。为什么允许在静态SQL中调用不存在的函数。我希望使用EXEC和SQL调用时会出现相同的行为。由于某种原因,Microsoft决定,对于
EXEC
语句,应该检查existance。也许是因为人们不想被警告不要引用临时表?尽管您也可以创建临时存储过程。请将代码作为文本而不是图像。我在这里找到了类似的答案:实际上,考虑到SqlServer的同义词和其他特性,web上有许多版本。谢谢你的回答,不幸的是我不能投票赞成:-)