0

我正在做一些模式迁移,并且想知道是否可以或可取地运行我的数据库中的每个存储过程、视图和函数作为更改语句来“编译”它们,以确保没有什么是完全的破碎的。

4

1 回答 1

0

好吧,我建立了一个存储过程来做到这一点,不是很优雅,但希望其他人会发现它很有用:

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
于 2010-05-07T04:40:00.787 回答