我通过获取它们的定义并在它们上运行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
如何捕获非编译错误?感谢
答案 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