代码之家  ›  专栏  ›  技术社区  ›  Scott Weinstein

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

  •  3
  • Scott Weinstein  · 技术社区  · 15 年前

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

    create proc IamBrokenAndDontKnowIt as
    select * from tablewhichdoesnotexist
    

    当然,如果我尝试运行它,它会失败

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

    7 回复  |  直到 15 年前
        1
  •  1
  •   Tom H    15 年前

    你可以用

    SET FMTONLY ON
    EXEC dbo.My_Proc
    SET FMTONLY OFF
    

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

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

        2
  •  1
  •   Aaronaught    15 年前

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

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

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

    SQL Server 实际存在 . 不幸的是,没有一个依赖技巧像 sp_depends sp_MSdependencies 会在这里工作,因为你在找

    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
    

    检查 存储过程,并检查缺少的依赖项,而不实际运行它。

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

    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 Name 这不涉及任何表格。如果将其封装在 SET FMTONLY ON/OFF

    这可能是人为的问题,但是 FMTONLY ON 还有其他奇怪的事情,比如执行 IF THEN ELSE 块,这可能会导致其他意外错误,因此必须非常具体地处理错误。

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

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

    CATCH ),并立即回滚事务。当然,即使这样也可能有一些副作用,比如改变 IDENTITY

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

        3
  •  1
  •   gbn    15 年前

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

    Deferred Name Resolution

    Erland Sommarskog 提出 MS Connect 对于 SET STRICT_CHECKS ON

    workaround

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

        5
  •  0
  •   devio    15 年前

    在SQL 2005或更高版本中,可以使用事务和try/catch测试存储过程:

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

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

        6
  •  0
  •   TonyP    15 年前

    您可以检查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'
    

    .INFORMATION_SCHEMA.ROUTINES.Routine_存储过程/函数的名称

        7
  •  0
  •   Scott Weinstein    14 年前

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