2008-09-10 47 views
20

Là một phần của chiến lược tích hợp của tôi, tôi có một vài tập lệnh SQL chạy để cập nhật cơ sở dữ liệu. Điều đầu tiên mà tất cả các tập lệnh này thực hiện là kiểm tra xem liệu chúng có cần chạy hay không, ví dụ:Làm cách nào để tạo điều kiện thủ tục được lưu trữ trong SQL Server?

if @version <> @expects 
    begin 
     declare @error varchar(100); 
     set @error = 'Invalid version. Your version is ' + convert(varchar, @version) + '. This script expects version ' + convert(varchar, @expects) + '.'; 
     raiserror(@error, 10, 1); 
    end 
else 
    begin 
     ...sql statements here... 
    end 

Hoạt động tuyệt vời! Ngoại trừ nếu tôi cần phải thêm một thủ tục được lưu trữ. Lệnh "create proc" phải là lệnh duy nhất trong một loạt lệnh sql. Đặt "proc tạo" trong câu lệnh IF của tôi gây ra lỗi này:

 
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch. 

Ouch! Làm thế nào để đặt lệnh CREATE PROC trong kịch bản của tôi, và nó chỉ thực thi nếu nó cần?

Trả lời

20

Đây là những gì tôi đã đưa ra:

Wrap nó trong một EXEC(), như vậy:

if @version <> @expects 
    begin 
     ...snip... 
    end 
else 
    begin 
     exec('CREATE PROC MyProc AS SELECT ''Victory!'''); 
    end 

trình như một say mê!

+2

Tạo lại procs mỗi lần (giảm điều kiện) là giải pháp tốt hơn nhiều.Nếu sử dụng exec, bạn không đạt được gì và có những nhược điểm; proc của bạn phải thoát khỏi chuỗi và bất kỳ số dòng nào trong các lỗi sẽ tham chiếu đến số dòng tương ứng với lệnh exec. – Peter

+0

+1 để có thể xử lý các điều kiện khác với sự tồn tại (trong trường hợp của tôi @@ Phiên bản ổ đĩa cho dù procs nào đó được tạo hay không) – cmsjr

+1

+1 - Tôi đã sử dụng cấu hình này để tạo cấu hình trình tạo CRUD của mình tồn tại, và _then_ thay đổi nó. Điều này cho phép tôi sửa đổi procs được lưu trữ của tôi, xây dựng CRUD nhưng _preserve bất kỳ quyền nào được gán cho procs_ hiện có. –

5

Nhưng hãy xem các dấu nháy đơn trong Thủ tục được lưu trữ của bạn - chúng cần phải được "thoát" bằng cách thêm dấu thứ hai. Câu trả lời đầu tiên đã làm điều này, nhưng chỉ trong trường hợp bạn bỏ lỡ nó. Một cái bẫy cho các cầu thủ trẻ.

+0

câu trả lời này phải là một nhận xét. Tại sao bạn không di chuyển nó ở đó? – Luiso

3

Phiên bản cơ sở dữ liệu của bạn là cách để đi, nhưng ... Tại sao có điều kiện tạo các thủ tục được lưu trữ. Đối với Chế độ xem, các thủ tục được lưu trữ, chức năng, chỉ có điều kiện thả chúng và tạo lại chúng mỗi lần. Nếu bạn có điều kiện tạo, thì bạn sẽ không dọn dẹp cơ sở dữ liệu có vấn đề hoặc hack đã được 2 năm trước bởi một nhà phát triển khác (bạn hoặc tôi sẽ không bao giờ làm điều này), người chắc chắn anh ta sẽ nhớ xóa một lần cập nhật khẩn cấp.

1

Tôi phải thừa nhận, tôi thường đồng ý với @Peter - Tôi có điều kiện thả và sau đó tái tạo vô điều kiện mỗi lần. Tôi đã bị bắt quá nhiều lần trong quá khứ khi cố gắng đoán hai sự khác nhau về lược đồ giữa các cơ sở dữ liệu, có hoặc không có bất kỳ dạng điều khiển phiên bản nào.

Có nói rằng, đề xuất của riêng bạn @Josh khá thú vị. Chắc chắn thú vị. :-)

0

Vấn đề với việc giảm và tạo là bạn mất bất kỳ khoản trợ cấp bảo mật nào trước đó đã được áp dụng cho đối tượng bị xóa.

+0

Nó chỉ là một vấn đề nếu bạn không còn lại thêm các khoản tài trợ sau khi thủ tục được tái tạo ;-). –

0
IF NOT EXISTS(SELECT * FROM sys.procedures WHERE name = 'pr_MyStoredProc') 
BEGIN 

    CREATE PROCEDURE pr_MyStoredProc AS ..... 
    SET NOCOUNT ON 
END 

ALTER PROC pr_MyStoredProc 
AS 
SELECT * FROM tb_MyTable 
0

sử dụng lệnh 'Hiện hữu' trong T-SQL để xem liệu tệp lưu trữ có tồn tại hay không. Nếu có, hãy sử dụng 'Thay đổi', nếu không hãy sử dụng 'Tạo'

0

Đây là một chuỗi cũ nhưng Jobo không chính xác: Tạo Thủ tục phải là câu lệnh đầu tiên trong một đợt. Do đó, bạn không thể sử dụng Exists để kiểm tra sự tồn tại và sau đó sử dụng Create hoặc Alter. Lòng thương hại.

+0

True :) (Btw, đó có lẽ là một bình luận, chứ không phải là một câu trả lời. Nhưng tôi hiểu bạn không thể "bình luận" được nêu ra;) – Leigh

4

SET noexec ON là cách tốt để tắt một số phần của mã

IF NOT EXISTS (SELECT * FROM sys.assemblies WHERE name = 'SQL_CLR_Functions') 
    SET NOEXEC ON 
GO 
CREATE FUNCTION dbo.CLR_CharList_Split(@list nvarchar(MAX), @delim nchar(1) = N',') 
RETURNS TABLE (str nvarchar(4000)) AS EXTERNAL NAME SQL_CLR_Functions.[Granite.SQL.CLR.Functions].CLR_CharList_Split 
GO 
SET NOEXEC OFF 

Tìm thấy ở đây: https://codereview.stackexchange.com/questions/10490/conditional-create-must-be-the-only-statement-in-the-batch

T.B. Một cách khác là SET PARSEONLY {ON | TẮT }.

Các vấn đề liên quan