How to check all stored procedure is ok in sql server if I drop a table or fields?
问题:
回答1:
I found Cade's answer useful in formulating my own script for checking objects in a database, so I thought I'd share my script as well:
DECLARE @Name nvarchar(1000);
DECLARE @Sql nvarchar(1000);
DECLARE @Result int;
DECLARE ObjectCursor CURSOR FAST_FORWARD FOR
SELECT QUOTENAME(SCHEMA_NAME(o.schema_id)) + '.' + QUOTENAME(OBJECT_NAME(o.object_id))
FROM sys.objects o
WHERE type_desc IN (
'SQL_STORED_PROCEDURE',
'SQL_TRIGGER',
'SQL_SCALAR_FUNCTION',
'SQL_TABLE_VALUED_FUNCTION',
'SQL_INLINE_TABLE_VALUED_FUNCTION',
'VIEW')
--include the following if you have schema bound objects since they are not supported
AND ISNULL(OBJECTPROPERTY(o.object_id, 'IsSchemaBound'), 0) = 0
;
OPEN ObjectCursor;
FETCH NEXT FROM ObjectCursor INTO @Name;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Sql = N'EXEC sp_refreshsqlmodule ''' + @Name + '''';
--PRINT @Sql;
BEGIN TRY
EXEC @Result = sp_executesql @Sql;
IF @Result <> 0 RAISERROR('Failed', 16, 1);
END TRY
BEGIN CATCH
PRINT 'The module ''' + @Name + ''' does not compile.';
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
END CATCH
FETCH NEXT FROM ObjectCursor INTO @Name;
END
CLOSE ObjectCursor;
DEALLOCATE ObjectCursor;
回答2:
It won't catch everything (dynamic SQL or latebound objects), but it can be useful - call sp_refreshsqlmodule on all non-schema bound stored procedures (you can call it before to ensure that dependencies are updated and then query the dependencies, or call it afterwards and see if anything is broken):
DECLARE @template AS varchar(max)
SET @template = 'PRINT ''{OBJECT_NAME}''
EXEC sp_refreshsqlmodule ''{OBJECT_NAME}''
'
DECLARE @sql AS varchar(max)
SELECT @sql = ISNULL(@sql, '') + REPLACE(@template, '{OBJECT_NAME}',
QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME))
FROM INFORMATION_SCHEMA.ROUTINES
WHERE OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') IS NULL
OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') = 0
EXEC (
@sql
)
回答3:
I basically did the same thing, but wrote it to be CURSORless which is super fast.
DECLARE @Name nvarchar(1000);
DECLARE @Sql nvarchar(1000);
DECLARE @Result int;
DECLARE @Objects TABLE (
Id INT IDENTITY(1,1),
Name nvarchar(1000)
)
INSERT INTO @Objects
SELECT QUOTENAME(SCHEMA_NAME(o.schema_id)) + '.' + QUOTENAME(OBJECT_NAME(o.object_id))
FROM sys.objects o
WHERE type_desc IN (
'SQL_STORED_PROCEDURE',
'SQL_TRIGGER',
'SQL_SCALAR_FUNCTION',
'SQL_TABLE_VALUED_FUNCTION',
'SQL_INLINE_TABLE_VALUED_FUNCTION',
'VIEW')
--include the following if you have schema bound objects since they are not supported
AND ISNULL(OBJECTPROPERTY(o.object_id, 'IsSchemaBound'), 0) = 0
DECLARE @x INT
DECLARE @xMax INT
SELECT @xMax = MAX(Id) FROM @Objects
SET @x = 1
WHILE @x < @xMax
BEGIN
SELECT @Name = Name FROM @Objects WHERE Id = @x
SET @Sql = N'EXEC sp_refreshsqlmodule ''' + @Name + '''';
--PRINT @Sql;
BEGIN TRY
EXEC @Result = sp_executesql @Sql;
IF @Result <> 0 RAISERROR('Failed', 16, 1);
END TRY
BEGIN CATCH
PRINT 'The module ''' + @Name + ''' does not compile.';
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
END CATCH
SET @x = @x + 1
END
回答4:
In addition to the script from Michael Petito you can check for issues with late-bound objects in SPs (deferred name resolution) like this:
-- Based on comment from http://blogs.msdn.com/b/askjay/archive/2012/07/22/finding-missing-dependencies.aspx
-- Check also http://technet.microsoft.com/en-us/library/bb677315(v=sql.110).aspx
select o.type, o.name, ed.referenced_entity_name, ed.is_caller_dependent
from sys.sql_expression_dependencies ed
join sys.objects o on ed.referencing_id = o.object_id
where ed.referenced_id is null
回答5:
Couple of ways that come to mind
- Most obvious way run the procedures
- check dependencies on the table before you drop the table or a field. then check out those dependent proceudres
- generate scripts on all procedures and search for that field or table
- Query sysobjects
回答6:
I tried "Cade Roux" Answer , it went wrong and I fixed it as following
SELECT 'BEGIN TRAN T1;' UNION
SELECT REPLACE('BEGIN TRY
EXEC sp_refreshsqlmodule ''{OBJECT_NAME}''
END TRY
BEGIN CATCH
PRINT ''{OBJECT_NAME} IS INVALID.''
END CATCH', '{OBJECT_NAME}',
QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME))
FROM INFORMATION_SCHEMA.ROUTINES
WHERE OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') IS NULL
OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') = 0
UNION
SELECT 'ROLLBACK TRAN T1;'
回答7:
Same idea, but more universal - you check all user defined objects with bodies And it shows you error during compiling. This is really useful after renaming/removing objects/columns etc
Just run it after database schema update to make sure that all body objects still valid
DECLARE @obj_name AS sysname, @obj_type AS sysname
DECLARE obj_cursor CURSOR FOR
SELECT SCHEMA_NAME(o.schema_id) + '.' + o.name, o.type_desc
FROM sys.objects o
INNER JOIN sys.sql_modules m ON o.object_id = m.object_id
WHERE o.is_ms_shipped = 0 AND m.is_schema_bound = 0
ORDER BY o.type_desc, SCHEMA_NAME(o.schema_id), o.name
OPEN obj_cursor
FETCH NEXT FROM obj_cursor INTO @obj_name, @obj_type
WHILE (@@FETCH_STATUS <> -1)
BEGIN
BEGIN TRY
EXEC sp_refreshsqlmodule @obj_name
--PRINT 'Refreshing ''' + @obj_name + ''' completed'
END TRY
BEGIN CATCH
PRINT 'ERROR - ' + @obj_type + ' ''' + @obj_name + ''':' + ERROR_MESSAGE()
END CATCH
FETCH NEXT FROM obj_cursor INTO @obj_name, @obj_type
END
CLOSE obj_cursor
DEALLOCATE obj_cursor