Syntax check all stored procedures?

前端 未结 9 1915
情话喂你
情话喂你 2020-12-04 22:51

i want to ensure that all stored procedures are still syntactically valid. (This can happen if someone renames/deletes a table/column).

Right now my solution to chec

相关标签:
9条回答
  • 2020-12-04 22:54

    Here is an amendment which deals with multiple schemas

    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    ALTER PROCEDURE [dbo].[RefreshAllViews] AS
    
    -- This sp will refresh all views in the catalog. 
    --     It enumerates all views, and runs sp_refreshview for each of them
    
    DECLARE abc CURSOR FOR
         SELECT TABLE_SCHEMA+'.'+TABLE_NAME AS ViewName
         FROM INFORMATION_SCHEMA.VIEWS
    OPEN abc
    
    DECLARE @ViewName varchar(128)
    
    -- Build select string
    DECLARE @SQLString nvarchar(2048)
    
    FETCH NEXT FROM abc 
    INTO @ViewName
    WHILE @@FETCH_STATUS = 0 
    BEGIN
        SET @SQLString = 'EXECUTE sp_RefreshView ['+@ViewName+']'
        PRINT @SQLString
        EXECUTE sp_ExecuteSQL @SQLString
    
        FETCH NEXT FROM abc
        INTO @ViewName
    END
    CLOSE abc
    DEALLOCATE abc
    GO
    
    0 讨论(0)
  • 2020-12-04 22:55

    I know this is a old question but this is my solution when I could not find any suiting.

    I required to validate my stored procedures and views after alot of changes in the database.

    Basicly what i wanted was to try to do a ALTER PROCEDURE and ALTER VIEW using the current procedures and view (not actually changing them).

    I have written this that works fairly well.

    Note! Do not perform on live database, make a copy to validate and then fix the things need fixing. Also sys.sql_modules can be inconsistent so take extra care. I do not use this to actually make the changes, only to check which are not working properly.

    DECLARE @scripts TABLE
    (
        Name NVARCHAR(MAX),
        Command NVARCHAR(MAX),
        [Type] NVARCHAR(1)
    )
    
    DECLARE @name NVARCHAR(MAX),        -- Name of procedure or view
        @command NVARCHAR(MAX),         -- Command or part of command stored in syscomments
        @type NVARCHAR(1)               -- Procedure or view
    
    INSERT INTO @scripts(Name, Command, [Type])
    SELECT P.name, M.definition, 'P' FROM sys.procedures P 
    JOIN sys.sql_modules M ON P.object_id = M.object_id
    
    INSERT INTO @scripts(Name, Command, [Type])
    SELECT V.name, M.definition, 'V' FROM sys.views V 
    JOIN sys.sql_modules M ON V.object_id = M.object_id
    
    DECLARE curs CURSOR FOR
    SELECT Name, Command, [Type]  FROM @scripts
    
    OPEN curs
    
    FETCH NEXT FROM curs
    INTO @name, @command, @type
    
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        BEGIN TRY
            IF @type = 'P'
                SET @command = REPLACE(@command, 'CREATE PROCEDURE', 'ALTER PROCEDURE')
            ELSE
                SET @command = REPLACE(@command, 'CREATE VIEW', 'ALTER VIEW')
    
    
            EXEC sp_executesql @command
            PRINT @name + ' - OK'
        END TRY
        BEGIN CATCH
            PRINT @name + ' - FAILED: ' + CAST(ERROR_NUMBER() AS NVARCHAR(MAX)) + ' ' + ERROR_MESSAGE()
            --PRINT @command
        END CATCH
    
        FETCH NEXT FROM curs
        INTO @name, @command, @type
    END
    
    CLOSE curs 
    
    0 讨论(0)
  • 2020-12-04 22:55

    A bit of a drawn-out option:

    1. Create a copy of the database (backup and restore). You could do this on the target database, if your confidence level is high.
    2. Use SSMS to script out all the stored procedures into a single script file
    3. DROP all the procedures
    4. Run the script to recreate them. Any that can't be created will error out.

    Couple of fussy gotchas in here, such as:

    • You want to have the "if proc exists then drop proc GO create proc ... GO" syntax to separte each procedure.
    • Nested procedures will fail if they call a proc that has not yet been (re)created. Running the script several times should catch that (since ordering them properly can be a real pain).
    • Other and more obscure issues might crop up, so be wary.

    To quickly drop 10 or 1000 procedures, run

    SELECT 'DROP PROCEDURE ' + schema_name(schema_id) + '.' +  name
     from sys.procedures
    

    select the output, and run it.

    This assumes you're doing a very infrequent task. If you have to do this regularly (daily, weekly...), please let us know why!

    0 讨论(0)
  • 2020-12-04 22:58

    I know this is way old, but I created a slightly different version that actually re-creates all stored procedures, thus throwing errors if they cannot compile. This is something you do not achieve by using the SP_Recompile command.

    CREATE PROCEDURE dbo.UTL_ForceSPRecompilation
    (
        @Verbose BIT = 0
    )
    AS
    BEGIN
    
        --Forces all stored procedures to recompile, thereby checking syntax validity.
    
        DECLARE @SQL NVARCHAR(MAX)
        DECLARE @SPName NVARCHAR(255)           
    
        DECLARE abc CURSOR FOR
             SELECT NAME, OBJECT_DEFINITION(o.[object_id])
             FROM sys.objects AS o 
             WHERE o.[type] = 'P'
             ORDER BY o.[name]
    
        OPEN abc
    
        FETCH NEXT FROM abc
        INTO @SPName, @SQL
        WHILE @@FETCH_STATUS = 0 
        BEGIN       
    
            --This changes "CREATE PROCEDURE" to "ALTER PROCEDURE"
            SET @SQL = 'ALTER ' + RIGHT(@SQL, LEN(@SQL) - (CHARINDEX('CREATE', @SQL) + 6))
    
            IF @Verbose <> 0 PRINT @SPName
    
            EXEC(@SQL)
    
            FETCH NEXT FROM abc
            INTO @SPName, @SQL
        END
        CLOSE abc
        DEALLOCATE abc  
    
    END
    
    0 讨论(0)
  • 2020-12-04 23:02

    In addition you might want to consider using Visual Studio Team System 2008 Database Edition which, among other things, does a static verification of all stored procedures in the project on build, thus ensuring that all are consistent with the current schema.

    0 讨论(0)
  • 2020-12-04 23:04

    The check suggested by KenJ is definitely the best one, since the recreate/alter-approaches does not find all errors. E.g.

    • impossible execution plans due to query-hints
    • I even had an SP referencing a non-existing table that went through without the error being detected.

    Please find my version that checks all existing SPs at once with KenJ's method below. AFAIK, it will detect every error that will keep the SP from being executed.

    --Forces the creation of execution-plans for all sps.
    --To achieve this, a temporary SP is created that calls all existing SPs.
    --It seems like the simulation of the parameters is not necessary. That makes things a lot easier.
    DECLARE @stmt NVARCHAR(MAX) = 'CREATE PROCEDURE pTempCompileTest AS ' + CHAR(13) + CHAR(10)
    SELECT @stmt = @stmt + 'EXEC [' + schemas.name + '].[' + procedures.name + '];'
        FROM sys.procedures
            INNER JOIN sys.schemas ON schemas.schema_id = procedures.schema_id
        WHERE schemas.name = 'dbo'
        ORDER BY procedures.name
    
    EXEC sp_executesql @stmt
    GO
    
    --Here, the real magic happens.
    --In order to display as many errors as possible, XACT_ABORT is turned off.
    --Unfortunately, for some errors, the execution stops anyway.
    SET XACT_ABORT OFF
    GO
    --Showplan disables the actual execution, but forces t-sql to create execution-plans for every statement.
    --This is the core of the whole thing!
    SET SHOWPLAN_ALL ON
    GO
    --You cannot use dynamic SQL in here, since sp_executesql will not be executed, but only show the string passed in in the execution-plan
    EXEC pTempCompileTest
    GO
    SET SHOWPLAN_ALL OFF
    GO
    SET XACT_ABORT ON
    GO
    --drop temp sp again
    DROP PROCEDURE pTempCompileTest
    --If you have any errors in the messages-window now, you should fix these...
    
    0 讨论(0)
提交回复
热议问题