2009-07-24 25 views
16

tôi muốn đảm bảo rằng tất cả các thủ tục được lưu trữ vẫn còn hợp lệ về cú pháp. (Điều này có thể xảy ra nếu ai đó đổi tên/xóa bảng/cột).Cú pháp kiểm tra tất cả các thủ tục đã lưu?

Ngay bây giờ giải pháp của tôi để kiểm tra cú pháp của tất cả các thủ tục lưu trữ là để đi vào Enterprise Manager, chọn thủ tục lưu trữ đầu tiên trong danh sách, và sử dụng thủ tục:

  1. Nhập
  2. Alt + C
  3. thoát
  4. thoát
  5. Down arrow
  6. Chuyển đến 1

Nó hoạt động, nhưng nó khá tẻ nhạt. tôi muốn một stored procedure gọi

SyntaxCheckAllStoredProcedures

như thủ tục lưu trữ khác tôi đã viết rằng làm điều tương tự cho quan điểm:

RefreshAllViews


Đối với tất cả mọi người lợi ích, 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 

Đối với lợi ích của mọi người, một thủ tục lưu trữ để đánh dấu tất cả các thủ tục lưu trữ như cần một biên dịch lại (đánh dấu một thủ tục lưu trữ cho biên dịch lại sẽ không cho bạn biết nếu nó là cú pháp hợp lệ):

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 

Vì mục đích đầy đủ, quy trình UpdateAllStatistics. Điều này sẽ cập nhật tất cả thống kê trong cơ sở dữ liệu bằng cách thực hiện một dữ liệu đầy đủ quét:

RefreshAllStatistics.prc

CREATE PROCEDURE dbo.RefreshAllStatistics AS 

EXECUTE sp_msForEachTable 'UPDATE STATISTICS ? WITH FULLSCAN' 
+0

Vui lòng xem gắn thẻ của bạn. Đây là câu hỏi _only_ trên trang web được gắn thẻ 'sqlserver'. Sử dụng 'sql-server' để thay thế. –

Trả lời

1

Bên cạnh đó bạn có thể muốn xem xét sử dụng Visual Studio Team System 2008 Database Edition đó, trong số những thứ khác, không xác minh tĩnh của tất cả các thủ tục được lưu trữ trong dự án xây dựng, do đó đảm bảo rằng tất cả đều phù hợp với lược đồ hiện tại.

+0

Điều đó chỉ hoạt động, tôi giả sử, nếu bạn đang phát triển trong Visual Studio, hoặc chống lại một cơ sở dữ liệu SQL Server 2008? –

+0

@ Có thể nó chỉ hoạt động với studio trực quan vì nó sẽ sử dụng loại dự án cơ sở dữ liệu cụ thể (chính xác hơn bạn cần VS Team System), nhưng nó hoạt động với Sql Server 2005 cũng – Aleris

0

Một chút một lựa chọn rút ra:

  1. Tạo một bản sao của cơ sở dữ liệu (sao lưu và khôi phục). Bạn có thể làm điều này trên cơ sở dữ liệu đích, nếu mức độ tin cậy của bạn cao.
  2. Sử dụng SSMS kịch bản ra tất cả các thủ tục được lưu trữ vào một tập tin script đơn
  3. thả tất cả các thủ tục
  4. Chạy kịch bản để tái tạo chúng. Mọi thứ không thể tạo ra sẽ bị lỗi.

Couple gotchas kén chọn ở đây, chẳng hạn như:

  • Bạn muốn có "nếu proc tồn tại sau đó thả proc GO tạo proc ... GO" cú pháp để separte mỗi thủ tục.
  • Quy trình lồng nhau sẽ không thành công nếu họ gọi một proc chưa được tạo (lại) được tạo. Chạy kịch bản một số lần sẽ bắt được (kể từ khi đặt hàng chúng đúng cách có thể là một nỗi đau thực sự ).
  • Các vấn đề khác và ít người biết đến hơn có thể tăng lên, vì vậy hãy cảnh giác.

Để nhanh chóng thả 10 hay 1000 thủ tục, chạy

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

chọn đầu ra, và chạy nó.

Giả định bạn đang thực hiện một nhiệm vụ rất không thường xuyên. Nếu bạn phải làm điều này thường xuyên (hàng ngày, hàng tuần ...), vui lòng cho chúng tôi biết lý do!

+0

Vâng - không có cách nào tôi đang xóa các thủ tục lưu sẵn trên cơ sở dữ liệu trực tiếp;) –

0

Không có cách nào để làm điều đó từ T-SQL, hoặc Enterprise Manager, vì vậy tôi đã phải viết một cái gì đó từ mã khách hàng. tôi sẽ không gửi tất cả các mã ở đây, nhưng thủ đoạn này là:

1) Nhận một danh sách của tất cả các thủ tục lưu trữ

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

2) Lấy stored procedure tạo 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) Chạy tạo tuyên bố với noexec trên, vì vậy mà cú pháp sẽ được kiểm tra, nhưng nó không thực sự cố gắng để tạo ra các thủ tục lưu trữ:

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

Quyết định chấp nhận thách thức của bạn: D không chắc chắn liệu chúng tôi có được phép tự cắm blog hay không nhưng tôi đã đăng giải pháp hoàn chỉnh lên blog của mình. Hóa ra nó rất yên tĩnh. [link] (http://chocosmith.wordpress.com/2012/12/07/tsql-recompile-all-views-and-stored-proceedures-and-check-for-error/) Tôi chưa chọn chống truncate bảng mặc dù nhưng tôi có thể nhìn thấy nó là một vấn đề. Tôi không nghĩ rằng studio quản lý được điều chỉnh chính xác. –

7

Bạn cũng có thể làm điều này "tại chỗ" - mà không nhận được tất cả các câu lệnh tạo.

Ngoài cài đặt NOEXEC ON, bạn cũng cần đặt SHOWPLAN_* ON yêu thích của mình (Tôi sử dụng SHOWPLAN_TEXT). Bây giờ bạn có thể loại bỏ bước 2 của bạn và chỉ thực hiện từng quy trình bạn đã truy xuất ở bước 1.

Đây là mẫu sử dụng quy trình được lưu trữ riêng lẻ. Bạn có thể làm việc nó vào vòng lặp của bạn yêu thích:

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 

Các mẫu ở trên sẽ tạo ra kết quả như sau:

Msg 208, Level 16, State 1, kiểm tra thủ tục, Dòng 2
tên đối tượng không hợp lệ 'missing_table_or_view'.

1

Tôi biết đây là cách cũ, nhưng tôi đã tạo một phiên bản hơi khác thực sự tạo lại tất cả các thủ tục được lưu trữ, do đó sẽ ném lỗi nếu chúng không thể biên dịch được. Đây là một cái gì đó bạn không đạt được bằng cách sử dụng lệnh 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

Hoạt động tốt, nhưng cần xử lý 'TẠO THỦ TỤC 'quá –

3

Nếu bạn đang sử dụng SQL 2008 R2 hoặc dưới đây sau đó không sử dụng

SET noexec ON

Nó chỉ kiểm tra cú pháp và không cho các lỗi tiềm ẩn như sự tồn tại của bảng hoặc cột. Thay vì sử dụng:

SET FMTONLY ON

nó sẽ làm một biên dịch đầy đủ như nó cố gắng để trả lại dữ liệu meta của thủ tục lưu trữ.

Đối với năm 2012 và bạn sẽ cần phải sử dụng thủ tục lưu trữ: sp_describe_first_result_set

Ngoài ra bạn có thể làm một kịch bản hoàn chỉnh trong TSQL để kiểm tra xem tất cả các sp và, nó chỉ là một chút công việc.

CẬP NHẬT Tôi đã viết giải pháp hoàn chỉnh cho tsql đi qua tất cả các thủ tục được lưu trữ do người dùng xác định và kiểm tra cú pháp đó. kịch bản được dài hơi nhưng có thể được tìm thấy ở đây http://chocosmith.wordpress.com/2012/12/07/tsql-recompile-all-views-and-stored-proceedures-and-check-for-error/

+0

Có ai đã thử' SET FMTONLY ON' (hoặc 'sp_describe_first_result_set') với' TRUNCATE TABLE CustomerAccounts' không? –

+2

@ChocoSmith Dành cho ** thủ tục được lưu trữ **, có hạn chế sử dụng sys.sp_refreshsqlmodule không? Tôi đã tìm thấy rằng nó sẽ bắt các thủ tục được lưu trữ mà không xếp hàng với các thay đổi của bảng hoặc lược đồ. – Question3CPO

+0

@ Question3CPO Điểm bắt/điểm tuyệt vời, fmtonly sẽ kiểm tra lược đồ cơ bản nhưng sp_refreshsqlmodule sẽ kiểm tra lược đồ hiện tại. sp_refreshsqlmodule cũng sẽ làm việc với các khung nhìn (giống như sp_refreshview gọi trên các khung nhìn). sp_refreshsqlmodule là một chút chậm hơn nhưng tôi không nghĩ rằng tốc độ nên được quan tâm khi nói đến các thủ tục lưu trữ bị hỏng :). Tôi sẽ kiểm tra nó tối nay và xem cập nhật có vi phạm gì không. –

0

Dưới đây là một sửa đổi trong đó giao dịch với nhiều 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 ['[email protected]+']' 
    PRINT @SQLString 
    EXECUTE sp_ExecuteSQL @SQLString 

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

Tôi biết đây là một câu hỏi cũ nhưng đây là giải pháp của tôi khi tôi không thể tìm thấy bất kỳ suiting .

Tôi bắt buộc phải xác thực các thủ tục và chế độ xem đã lưu trữ của mình sau nhiều thay đổi trong cơ sở dữ liệu.

Cơ bản những gì tôi muốn là cố gắng thực hiện ALTER PROCEDURE và ALTER VIEW bằng cách sử dụng quy trình và chế độ xem hiện tại (không thực sự thay đổi chúng).

Tôi đã viết điều này hoạt động khá tốt.

Lưu ý! Không thực hiện trên cơ sở dữ liệu trực tiếp, tạo một bản sao để xác thực và sau đó sửa chữa những thứ cần sửa. Ngoài ra sys.sql_modules có thể không phù hợp nên hãy cẩn thận hơn. Tôi không sử dụng điều này để thực sự thực hiện các thay đổi, chỉ để kiểm tra những gì không hoạt động đúng.

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

Kiểm tra được đề xuất bởi KenJ chắc chắn là tốt nhất, vì cách tiếp cận tạo lại/thay đổi không tìm thấy tất cả lỗi. Ví dụ.

  • kế hoạch thực hiện không thể do truy vấn-gợi ý
  • Tôi thậm chí đã có một SP tham khảo một bảng không tồn tại mà đã trải qua mà không có lỗi bị phát hiện.

Vui lòng tìm phiên bản của tôi kiểm tra tất cả SP hiện có cùng với phương pháp của KenJ bên dưới. AFAIK, nó sẽ phát hiện mọi lỗi sẽ giữ cho SP không bị thực hiện.

--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... 
Các vấn đề liên quan