Wann muss ich in SQL Server Begin / End Blocks und das Schlüsselwort Go verwenden?

103

Kann mir jemand sagen, wann und wo ich SQL Server verwenden beginund endblockieren muss?
Was genau macht das GoKeyword?

Tarik
quelle

Antworten:

116

GO ist wie das Ende eines Skripts.

Sie können mehrere CREATE TABLE-Anweisungen haben, die durch GO getrennt sind. Auf diese Weise können Sie einen Teil des Skripts von einem anderen isolieren, aber alles in einem Block einreichen.


BEGIN und END sind wie {und} in C / ++ / #, Java usw.

Sie banden einen logischen Codeblock. Ich neige dazu, BEGIN und END zu Beginn und am Ende einer gespeicherten Prozedur zu verwenden, aber dies ist dort nicht unbedingt erforderlich. Wo es notwendig ist, sind Schleifen und IF-Anweisungen usw., wo Sie mehr als einen Schritt benötigen ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END
MatBailie
quelle
Haben Sie versucht, einen SP ohne BEGIN und END zu erstellen? IIRC, nur die erste Zeile ist im SP enthalten, der Rest wird nur dort ausgeführt und dann ...
cjk
2
Das ist sicherlich nicht meine Erfahrung ab SQL Server 2000.
MatBailie
1
Definieren BEGIN und END auch einen neuen Bereich?
Samis
2
Ja. Alles, was außen deklariert ist, ist innen sichtbar, aber alles, was innen deklariert ist, wird am ENDE außer Reichweite geraten.
MatBailie
36

Sie benötigen BEGIN ... END, um einen Block zu erstellen, der mehr als eine Anweisung umfasst. Wenn Sie also zwei Dinge in einem 'Bein' einer IF-Anweisung ausführen möchten oder wenn Sie mehr als eine Aufgabe im Hauptteil einer WHILE-Schleife ausführen möchten, müssen Sie diese Anweisungen mit BEGIN in Klammern setzen ... ENDE.

Das GO-Schlüsselwort ist nicht Teil von SQL. Es wird nur von Query Analyzer verwendet, um Skripte in "Stapel" zu unterteilen, die unabhängig voneinander ausgeführt werden.

Gary McGill
quelle
28

GO ist kein Schlüsselwort in SQL Server. Es ist ein Batch-Separator. GO beendet eine Reihe von Anweisungen. Dies ist besonders nützlich, wenn Sie etwas wie SQLCMD verwenden. Stellen Sie sich vor, Sie geben SQL-Anweisungen in der Befehlszeile ein. Sie möchten nicht unbedingt, dass das Objekt jedes Mal ausgeführt wird, wenn Sie eine Anweisung beenden. Daher unternimmt SQL Server nichts, bis Sie "GO" eingeben.

Ebenso müssen vor dem Start Ihres Stapels häufig einige Objekte sichtbar sein. Angenommen, Sie erstellen eine Datenbank und fragen sie dann ab. Du kannst nicht schreiben:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

weil foo für den Stapel, der die CREATE TABLE ausführt, nicht existiert. Sie müssten dies tun:

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

BEGIN und END wurden von anderen gut beantwortet.

Wie Gary betont, ist GO ein Batch-Trennzeichen, das von den meisten von Microsoft bereitgestellten Client-Tools wie isql, sqlcmd, query analyzer und SQL Server Management Studio verwendet wird. (Zumindest einige der Tools ermöglichen das Ändern des Batch-Separators. Ich habe noch nie eine Verwendung zum Ändern des Batch-Separators gesehen.)

Um die Frage zu beantworten, wann GO verwendet werden soll, muss bekannt sein, wann SQL in Stapel aufgeteilt werden muss.

Einige Anweisungen müssen die erste Anweisung eines Stapels sein.

select 1
create procedure #Zero as
    return 0

Unter SQL Server 2000 lautet der Fehler:

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.

Unter SQL Server 2005 ist der Fehler weniger hilfreich:

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

Verwenden Sie GOdiese Option, um Anweisungen, die der Beginn eines Stapels sein müssen, von den Anweisungen zu trennen, die in einem Skript davor stehen.

Wenn ein Skript ausgeführt wird, führen viele Fehler dazu, dass die Ausführung des Stapels gestoppt wird. Der Client sendet jedoch einfach den nächsten Stapel. Die Ausführung des Skripts wird nicht gestoppt. Ich benutze dies oft beim Testen. Ich werde das Skript mit der Starttransaktion beginnen und mit dem Rollback enden, wobei alle Tests in der Mitte durchgeführt werden:

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

Auf diese Weise kehre ich immer in den Startzustand zurück, auch wenn im Testcode ein Fehler aufgetreten ist. Die Anweisungen zum Starten und Zurücksetzen von Transaktionen, die Teil eines separaten Stapels sind, treten weiterhin auf. Wenn sie sich nicht in separaten Stapeln befinden, verhindert ein Syntaxfehler, dass die Transaktion beginnt, da ein Stapel als Einheit analysiert wird. Und ein Laufzeitfehler würde das Rollback verhindern.

Wenn Sie ein Installationsskript ausführen und mehrere Stapel in einer Datei haben, verhindert ein Fehler in einem Stapel nicht, dass das Skript weiter ausgeführt wird, was zu einem Durcheinander führen kann. (Vor der Installation immer sichern.)

In Bezug auf das, was Dave Markel hervorgehoben hat, gibt es Fälle, in denen die Analyse fehlschlägt, weil SQL Server im Datenwörterbuch nach Objekten sucht, die früher im Stapel erstellt wurden. Die Analyse kann jedoch erfolgen, bevor Anweisungen ausgeführt werden. Manchmal ist dies ein Problem, manchmal nicht. Ich kann kein gutes Beispiel finden. Wenn Sie jedoch jemals den Fehler "X existiert nicht" erhalten, wird dieser durch diese Anweisung eindeutig in Stapel aufgeteilt.

Und noch eine letzte Anmerkung. Die Transaktion kann mehrere Stapel umfassen. (Siehe oben.) Variablen erstrecken sich nicht über Stapel.

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
quelle
1
Dies ist, was ich brauchte, danke: "Transaktion kann Stapel umfassen. Variablen umfassen keine Stapel."
Gary
3

GO beendet einen Stapel, Sie müssten ihn nur sehr selten im Code verwenden. Beachten Sie, dass bei Verwendung in einem gespeicherten Prozess kein Code nach dem GO ausgeführt wird, wenn Sie den Prozess ausführen.

BEGIN und END werden für alle prozeduralen Typanweisungen mit mehreren zu verarbeitenden Codezeilen benötigt. Sie benötigen sie für WHILE-Schleifen und Cursor (die Sie natürlich möglichst vermeiden) und IF-Anweisungen (technisch gesehen benötigen Sie sie nicht für eine IF-Anweisung, die nur eine Codezeile enthält, dies ist jedoch einfacher Behalten Sie den Code bei, wenn Sie ihn immer nach einer IF eingeben. CASE-Anweisungen verwenden ebenfalls ein END, haben jedoch kein BEGIN.

HLGEM
quelle
Würde irgendein Code nach dem GO tatsächlich gegen den gespeicherten Prozess gespeichert werden? Würde die Anweisung CREATE oder ALTER nicht so verarbeitet, als ob der Code nach dem GO nicht vorhanden wäre? Und dann wird der Code nach dem GO ausgeführt, als wäre es ein eigenes Skript?
MatBailie
Was haben Cursor damit zu tun?
Gary McGill
3

Nachdem ich heute mit diesem Problem gerungen habe, ist meine Meinung folgende: BEGIN ... END Klammern Code genau wie {....} in C-Sprachen, z. B. Codeblöcke für if ... else und Schleifen

GO wird (muss verwendet werden), wenn nachfolgende Anweisungen auf einem Objekt beruhen, das durch eine vorherige Anweisung definiert wurde. Die USE-Datenbank ist oben ein gutes Beispiel, aber das Folgende wird Sie auch beißen:

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.

Mir scheint, das Problem ist folgendes: Der SQL Server SQL Parser kann im Gegensatz zum Oracle nicht erkennen, dass Sie ein neues Symbol in der ersten Zeile definieren und dass es in Ordnung ist, in den folgenden Zeilen darauf zu verweisen. Es "sieht" das Symbol erst, wenn es auf ein GO-Token stößt, das es anweist, das vorhergehende SQL seit dem letzten GO auszuführen. An diesem Punkt wird das Symbol auf die Datenbank angewendet und für den Parser sichtbar.

Warum es das Semikolon nicht einfach als semantische Unterbrechung behandelt und Aussagen einzeln anwendet, weiß ich nicht und wünsche es mir. Der einzige Bonus, den ich sehen kann, ist, dass Sie eine print () - Anweisung direkt vor dem GO platzieren können. Wenn eine der Anweisungen fehlschlägt, wird der Druck nicht ausgeführt. Viel Ärger für einen kleinen Gewinn.

matao
quelle