ฉันต้องใช้ Begin / End Blocks และคำสำคัญ Go ใน SQL Server เมื่อใด


103

ใครช่วยบอกทีว่าต้องใช้beginและendบล็อกใน SQL Server เมื่อไหร่และที่ไหน
นอกจากนี้Goคีย์เวิร์ดทำอะไรกันแน่?

คำตอบ:


116

GO เปรียบเสมือนจุดสิ้นสุดของสคริปต์

คุณสามารถมีคำสั่ง CREATE TABLE หลายรายการโดยคั่นด้วย GO เป็นวิธีการแยกส่วนหนึ่งของสคริปต์ออกจากอีกส่วนหนึ่ง แต่ส่งทั้งหมดในบล็อกเดียว


BEGIN และ END เหมือนกับ {and} ใน C / ++ / #, Java และอื่น ๆ

พวกเขาผูกบล็อกโค้ดเชิงตรรกะ ฉันมักจะใช้ BEGIN และ END ที่จุดเริ่มต้นและจุดสิ้นสุดของโพรซีเดอร์ที่เก็บไว้ แต่ก็ไม่จำเป็นอย่างยิ่งที่นั่น ในกรณีที่จำเป็นสำหรับลูปและคำสั่ง IF ฯลฯ ซึ่งคุณต้องการมากกว่าหนึ่งขั้นตอน ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END

คุณได้ลองสร้าง SP โดยไม่มี BEGIN และ END หรือยัง? IIRC เฉพาะบรรทัดแรกเท่านั้นที่รวมอยู่ใน SP ส่วนที่เหลือจะถูกเรียกใช้ที่นั่นแล้ว ...
cjk

2
นั่นไม่ใช่ประสบการณ์ของฉันตั้งแต่ SQL Server 2000 เป็นต้นไปอย่างแน่นอน
MatBailie

1
BEGIN และ END กำหนดขอบเขตใหม่ด้วยหรือไม่
samis

2
ใช่. สิ่งที่ประกาศภายนอกสามารถมองเห็นได้ภายใน แต่สิ่งที่ประกาศภายในจะอยู่นอกขอบเขตที่ END
MatBailie

36

คุณต้อง BEGIN ... END เพื่อสร้างบล็อกที่ครอบคลุมมากกว่าหนึ่งคำสั่ง ดังนั้นหากคุณต้องการทำ 2 สิ่งใน 'ขา' เดียวของคำสั่ง IF หรือหากคุณต้องการทำมากกว่าหนึ่งสิ่งในเนื้อหาของลูปในขณะที่คุณต้องยึดคำสั่งเหล่านั้นด้วย BEGIN ... สิ้นสุด

คีย์เวิร์ด GO ไม่ได้เป็นส่วนหนึ่งของ SQL Query Analyzer ใช้เพื่อแบ่งสคริปต์ออกเป็น "แบทช์" ที่ดำเนินการอย่างอิสระ


28

GO ไม่ใช่คีย์เวิร์ดใน SQL Server มันเป็นตัวคั่นแบทช์ GO จบงบชุดหนึ่ง สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อคุณใช้บางอย่างเช่น SQLCMD สมมติว่าคุณกำลังป้อนคำสั่ง SQL ในบรรทัดคำสั่ง คุณไม่จำเป็นต้องให้สิ่งนั้นดำเนินการทุกครั้งที่คุณจบคำสั่งดังนั้น SQL Server จะไม่ทำอะไรเลยจนกว่าคุณจะเข้าสู่ "GO"

ในทำนองเดียวกันก่อนที่แบตช์ของคุณจะเริ่มขึ้นคุณมักจะต้องมองเห็นวัตถุบางอย่าง ตัวอย่างเช่นสมมติว่าคุณกำลังสร้างฐานข้อมูลแล้วทำการสืบค้น คุณไม่สามารถเขียน:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

เนื่องจาก foo ไม่มีอยู่สำหรับชุดงานที่สร้างตาราง คุณต้องทำสิ่งนี้:

CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;

13

BEGIN และ END ได้รับคำตอบจากผู้อื่นเป็นอย่างดี

ดังที่ Gary ชี้ให้เห็นว่า GO เป็นตัวแยกแบทช์ซึ่งใช้โดยเครื่องมือไคลเอนต์ที่ Microsoft จัดหาให้เช่น isql, sqlcmd, ตัววิเคราะห์แบบสอบถามและสตูดิโอการจัดการเซิร์ฟเวอร์ SQL (อย่างน้อยเครื่องมือบางอย่างก็อนุญาตให้เปลี่ยนตัวคั่นแบทช์ได้ฉันไม่เคยเห็นการใช้สำหรับการเปลี่ยนตัวคั่นแบทช์)

ในการตอบคำถามว่าจะใช้ GO เมื่อใดต้องทราบว่าเมื่อใดที่ต้องแยก SQL ออกเป็นแบตช์

ข้อความบางรายการต้องเป็นคำสั่งแรกของชุดงาน

select 1
create procedure #Zero as
    return 0

บน SQL Server 2000 ข้อผิดพลาดคือ:

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.

ใน SQL Server 2005 ข้อผิดพลาดมีประโยชน์น้อย:

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

ดังนั้นใช้GOเพื่อแยกคำสั่งที่ต้องเป็นจุดเริ่มต้นของชุดงานจากคำสั่งที่อยู่ข้างหน้าในสคริปต์

เมื่อเรียกใช้สคริปต์ข้อผิดพลาดจำนวนมากจะทำให้การดำเนินการของชุดงานหยุดลง แต่จากนั้นไคลเอนต์จะส่งชุดถัดไปการเรียกใช้สคริปต์จะไม่หยุด ฉันมักจะใช้สิ่งนี้ในการทดสอบ ฉันจะเริ่มสคริปต์ด้วย start transaction และจบลงด้วย rollback ทำการทดสอบทั้งหมดตรงกลาง:

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

ด้วยวิธีนี้ฉันจะกลับสู่สถานะเริ่มต้นเสมอแม้ว่าจะมีข้อผิดพลาดเกิดขึ้นในรหัสทดสอบคำสั่งธุรกรรมเริ่มต้นและย้อนกลับซึ่งเป็นส่วนหนึ่งของชุดงานที่แยกจากกันยังคงเกิดขึ้น หากพวกเขาไม่ได้อยู่ในแบทช์ที่แยกจากกันข้อผิดพลาดทางไวยากรณ์จะทำให้การทำธุรกรรมไม่เกิดขึ้นเนื่องจากแบตช์จะถูกแยกวิเคราะห์เป็นหน่วย และข้อผิดพลาดรันไทม์จะทำให้การย้อนกลับไม่เกิดขึ้น

นอกจากนี้หากคุณกำลังทำสคริปต์การติดตั้งและมีหลายชุดในไฟล์เดียวข้อผิดพลาดในชุดเดียวจะไม่ทำให้สคริปต์ทำงานต่อไปซึ่งอาจทำให้ยุ่งเหยิง (สำรองข้อมูลก่อนติดตั้งทุกครั้ง)

เกี่ยวข้องกับสิ่งที่ Dave Markel ชี้ให้เห็นมีบางกรณีที่การแยกวิเคราะห์จะล้มเหลวเนื่องจาก SQL Server กำลังค้นหาในพจนานุกรมข้อมูลสำหรับวัตถุที่สร้างขึ้นก่อนหน้านี้ในชุดงาน แต่การแยกวิเคราะห์สามารถเกิดขึ้นได้ก่อนที่จะเรียกใช้คำสั่งใด ๆ บางครั้งนี่เป็นปัญหาบางครั้งก็ไม่ใช่ ฉันไม่สามารถหาตัวอย่างที่ดีได้ แต่ถ้าคุณเคยได้รับข้อผิดพลาด 'X ไม่มีอยู่จริง' เมื่อคำสั่งนั้นจะแบ่งออกเป็นแบตช์

และบันทึกสุดท้าย ธุรกรรมสามารถครอบคลุมแบทช์ (ดูด้านบน) ตัวแปรไม่ขยายแบทช์

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

Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".

1
นี่คือสิ่งที่ฉันต้องการขอบคุณ: "ธุรกรรมสามารถขยายแบทช์ตัวแปรไม่ขยายแบทช์"
Gary

3

GO สิ้นสุดแบทช์คุณแทบจะไม่จำเป็นต้องใช้ในโค้ดเท่านั้น โปรดทราบว่าหากคุณใช้ใน proc ที่จัดเก็บไว้จะไม่มีการเรียกใช้โค้ดหลังจาก GO เมื่อคุณดำเนินการ proc

BEGIN และ END จำเป็นสำหรับคำสั่งประเภทขั้นตอนใด ๆ ที่มีโค้ดหลายบรรทัดในการประมวลผล คุณจะต้องใช้สำหรับลูปและเคอร์เซอร์ในขณะที่ (ซึ่งคุณจะหลีกเลี่ยงได้หากเป็นไปได้แน่นอน) และคำสั่ง IF (โดยทางเทคนิคแล้วคุณไม่จำเป็นต้องใช้มันสำหรับสถิติ IF ที่มีโค้ดเพียงบรรทัดเดียว แต่ง่ายกว่า รักษารหัสหากคุณใส่ไว้หลัง IF เสมอ) คำสั่ง CASE ยังใช้ END แต่ไม่มี BEGIN


รหัสใด ๆ หลังจาก GO จะถูกเก็บไว้กับ proc ที่จัดเก็บไว้หรือไม่? คำสั่ง CREATE หรือ ALTER จะไม่ถูกประมวลผลราวกับว่าไม่มีรหัสหลังจาก GO ไม่มีอยู่จริง? แล้วโค้ดหลังจาก GO จะถูกเรียกใช้งานราวกับว่ามันเป็นสคริปต์ของตัวเอง?
MatBailie

เคอร์เซอร์ต้องทำอย่างไรกับมัน?
Gary McGill

3

หลังจากต่อสู้กับปัญหานี้ในวันนี้ความคิดเห็นของฉันคือ: BEGIN ... END brackets code เหมือนกับที่ {.... } ทำในภาษา C เช่นรหัสบล็อกสำหรับ if ... else และลูป

GO คือ (ต้อง) ใช้เมื่อคำสั่งสำเร็จขึ้นอยู่กับวัตถุที่กำหนดโดยคำสั่งก่อนหน้า ฐานข้อมูล USE เป็นตัวอย่างที่ดีข้างต้น แต่สิ่งต่อไปนี้จะกัดคุณด้วย:

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.

สำหรับฉันแล้วปัญหาคือสิ่งนี้: SQL Server SQL Parser ซึ่งแตกต่างจาก Oracle ไม่สามารถตระหนักได้ว่าคุณกำลังกำหนดสัญลักษณ์ใหม่ในบรรทัดแรกและสามารถอ้างอิงในบรรทัดต่อไปนี้ได้ มันจะไม่ "เห็น" สัญลักษณ์จนกว่าจะพบกับโทเค็น GO ซึ่งบอกให้เรียกใช้ SQL ที่นำหน้าตั้งแต่ GO ครั้งสุดท้าย ณ จุดนั้นสัญลักษณ์จะถูกนำไปใช้กับฐานข้อมูลและจะปรากฏให้ผู้แยกวิเคราะห์มองเห็นได้

ทำไมมันไม่เพียง แต่ถือว่าเซมิโคลอนเป็นตัวแบ่งความหมายและใช้คำสั่งทีละคำฉันไม่รู้และหวังว่ามันจะเป็นเช่นนั้น โบนัสเดียวที่ฉันเห็นคือคุณสามารถใส่คำสั่ง print () ก่อนหน้า GO และหากข้อความใด ๆ ล้มเหลวการพิมพ์จะไม่ทำงาน มีปัญหามากมายสำหรับผลประโยชน์เล็กน้อย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.