2009-07-24 55 views
16

我想確保所有存儲過程仍然在語法上有效。 (如果有人重命名/刪除表/列,可能會發生這種情況。語法檢查所有存儲過程?

現在我的解決方案,以檢查所有存儲過程的語法是進入企業管理器,在列表中選擇第一個存儲過程,並使用過程:

  1. 輸入
  2. Alt + C鍵
  3. 逃逸
  4. 逃逸
  5. 向下箭頭
  6. 轉到第1

它的工作原理,但它是相當繁瑣的。我想調用的存儲過程

SyntaxCheckAllStoredProcedures

像其他存儲過程,我寫的確實爲享有同樣的事情:

RefreshAllViews


大家的受益,RefreshAllViews:

RefreshAllViews.prc

CREATE 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_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 '[email protected] 
    PRINT @SQLString 
    EXECUTE sp_ExecuteSQL @SQLString 

    FETCH NEXT FROM abc 
    INTO @ViewName 
END 
CLOSE abc 
DEALLOCATE abc 

爲了大家的利益,一個存儲過程來標記所有存儲過程作爲需要重新編譯(標記爲重新編譯不會告訴你,如果它是語法上有效的存儲過程):

RecompileAllStoredProcedures.prc

CREATE PROCEDURE dbo.RecompileAllStoredProcedures AS 

DECLARE abc CURSOR FOR 
    SELECT ROUTINE_NAME 
    FROM INFORMATION_SCHEMA.routines 
    WHERE ROUTINE_TYPE = 'PROCEDURE' 
OPEN abc 

DECLARE @RoutineName varchar(128) 

-- Build select string once 
DECLARE @SQLString nvarchar(2048) 

FETCH NEXT FROM abc 
INTO @RoutineName 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    SET @SQLString = 'EXECUTE sp_recompile '[email protected] 
    PRINT @SQLString 
    EXECUTE sp_ExecuteSQL @SQLString 

    FETCH NEXT FROM abc 
    INTO @RoutineName 
END 
CLOSE abc 
DEALLOCATE abc 

爲了完整起見,UpdateAllStatistics過程。這將做一個完整的掃描數據更新數據庫中的所有統計信息:

RefreshAllStatistics.prc

CREATE PROCEDURE dbo.RefreshAllStatistics AS 

EXECUTE sp_msForEachTable 'UPDATE STATISTICS ? WITH FULLSCAN' 
+0

請留意您的標籤。這是標籤爲「sqlserver」的網站上的唯一問題。改用'sql-server'。 – 2009-07-24 13:29:57

回答

1

此外,你可能要考慮使用Visual Studio Team System 2008 Database Edition,除其他事情,做了靜態驗證所有存儲過程中的構建項目,從而確保所有存儲過程與當前模式一致。

+0

只有在Visual Studio或SQL Server 2008數據庫中進行開發時,我纔會這樣做。 – 2009-07-24 13:37:27

+0

@Ian是它只適用於visual studio,因爲它將使用特定的數據庫項目類型(更準確地說,您需要VS Team System),但它也適用於Sql Server 2005也 – Aleris 2009-07-24 14:40:35

0

一個漫長的選項的位:

  1. 創建數據庫 的拷貝(備份和恢復)。如果您的置信度很高,您可以在目標數據庫上執行此操作。
  2. 使用SSMS腳本了所有的 存儲過程轉換成一個單一的腳本文件
  3. 刪除所有程序
  4. 運行腳本來創建它們。任何無法創建的都會出錯。

夫婦在這裏繁瑣陷阱,如:

  • 你想擁有的, 「如果PROC存在 跌得PROC GO創建處理... GO」 語法separte每個過程。
  • 如果嵌套過程調用一個尚未被 (重新)創建的過程,它們將失敗。運行腳本幾個 時間應該趕上(因爲 正確的順序可以是一個真正的 疼痛)。
  • 其他更隱晦的問題可能會出現,所以要謹慎。

迅速下降10名或1000的程序,運行

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

選擇輸出,並運行它。

這假設你正在做一個非常罕見的任務。如果您必須定期(每日,每週...)進行此操作,請告訴我們爲什麼!

+0

是的 - 沒有辦法我丟棄存儲過程) – 2009-07-24 15:25:32

0

沒有辦法從T-SQL或企業管理器中完成它,所以我不得不從客戶端代碼編寫一些東西。我不會在這裏發佈的所有代碼,但訣竅是:

1)獲取的所有存儲過程

SELECT ROUTINE_NAME AS StoredProcedureName 
FROM INFORMATION_SCHEMA.ROUTINES 
WHERE ROUTINE_TYPE = 'PROCEDURE' --as opposed to a function 
ORDER BY ROUTINE_NAME 

2)列表獲取存儲過程創建T-SQL:

select 
    c.text 
from dbo.syscomments c 
where c.id = object_id(N'StoredProcedureName') 
order by c.number, c.colid 
option(robust plan) 

3)運行與NOEXEC創建語句,使語法檢查,但它實際上並沒有嘗試創建存儲過程:

connection("SET NOEXEC ON", ExecuteNoRecords); 
connection(StoredProcedureCreateSQL, ExecuteNoRecords); 
connection("SET NOEXEC ON", ExecuteNoRecords); 
+1

決定接受你的挑戰:D 不確定是否允許我們自我插入博客,但我在我的博客上發佈了完整的解決方案。事情原來很安靜。 [鏈接](http://chocosmith.wordpress.com/2012/12/07/tsql-recompile-all-views-and-stored-proceedures-and-check-for-error/) 我還沒有檢查反對截斷表,但我可以看到它是一個問題。 但我不認爲管理工作室可以得到正確的或者。 – 2013-01-04 09:43:11

7

您也可以「就地」完成此操作 - 無需獲取所有創建語句。

除了設置NOEXEC ON,你還需要設置你最喜歡的SHOWPLAN_* ON(我使用SHOWPLAN_TEXT)。現在,您可以擺脫第2步,並執行第1步中檢索的每個過程。

以下是使用單個存儲過程的示例。你可以將它變成你喜歡的循環:

create procedure tests @bob int as 
select * from missing_table_or_view 
go 

set showplan_text on; 
go 

set noexec on 

exec tests 

set noexec off 
go 
set showplan_XML off 
go 
drop procedure tests 
go 

上述樣品應生成以下的輸出:

消息208,級別16,狀態1,過程檢驗,2號線
無效的對象名稱'missing_table_or_view'。

1

我知道這是古老的,但我創建了一個稍微不同的版本,實際上重新創建所有存儲過程,因此如果他們無法編譯會引發錯誤。這是通過使用SP_Recompile命令無法實現的。

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

工作正常,但也需要處理`CREATE PROC` – 2015-10-20 10:31:26

3

如果您使用的是SQL 2008 R2或以下則不要使用

SET NOEXEC ON

只檢查語法,而不是像表或列中存在潛在錯誤。 而是使用:

SET FMTONLY ON

它會做一個完整的編譯,因爲它試圖返回存儲過程的元數據。

2012年,你將需要使用存儲過程: sp_describe_first_result_set

,你也可以做在TSQL一個完整的腳本,檢查所有的SP和看法,它只是一個工作位。

UPDATE 我在tsql中編寫了一個完整的解決方案,它貫穿所有用戶定義的存儲過程並檢查那裏的語法。腳本長篇大論,但可以在這裏找到http://chocosmith.wordpress.com/2012/12/07/tsql-recompile-all-views-and-stored-proceedures-and-check-for-error/

0

這裏是一個修正案,以多種模式

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 ['[email protected]+']' 
    PRINT @SQLString 
    EXECUTE sp_ExecuteSQL @SQLString 

    FETCH NEXT FROM abc 
    INTO @ViewName 
END 
CLOSE abc 
DEALLOCATE abc 
GO 
0

我知道這是一個老問題涉及但這是我的解決方案時,我找不到任何花呢。

我需要驗證我的存儲過程和視圖後數據庫中的很多變化。

基本上我想要的是嘗試使用當前過程和視圖(而不是實際更改它們)來執行ALTER PROCEDURE和ALTER VIEW。

我寫了這個工作得很好。

注意!不要在實時數據庫上執行,使副本驗證,然後修復需要修復的內容。另外sys.sql_modules可能不一致,所以要格外小心。我不用這個來實際進行更改,只是爲了檢查哪些不能正常工作。

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 
2

通過KenJ建議的檢查肯定是最好的一個,因爲重新創建/修改的辦法沒有發現的所有錯誤。例如。

  • 不可能執行計劃由於查詢提示
  • 我甚至有一個SP引用該經歷而不被發現的錯誤不存在的表。

請查看我的版本,它使用KenJ的方法一次檢查所有現有的SP。 AFAIK,它會檢測到每一個會阻止SP執行的錯誤。

--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...