I'm in the course of doing some schema migrations, and would like to know if it's possible or advis开发者_StackOverflow社区able to run every stored procedure, view and function in my database as an alter statement to "compile" them all to make sure nothing is completely broken.
Well, I built a sproc to do this, not very elegant, but hopefully someone else will find it useful:
CREATE PROCEDURE [dbo].[UTIL_RunAlterOnAll]
@debugMessages BIT = 0
AS
BEGIN
BEGIN TRAN
SET NOCOUNT ON
DECLARE @allAlterTexts TABLE (name VARCHAR(256), alterText NVARCHAR(MAX), id INT, type CHAR(2))
DECLARE @rowsInError TABLE (errorMessage NVARCHAR(2048), errorNumber INT, name VARCHAR(256), alterText NVARCHAR(MAX), id INT, type CHAR(2))
;WITH Texts AS
(
SELECT o.name, o.type, sm.definition AS text, o.id
FROM sysobjects AS o
INNER JOIN sys.sql_modules AS sm
ON sm.object_id = o.id
WHERE o.type IN ('P', 'V', 'FN')
)
INSERT INTO @allAlterTexts (name, alterText, id, type)
SELECT name, alterStatement, id, type
FROM
(
SELECT name, REPLACE(text, 'CREATE PROCEDURE', 'ALTER PROCEDURE') AS alterStatement, id, type
FROM Texts AS procs
WHERE procs.type = 'P'
UNION ALL
SELECT name, REPLACE(text, 'CREATE VIEW', 'ALTER VIEW') AS alterStatement, id, type
FROM Texts AS procs
WHERE procs.type = 'V'
UNION ALL
SELECT name, REPLACE(text, 'CREATE FUNCTION', 'ALTER FUNCTION') AS alterStatement, id, type
FROM Texts AS procs
WHERE procs.type = 'FN'
) AS allAlters
DECLARE curs CURSOR FORWARD_ONLY
FOR
SELECT *
FROM @allAlterTexts
DECLARE @name VARCHAR(MAX)
, @alterText VARCHAR(MAX)
, @id INT
, @type VARCHAR(2)
OPEN curs
FETCH NEXT FROM curs
INTO @name, @alterText, @id, @type
WHILE @@FETCH_STATUS = 0
BEGIN
IF @debugMessages = 1
BEGIN
PRINT 'Alter text for @name'
PRINT '-----'
PRINT @alterText
PRINT '-----'
END
BEGIN TRY
IF @debugMessages = 1
BEGIN
PRINT 'Running ' + @name
END
EXEC(@alterText)
IF @debugMessages = 1
BEGIN
PRINT 'Success'
END
END TRY
BEGIN CATCH
IF @debugMessages = 1
BEGIN
PRINT 'ERROR!'
PRINT ERROR_MESSAGE()
PRINT '----'
PRINT 'Text:'
PRINT @alterText
END
INSERT INTO @rowsInError (errorMessage, errorNumber, name, alterText, id, type)
VALUES(LTRIM(RTRIM(ERROR_MESSAGE())), ERROR_NUMBER(), @name, @alterText, @id, @type)
END CATCH
IF @debugMessages = 1
BEGIN
PRINT '-----'
END
FETCH NEXT FROM curs
INTO @name, @alterText, @id, @type
END
CLOSE curs
DEALLOCATE curs
SET NOCOUNT OFF
-- WTF? 3930 means transaction error, these get raised whenever another error is raised,
-- as the transaction is set to invalid
SELECT *
FROM @rowsInError
WHERE errorNumber != 3930
ORDER BY name
ROLLBACK TRAN
END
GO
精彩评论