Kapan saya perlu menggunakan Begin / End Blocks dan kata kunci Go di SQL Server?

103

Dapatkah seseorang memberi tahu saya kapan dan di mana saya perlu menggunakan begindan endmemblokir di SQL Server?
Selain itu, apa sebenarnya yang dilakukan Gokata kunci tersebut?

Tarik
sumber

Jawaban:

116

GO seperti akhir dari sebuah naskah.

Anda dapat memiliki beberapa pernyataan CREATE TABLE, dipisahkan oleh GO. Ini adalah cara untuk mengisolasi satu bagian dari skrip dari yang lain, tetapi mengirimkan semuanya dalam satu blok.


BEGIN dan END sama seperti {dan} di C / ++ / #, Java, dll.

Mereka mengikat blok kode logis. Saya cenderung menggunakan BEGIN dan END di awal dan akhir prosedur yang tersimpan, tetapi tidak sepenuhnya diperlukan di sana. Di mana IS diperlukan adalah untuk loop, dan pernyataan IF, dll, di mana Anda membutuhkan lebih dari satu langkah ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END
MatBailie
sumber
Sudahkah Anda mencoba membuat SP tanpa BEGIN dan END? IIRC, hanya baris pertama yang dimasukkan dalam SP, sisanya dieksekusi di sana dan kemudian ...
cjk
2
Itu pasti bukan pengalaman saya dari SQL Server 2000 dan seterusnya.
MatBailie
1
Apakah BEGIN dan END juga menentukan cakupan baru?
samis
2
Iya. Apa pun yang dideklarasikan di luar terlihat di dalam, tetapi apa pun yang dideklarasikan di dalam akan keluar dari cakupan pada AKHIR.
MatBailie
36

Anda perlu BEGIN ... END untuk membuat blok yang mencakup lebih dari satu pernyataan. Jadi, jika Anda ingin melakukan 2 hal dalam satu 'kaki' pernyataan IF, atau jika Anda ingin melakukan lebih dari satu hal di badan pengulangan WHILE, Anda perlu mengurung pernyataan tersebut dengan BEGIN ... AKHIR.

Kata kunci GO bukan bagian dari SQL. Ini hanya digunakan oleh Query Analyzer untuk membagi skrip menjadi "batch" yang dijalankan secara independen.

Gary McGill
sumber
28

GO bukanlah kata kunci di SQL Server; itu pemisah batch. GO mengakhiri serangkaian pernyataan. Ini sangat berguna ketika Anda menggunakan sesuatu seperti SQLCMD. Bayangkan Anda memasukkan pernyataan SQL pada baris perintah. Anda tidak perlu harus mengeksekusi setiap kali Anda mengakhiri pernyataan, jadi SQL Server tidak melakukan apa pun sampai Anda memasukkan "GO".

Demikian juga, sebelum kumpulan Anda dimulai, Anda sering kali perlu melihat beberapa objek. Misalnya, Anda membuat database, lalu membuat kueri. Anda tidak bisa menulis:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

karena foo tidak ada untuk batch yang melakukan CREATE TABLE. Anda perlu melakukan ini:

CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;
Dave Markle
sumber
13

BEGIN dan END telah dijawab dengan baik oleh orang lain.

Seperti yang ditunjukkan oleh Gary, GO adalah pemisah batch, yang digunakan oleh sebagian besar alat klien yang disediakan Microsoft, seperti isql, sqlcmd, penganalisis kueri, dan studio Manajemen Server SQL. (Setidaknya beberapa alat memungkinkan pemisah batch diubah. Saya belum pernah melihat kegunaan untuk mengubah pemisah batch.)

Untuk menjawab pertanyaan kapan harus menggunakan GO, kita perlu mengetahui kapan SQL harus dipisahkan menjadi beberapa batch.

Beberapa pernyataan harus menjadi pernyataan pertama dari sebuah kelompok.

select 1
create procedure #Zero as
    return 0

Di SQL Server 2000 kesalahannya adalah:

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.

Di SQL Server 2005 kesalahan kurang membantu:

Msg 178, Level 15, State 1, Procedure #Zero, Line 5
A RETURN statement with a return value cannot be used in this context.

Jadi, gunakan GOuntuk memisahkan pernyataan yang harus menjadi awal batch dari pernyataan yang mendahuluinya dalam skrip.

Saat menjalankan skrip, banyak kesalahan akan menyebabkan eksekusi batch berhenti, tetapi kemudian klien hanya akan mengirim batch berikutnya, eksekusi skrip tidak akan berhenti. Saya sering menggunakan ini dalam pengujian. Saya akan memulai skrip dengan memulai transaksi dan diakhiri dengan rollback, melakukan semua pengujian di tengah:

begin transaction
go
... test code here ...
go
rollback transaction

Dengan cara itu saya selalu kembali ke status awal, bahkan jika terjadi kesalahan dalam kode pengujian, pernyataan transaksi mulai dan kembalikan yang menjadi bagian dari batch terpisah masih terjadi. Jika mereka tidak berada dalam kelompok terpisah, maka kesalahan sintaksis akan mencegah terjadinya transaksi, karena sebuah kelompok diurai sebagai satu unit. Dan kesalahan waktu proses akan mencegah terjadinya rollback.

Selain itu, jika Anda melakukan skrip penginstalan, dan memiliki beberapa kumpulan dalam satu file, kesalahan dalam satu kumpulan tidak akan mencegah skrip terus berjalan, yang mungkin akan menimbulkan kekacauan. (Selalu backup sebelum menginstal.)

Terkait dengan apa yang ditunjukkan Dave Markel, ada beberapa kasus ketika penguraian akan gagal karena SQL Server mencari di kamus data untuk objek yang dibuat sebelumnya dalam batch, tetapi penguraian dapat terjadi sebelum pernyataan apa pun dijalankan. Terkadang ini menjadi masalah, terkadang tidak. Saya tidak bisa memberikan contoh yang baik. Tetapi jika Anda pernah mendapatkan kesalahan 'X tidak ada', ketika itu jelas akan ada dengan pernyataan itu masuk ke dalam batch.

Dan catatan terakhir. Transaksi dapat menjangkau batch. (Lihat di atas.) Variabel tidak mencakup batch.

declare @i int
set @i = 0
go
print @i

Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".
Shannon Severance
sumber
1
Inilah yang saya butuhkan, terima kasih: "Transaksi dapat mencakup kelompok. Variabel tidak mencakup kelompok."
Gary
3

GO mengakhiri batch, Anda hanya akan sangat jarang menggunakannya dalam kode. Ketahuilah bahwa jika Anda menggunakannya di proc yang tersimpan, tidak ada kode setelah GO yang akan dieksekusi saat Anda menjalankan proc.

BEGIN dan END diperlukan untuk semua pernyataan tipe prosedural dengan banyak baris kode untuk diproses. Anda akan membutuhkannya untuk WHILE loop dan cursor (yang akan Anda hindari jika memungkinkan tentunya) dan pernyataan IF (secara teknis Anda tidak membutuhkannya untuk pernyataan IF yang hanya memiliki satu baris kode, tetapi lebih mudah untuk pertahankan kode jika Anda selalu memasukkannya setelah IF). Pernyataan CASE juga menggunakan END tetapi tidak memiliki BEGIN.

HLGEM
sumber
Akankah kode apa pun setelah GO benar-benar disimpan di proc yang disimpan? bukankah pernyataan CREATE atau ALTER akan diproses seolah-olah ada kode setelah GO tidak ada? Dan KEMUDIAN kode setelah GO dieksekusi seolah-olah itu adalah skrip itu sendiri?
MatBailie
Apa hubungannya kursor dengan itu?
Gary McGill
3

Setelah bergumul dengan masalah ini hari ini pendapat saya adalah ini: MULAI ... AKHIRI kode kurung seperti yang {....} lakukan dalam bahasa C, misalnya blok kode untuk if ... else dan loop

GO (harus) digunakan ketika pernyataan berhasil bergantung pada objek yang ditentukan oleh pernyataan sebelumnya. Basis data USE adalah contoh yang bagus di atas, tetapi berikut ini juga akan membantu Anda:

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.

Menurut saya masalahnya adalah ini: SQL Server SQL Parser, tidak seperti Oracle, tidak dapat menyadari bahwa Anda sedang mendefinisikan simbol baru pada baris pertama dan tidak masalah untuk merujuk pada baris berikut. Itu tidak "melihat" simbol sampai ia menemukan sebuah token GO yang memerintahkannya untuk mengeksekusi SQL sebelumnya sejak GO terakhir, di mana simbol tersebut diterapkan ke database dan menjadi terlihat oleh parser.

Mengapa tidak hanya memperlakukan titik koma sebagai pemisah semantik dan menerapkan pernyataan secara individual, saya tidak tahu dan berharap demikian. Satu-satunya bonus yang dapat saya lihat adalah Anda dapat meletakkan pernyataan print () tepat sebelum GO dan jika ada pernyataan yang gagal, pencetakan tidak akan dijalankan. Banyak masalah untuk keuntungan kecil.

matao
sumber