Sql server 有没有办法让SQL server验证存储过程中的对象引用?

Sql server 有没有办法让SQL server验证存储过程中的对象引用?,sql-server,stored-procedures,typechecking,Sql Server,Stored Procedures,Typechecking,以下代码在SQL Server中执行良好 create proc IamBrokenAndDontKnowIt as select * from tablewhichdoesnotexist 当然,如果我尝试运行它,它会失败 无效的对象名称“tablewhichdoesnotexist” 有没有办法编译或验证存储的进程是否有效?您可以运行sp\u dependens(请参阅),并使用该信息查询信息架构(),查看是否存在所有对象。根据我在这里读到的()内容,您只需要检查引用的表,这是可行的。您可

以下代码在SQL Server中执行良好

create proc IamBrokenAndDontKnowIt as
select * from tablewhichdoesnotexist
当然,如果我尝试运行它,它会失败

无效的对象名称“tablewhichdoesnotexist”


有没有办法编译或验证存储的进程是否有效?

您可以运行
sp\u dependens
(请参阅),并使用该信息查询信息架构(),查看是否存在所有对象。根据我在这里读到的()内容,您只需要检查引用的表,这是可行的。

您可以使用

SET FMTONLY ON
EXEC dbo.My_Proc
SET FMTONLY OFF
您将需要以某种方式捕获错误,但是不需要花费太多时间就可以构建一个快速实用程序应用程序,利用它查找无效的存储过程


我还没有广泛使用过它,所以我不知道是否有任何副作用需要注意。

当您尝试创建这样的存储过程时,通常会收到一条警告消息。它会说:

无法向当前存储过程的sysdepends添加行,因为它依赖于缺少的对象“dbo.nonexistenttable”。存储过程仍将被创建

由于某些原因,我现在无法理解它,我不确定它是否已被更改,或者是否只有一些设置可以打开或关闭警告。不管怎样,这应该给你一个提示,这里发生了什么

SQL Server确实跟踪依赖项,但只跟踪实际存在的依赖项。不幸的是,像
sp_dependences
sp_msdependences
这样的依赖技巧在这里都不起作用,因为您正在查找缺少的依赖项

即使我们可以假设找到一种方法来检查这些缺失的依赖项,但捏造一些东西来破坏检查仍然是微不足道的:

CREATE PROCEDURE usp_Broken
AS

DECLARE @sql nvarchar(4000)
SET @sql = N'SELECT * FROM NonExistentTable'
EXEC sp_executesql @sql
您也可以尝试解析“FROM xxx”之类的表达式,但也很容易克服这一点:

CREATE PROCEDURE usp_Broken2
AS

SELECT *
FROM
    NonExistentTable
在不实际运行存储过程的情况下,确实没有任何可靠的方法来检查存储过程并检查缺少的依赖项

如Tom H所述,您可以使用
SET FMTONLY ON
,但请注意,这会改变过程“运行”的方式。它抓不到一些东西。例如,没有什么可以阻止您编写这样的过程:

CREATE PROCEDURE usp_Broken3
AS

DECLARE @TableName sysname

SELECT @TableName = Name
FROM SomeTable
WHERE ID = 1

DECLARE @sql nvarchar(4000)
SET @sql = N'SELECT * FROM ' + @TableName
EXEC sp_executesql @sql
假设您有一个名为
SomeTable
的实表和一个ID=1的实行,但其
名称不引用任何表。如果将其包装在
SET FMTONLY ON/OFF
块中,则不会产生任何错误

这可能是人为造成的问题,但是
FMTONLY ON
会执行其他奇怪的操作,比如执行
IF
/
然后
/
ELSE
块的每个分支,这可能会导致其他意外错误,因此您必须非常具体地处理错误

测试过程唯一真正可靠的方法是实际运行它,如下所示:

BEGIN TRAN

BEGIN TRY
    EXEC usp_Broken
END TRY
BEGIN CATCH
    PRINT 'Error'
END CATCH

ROLLBACK
此脚本将在事务中运行该过程,对错误(在
捕获
中)采取一些操作,并立即回滚事务。当然,即使这样做也可能有一些副作用,例如,如果将
标识
种子插入到表中(成功),则会更改该种子。只是一些需要注意的事情

老实说,我不会用一根50英尺长的杆子碰这个问题。

不会(但请继续阅读,请参阅最后一行)

它的设计是:

设置严格的检查

连接请求有一个(不是我自己尝试的):

使用检查执行计划。唯一的 缺点是你可能需要 查看执行计划的权限 首先


您可以检查information_schema.tables以检查表是否存在,然后执行代码

这里是快速悬挂功能检查

 create function fnTableExist(@TableName varchar(64)) returns int as
    begin
        return (select count(*) from information_schema.tables where table_name=@tableName and Table_type='Base_Table')
    end

go        

    if dbo.fnTableExist('eObjects') = 0 
        print 'Table exist'
    else
        print 'no suchTable'
像wise一样,您可以在中检查存储的进程/函数是否存在


.INFORMATION\u SCHEMA.ROUTINES.Routine\u存储过程/函数的名称在SQL 2005或更高版本中,您可以使用事务和try/catch测试存储过程:

BEGIN TRANSACTION

BEGIN TRY
  EXEC (@storedproc)
  ROLLBACK TRANSACTION
END TRY
BEGIN CATCH
  WHILE @@TRANCOUNT > 0
    ROLLBACK
END CATCH

测试数据库中所有存储过程的算法要复杂一些,因为如果有许多SP返回许多结果集,则需要绕过SSMS限制。请参阅我的。

我刚刚发现带有数据库项目的VS2010将执行语法和名称引用检查。似乎是最好的选择。

我认为sp_depend只适用于实际存在的对象。在我的服务器上进行的快速测试表明,当我引用无效表时,没有报告任何依赖项。Tom H.谢谢。我想我应该测试一下,而不是假设一下。对不起,我说的是青鱼。它将返回空结果集,并且不会运行任何更新/插入等。我也只是在DDL(DROP TABLE)上运行了一个快速测试,并使用了动态SQL,但这两个测试都没有运行。UPDATE语句刚刚返回了受影响的0行计数。a好的,只有当一个sp调用另一个(尚未存在)sp时,才会收到警告。我从未在不存在表或视图的情况下看到过此警告。