2015-12-09 25 views
6

Chúng tôi có thể sử dụng GO lần mutiple tuyên bố trong một SQL Transaction. Tôi đang có một kịch bản T-SQL dài và tôi muốn chạy nó trong một SQL Transaction. Nếu mọi việc suôn sẻ thì tôi sẽ cam kết ngược lại.Chúng ta có thể sử dụng 'GO' nhiều lần trong Giao dịch SQL không?

Nhưng, khi chạy truy vấn đó, tôi gặp lỗi như 'create function must be the only statement in the batch'. Khi tôi đang tạo và bỏ nhiều chức năng và thủ tục trong đó.

Tôi chưa sử dụng GO ở bất kỳ đâu trong tập lệnh. Câu hỏi của tôi là - Tôi có thể sử dụng nhiều câu lệnh GO trong tập lệnh dài đó không. Bởi vì, GO tạo một lô và nếu lô thực thi thành công lần đầu tiên nhưng không thành công vào lần tiếp theo thì câu lệnh rollback transaction có thể thực sự khôi phục đã được thực thi không?

Cấu trúc kịch bản của tôi trông giống như:

PRINT 'Transaction Started' 
BEGIN TRY 
    BEGIN TRAN 

    Drop Function 
    .... 
    .... 
    Create Function 
    .... 
    .... 
    Drop Procedure 
    .... 
    .... 
    Lots of statements 
    .... 
    .... 

    COMMIT TRAN 
    PRINT 'Transaction Succeeded' 
END TRY 
BEGIN CATCH 
    PRINT 'Transaction Failed' 
    IF(@@TRANCOUNT > 0) 
     ROLLBACK TRAN 
END CATCH 

tôi đang tạo ra kịch bản này để di chuyển một số thay đổi từ newdb để oldDB trong một kịch bản duy nhất.

+0

Bạn tạo ra một thủ tục lưu trữ hoặc chức năng trong kịch bản này? – Dane

+0

Tôi đã cập nhật câu trả lời của mình. Dù sao..Tôi đang tạo và thả cả hai. Đầu tiên kiểm tra xem chúng có tồn tại hay không. –

+0

Hãy thử câu trả lời này tại đây: http://stackoverflow.com/a/11121382/249813 – JamesT

Trả lời

16

Bạn đang trộn các khái niệm. GO không phải là khái niệm Giao dịch-SQL, không phải là một phần của ngôn ngữ và không được SQL Server hiểu. GO là công cụ phân tách hàng loạt. sqlcmd.exe và SSMS đều đang sử dụng theo mặc định, GO làm dấu tách hàng loạt. Dấu tách hàng loạt được sử dụng để xác định các lô hàng riêng lẻ bên trong tệp nguồn SQL. Công cụ khách hàng gửi đến máy chủ một lô tại một thời điểm (tất nhiên, bỏ qua dấu phân tách).

Giao dịch có thể mở rộng lô. TRY/CATCH khối không thể. Các câu lệnh CREATE/ALTER phải là câu lệnh duy nhất trong một loạt (các chú thích không phải là các câu lệnh, và các câu lệnh chứa trong một thân thể thủ tục hàm là, được, chứa).

Điều gì đó tương tự với những gì bạn muốn làm có thể đạt được bằng cách bắt đầu giao dịch và hủy bỏ việc thực thi trên lỗi đầu tiên (-b tại sqlcmd.exe bắt đầu hoặc sử dụng :on error exit in SSMS).

Nhưng thực hiện DDL bên trong các giao dịch dài sẽ không hoạt động. Đặc biệt nếu bạn định trộn nó với DML. Hầu hết các sự cố tham nhũng tôi phải điều tra đến từ kết hợp này (Xact, DDL + DML, rollback). Tôi khuyên bạn nên chống lại nó.

Cách duy nhất để triển khai các bản cập nhật lược đồ một cách an toàn là thực hiện sao lưu, triển khai, khôi phục từ bản sao lưu nếu có sự cố.

Lưu ý rằng những gì Dan đề xuất (SQL động) hoạt động bởi vì sp_executesql bắt đầu một gói, bên trong, mới. Lô này sẽ đáp ứng các hạn chế CREATE/ALTER.

+0

giải thích tuyệt vời. gợi ý tuyệt vời. cảm ơn rất nhiều @Remus !! –

1

GO là từ khóa tốt để sử dụng. GO sẽ hoàn thành khối mã cuối cùng và tiếp tục đến khối tiếp theo. Có, bạn có thể sử dụng nhiều GO trong một câu lệnh để chia nhỏ thành nhiều đợt. Nhưng sẽ tốt hơn nếu sử dụng logic try/catch với sự kết hợp GOs vì bạn đang làm logic dựa trên giao dịch. https://msdn.microsoft.com/en-us/library/ms175976.aspx trang web này cung cấp cho bạn một số ví dụ về cuốc để sử dụng và nếu bạn gặp khó khăn, bạn có thể xuất ra lỗi đó và tiếp tục nếu bạn chọn.

2

Lưu ý rằng GO is not a SQL keyword. Nó là một bộ tách hàng phía máy khách được sử dụng bởi SQL Server Management Studio và các công cụ máy khách khác.

GO không ảnh hưởng đến phạm vi giao dịch. BEGIN TRAN sẽ bắt đầu giao dịch trên kết nối hiện tại. COMMIT và ROLLBACK sẽ kết thúc giao dịch. Bạn có thể thực hiện nhiều câu lệnh như bạn muốn ở giữa. GO sẽ thực thi các câu lệnh một cách riêng biệt.

Như quy định của MSDN:

Một TRY ... CATCH xây dựng không thể span nhiều lô.

Vì vậy, BEGIN TRY, END TRY, BEGIN CATCH và END CATCH không thể được phân tách thành các lô riêng biệt bằng trình tách GO. Chúng phải xuất hiện trong cùng một truy vấn.

Nếu bạn cố gắng bao gồm một tách hàng loạt trong một tuyên bố try/catch như SQL hợp lệ dưới đây:

begin try 
    go 
end try 
begin catch 
    go 
end catch 

này sẽ thực hiện 3 truy vấn khác nhau mà trở về lỗi cú pháp:

1) begin try

Msg 102, Level 15, State 1, Line 1 
Incorrect syntax near 'begin'. 

2) end try begin catch

Msg 102, Level 15, State 1, Line 3 
Incorrect syntax near 'try'. 

3) end catch

Msg 102, Level 15, State 1, Line 6 
Incorrect syntax near 'catch'. 
Các vấn đề liên quan