使用EXEC()重新创建存储过程并不会发现错误

时间:2017-03-02 11:12:36

标签: sql-server tsql

我通过获取它们的定义并在它们上运行ALTER语句来检查现有存储过程的有效性。

我遇到的问题是,任何没有编译的存储过程(因为依赖关系已经消失)都没有被标记为。

如果我尝试在SSMS中运行相同的ALTER命令,我会收到错误消息。 编辑:不,我不......

DECLARE @def nvarchar(MAX)
BEGIN TRY
    -- refresh the stored procedure
    SELECT @def = REPLACE(definition,'CREATE PROCEDURE ','ALTER PROCEDURE ')
      FROM sys.sql_modules
     WHERE ... -- selecting/limiting clause

    EXEC (@def);

END TRY
BEGIN CATCH
    PRINT 'Validation failed : ' + ERROR_MESSAGE()
END CATCH

如何捕获非编译错误?感谢

2 个答案:

答案 0 :(得分:2)

SQL Server存储过程使用deferred name resolution

  

创建存储过程时,将解析过程中的语句的语法准确性。如果在过程定义中遇到语法错误,则返回错误并且不会创建存储过程。如果语句在语法上是正确的,则存储过程的文本存储在sys.sql_modules目录视图中。

     

当第一次执行存储过程时,查询处理器从sys.sql_modules目录视图中读取存储过程的文本,并检查该过程使用的对象的名称是否存在。此过程称为延迟名称解析,因为存储过程引用的表对象在创建存储过程时不需要存在,但仅在执行存储过程时才存在。

所以你观察到的行为是故意的。您需要的是找出哪些程序取决于您丢失的表格。为此,请参阅View the Dependencies of a Stored Procedure,正确的答案取决于您的SQL Server版本。 SQL Server 2016在某种程度上更好地跟踪此信息并提供更好的视图。在此之前,这个过程非常难以辨认,请阅读Keeping sysdepends up to date in SQL Server 2008

答案 1 :(得分:0)

忘记这一点 - 吠叫错误的树; - ((

即使存在依赖关系,存储过程也会编译好。 SSMS中的编辑器突出显示缺少的项目,但不会停止ALTER语句的工作。

此查询将标识缺少依赖项的所有存储过程:

-- table variable to store procedure names
DECLARE @v TABLE (RecID INT IDENTITY(1,1), spname sysname)

-- retrieve the list of stored procedures
INSERT INTO @v(spname)
    SELECT 
        '[' + s.[name] + '].[' + sp.name + ']'
    FROM sys.procedures sp
    INNER JOIN sys.schemas s ON s.schema_id = sp.schema_id
    WHERE is_ms_shipped = 0
      AND sp.name like 'Get%'

-- counter variables
DECLARE @cnt INT, @Tot INT
SELECT @cnt = 1
SELECT @Tot = COUNT(*) FROM @v

DECLARE @spname sysname
DECLARE @ref nvarchar(MAX)

-- start the loop
WHILE @Cnt <= @Tot BEGIN
    SELECT @spname = spname
        FROM @v
        WHERE RecID = @Cnt

    BEGIN

        SELECT @ref = referenced_entity_name
          FROM sys.dm_sql_referenced_entities (@spname, 'OBJECT')
         WHERE referenced_id IS NULL;

    END
    SET @Cnt = @cnt + 1
END