Câu trả lời:
GO giống như phần cuối của một kịch bản.
Bạn có thể có nhiều câu lệnh CREATE TABLE, được phân tách bằng GO. Đó là một cách để cô lập một phần của tập lệnh với phần khác, nhưng gửi tất cả trong một khối.
BEGIN và END giống như {và} trong C / ++ / #, Java, v.v.
Họ ràng buộc một khối mã logic. Tôi có xu hướng sử dụng BEGIN và END khi bắt đầu và kết thúc một quy trình được lưu trữ, nhưng nó không hoàn toàn cần thiết ở đó. Trường hợp cần thiết là vòng lặp và câu lệnh IF, v.v., nơi bạn cần thêm thì một bước ...
IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
INSERT INTO Log SELECT @id, 'deleted'
DELETE my_table WHERE id = @id
END
Bạn cần BEGIN ... END để tạo một khối bao gồm nhiều câu lệnh. Vì vậy, nếu bạn muốn thực hiện 2 việc trong một 'chân' của câu lệnh IF hoặc nếu bạn muốn thực hiện nhiều hơn một việc trong phần nội dung của vòng lặp WHILE, bạn cần phải đặt các câu lệnh đó bằng BEGIN ... KẾT THÚC.
Từ khóa GO không phải là một phần của SQL. Nó chỉ được sử dụng bởi Trình phân tích truy vấn để chia tập lệnh thành "lô" được thực thi độc lập.
GO không phải là một từ khóa trong SQL Server; nó là một bộ tách hàng loạt. GO kết thúc một loạt các câu lệnh. Điều này đặc biệt hữu ích khi bạn đang sử dụng một thứ gì đó như SQLCMD. Hãy tưởng tượng bạn đang nhập các câu lệnh SQL trên dòng lệnh. Bạn không nhất thiết muốn điều đó thực thi mỗi khi bạn kết thúc một câu lệnh, vì vậy SQL Server sẽ không làm gì cho đến khi bạn nhập "GO".
Tương tự như vậy, trước khi lô của bạn bắt đầu, bạn thường cần hiển thị một số đối tượng. Ví dụ: giả sử bạn đang tạo một cơ sở dữ liệu và sau đó truy vấn nó. Bạn không thể viết:
CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;
vì foo không tồn tại cho lô mà TẠO BẢNG. Bạn cần làm điều này:
CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;
BEGIN và END đã được những người khác trả lời tốt.
Như Gary đã chỉ ra, GO là một bộ phân tách hàng loạt, được sử dụng bởi hầu hết các công cụ máy khách do Microsoft cung cấp, chẳng hạn như isql, sqlcmd, trình phân tích truy vấn và studio quản lý SQL Server. (Ít nhất một số công cụ cho phép thay đổi bộ tách lô. Tôi chưa bao giờ thấy việc sử dụng để thay đổi bộ tách lô.)
Để trả lời câu hỏi khi nào sử dụng GO, người ta cần biết khi nào thì SQL phải được tách thành các lô.
Một số câu lệnh phải là câu lệnh đầu tiên của một lô.
select 1
create procedure #Zero as
return 0
Trên SQL Server 2000, lỗi là:
Msg 111, Level 15, State 1, Line 3
'CREATE PROCEDURE' must be the first statement in a query batch.
Msg 178, Level 15, State 1, Line 4
A RETURN statement with a return value cannot be used in this context.
Trên SQL Server 2005, lỗi ít hữu ích hơn:
Msg 178, Level 15, State 1, Procedure #Zero, Line 5
A RETURN statement with a return value cannot be used in this context.
Vì vậy, sử dụng GO
để phân tách các câu lệnh phải là phần bắt đầu của một lô với các câu lệnh đứng trước nó trong một tập lệnh.
Khi chạy một tập lệnh, nhiều lỗi sẽ làm cho việc thực thi hàng loạt bị dừng lại, nhưng sau đó máy khách sẽ chỉ gửi đợt tiếp theo, việc thực thi tập lệnh sẽ không dừng lại. Tôi thường sử dụng điều này trong thử nghiệm. Tôi sẽ bắt đầu tập lệnh với bắt đầu giao dịch và kết thúc với khôi phục, thực hiện tất cả các thử nghiệm ở giữa:
begin transaction
go
... test code here ...
go
rollback transaction
Bằng cách đó, tôi luôn quay lại trạng thái bắt đầu, ngay cả khi lỗi xảy ra trong mã thử nghiệm, các câu lệnh giao dịch bắt đầu và khôi phục trở lại là một phần của các lô riêng biệt vẫn xảy ra. Nếu chúng không nằm trong các lô riêng biệt, thì lỗi cú pháp sẽ khiến giao dịch bắt đầu không xảy ra, vì một lô được phân tích cú pháp như một đơn vị. Và một lỗi thời gian chạy sẽ khiến quá trình khôi phục không xảy ra.
Ngoài ra, nếu bạn đang thực hiện cài đặt tập lệnh và có nhiều lô trong một tệp, lỗi trong một lô sẽ không giữ cho tập lệnh tiếp tục chạy, điều này có thể để lại một mớ hỗn độn. (Luôn sao lưu trước khi cài đặt.)
Liên quan đến những gì Dave Markel đã chỉ ra, có những trường hợp phân tích cú pháp sẽ không thành công vì SQL Server đang tìm kiếm trong từ điển dữ liệu cho các đối tượng được tạo trước đó trong lô, nhưng phân tích cú pháp có thể xảy ra trước khi chạy bất kỳ câu lệnh nào. Đôi khi đây là một vấn đề, đôi khi không. Tôi không thể đưa ra một ví dụ tốt. Nhưng nếu bạn gặp lỗi 'X không tồn tại', khi đó rõ ràng là lỗi sẽ tồn tại bởi câu lệnh đó sẽ chia thành nhiều đợt.
Và một lưu ý cuối cùng. Giao dịch có thể kéo dài hàng loạt. (Xem ở trên.) Các biến không mở rộng hàng loạt.
declare @i int
set @i = 0
go
print @i
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".
GO kết thúc một đợt, bạn chỉ rất hiếm khi cần sử dụng nó trong mã. Lưu ý rằng nếu bạn sử dụng nó trong một proc được lưu trữ, sẽ không có mã nào sau khi GO sẽ được thực thi khi bạn thực thi proc.
BEGIN và END là cần thiết cho bất kỳ câu lệnh kiểu thủ tục nào có nhiều dòng mã để xử lý. Bạn sẽ cần chúng cho các vòng lặp và con trỏ WHILE (tất nhiên là bạn sẽ tránh nếu có thể) và các câu lệnh IF (thực tế bạn không cần chúng cho một trạng thái IF chỉ có một dòng mã, nhưng sẽ dễ dàng hơn duy trì mã nếu bạn luôn đặt chúng sau IF). Các câu lệnh CASE cũng sử dụng END nhưng không có BEGIN.
Sau khi vật lộn với vấn đề này, ngày hôm nay ý kiến của tôi là: BEGIN ... END ngoặc mã giống như {....} trong ngôn ngữ C, ví dụ: khối mã cho if ... else và các vòng lặp
GO được sử dụng khi các câu lệnh kế tiếp dựa vào một đối tượng được xác định bởi một câu lệnh trước đó. Cơ sở dữ liệu USE là một ví dụ điển hình ở trên, nhưng những điều sau đây cũng sẽ khiến bạn khó chịu:
alter table foo add bar varchar(8);
-- if you don't put GO here then the following line will error as it doesn't know what bar is.
update foo set bar = 'bacon';
-- need a GO here to tell the interpreter to execute this statement, otherwise the Parser will lump it together with all successive statements.
Với tôi, có vẻ như vấn đề là thế này: Trình phân tích cú pháp SQL Server SQL, không giống như Oracle, không thể nhận ra rằng bạn đang xác định một ký hiệu mới trên dòng đầu tiên và bạn có thể tham chiếu trong các dòng sau. Nó không "nhìn thấy" biểu tượng cho đến khi nó gặp mã thông báo GO, nó yêu cầu nó thực thi SQL trước đó kể từ lần GO cuối cùng, tại thời điểm đó, biểu tượng được áp dụng cho cơ sở dữ liệu và hiển thị với trình phân tích cú pháp.
Tại sao nó không chỉ coi dấu chấm phẩy như một dấu ngắt ngữ nghĩa và áp dụng các câu lệnh riêng lẻ mà tôi không biết và ước nó sẽ như vậy. Phần thưởng duy nhất mà tôi có thể thấy là bạn có thể đặt một câu lệnh print () ngay trước khi GO và nếu bất kỳ câu lệnh nào bị lỗi, bản in sẽ không thực thi. Tuy nhiên, rất nhiều rắc rối cho một lợi nhuận nhỏ.