Quand dois-je utiliser les blocs de début / fin et le mot clé Go dans SQL Server?

103

Quelqu'un peut-il me dire quand et où je dois utiliser beginet endbloquer dans SQL Server?
De plus, que fait exactement le Gomot-clé?

Tarik
la source

Réponses:

116

GO est comme la fin d'un script.

Vous pouvez avoir plusieurs instructions CREATE TABLE, séparées par GO. C'est une façon d'isoler une partie du script d'une autre, mais de tout soumettre en un seul bloc.


BEGIN et END sont exactement comme {et} en C / ++ / #, Java, etc.

Ils ont lié un bloc logique de code. J'ai tendance à utiliser BEGIN et END au début et à la fin d'une procédure stockée, mais ce n'est pas strictement nécessaire ici. Là où c'est nécessaire, c'est pour les boucles, les instructions IF, etc., où vous avez besoin de plus d'une étape ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END
MatBailie
la source
Avez-vous essayé de créer un SP sans BEGIN et END? IIRC, seule la première ligne est incluse dans le SP, le reste est juste exécuté là et puis ...
cjk
2
Ce n'est certainement pas mon expérience à partir de SQL Server 2000.
MatBailie
1
BEGIN et END définissent-ils également un nouveau périmètre?
samis
2
Oui. Tout ce qui est déclaré à l'extérieur est visible à l'intérieur, mais tout ce qui est déclaré à l'intérieur sera hors de portée à la fin.
MatBailie
36

Vous avez besoin de BEGIN ... END pour créer un bloc couvrant plus d'une instruction. Donc, si vous vouliez faire 2 choses dans une `` jambe '' d'une instruction IF, ou si vous vouliez faire plus d'une chose dans le corps d'une boucle WHILE, vous auriez besoin de mettre ces instructions entre parenthèses avec BEGIN ... FIN.

Le mot clé GO ne fait pas partie de SQL. Il est uniquement utilisé par l'Analyseur de requêtes pour diviser les scripts en "lots" qui sont exécutés indépendamment.

Gary McGill
la source
28

GO n'est pas un mot clé dans SQL Server; c'est un séparateur de lots. GO termine une série d'instructions. Ceci est particulièrement utile lorsque vous utilisez quelque chose comme SQLCMD. Imaginez que vous entrez des instructions SQL sur la ligne de commande. Vous ne voulez pas nécessairement que la chose s'exécute à chaque fois que vous terminez une instruction, donc SQL Server ne fait rien tant que vous n'entrez pas "GO".

De même, avant que votre lot ne démarre, vous devez souvent avoir certains objets visibles. Par exemple, disons que vous créez une base de données puis que vous l'interrogez. Vous ne pouvez pas écrire:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

car foo n'existe pas pour le batch qui fait le CREATE TABLE. Vous auriez besoin de faire ceci:

CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;
Dave Markle
la source
13

BEGIN et END ont été bien répondu par d'autres.

Comme le souligne Gary, GO est un séparateur de lots, utilisé par la plupart des outils clients fournis par Microsoft, tels que isql, sqlcmd, analyseur de requêtes et SQL Server Management Studio. (Au moins certains des outils permettent de changer le séparateur de lots. Je n'ai jamais vu une utilisation pour changer le séparateur de lots.)

Pour répondre à la question de savoir quand utiliser GO, il faut savoir quand le SQL doit être séparé en lots.

Certaines instructions doivent être la première instruction d'un lot.

select 1
create procedure #Zero as
    return 0

Sur SQL Server 2000, l'erreur est:

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.

Sur SQL Server 2005, l'erreur est moins utile:

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

Donc, utilisez GOpour séparer les instructions qui doivent être le début d'un lot des instructions qui le précèdent dans un script.

Lors de l'exécution d'un script, de nombreuses erreurs entraîneront l'arrêt de l'exécution du lot, mais le client enverra simplement le lot suivant, l'exécution du script ne s'arrêtera pas. J'utilise souvent ceci dans les tests. Je vais commencer le script avec begin transaction et terminer par rollback, en faisant tous les tests au milieu:

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

De cette façon, je reviens toujours à l'état de départ, même si une erreur s'est produite dans le code de test, les instructions de transaction begin et rollback faisant partie d'un lot séparé se produisent toujours. S'ils n'étaient pas dans des lots séparés, alors une erreur de syntaxe empêcherait la transaction de début de se produire, car un lot est analysé comme une unité. Et une erreur d'exécution empêcherait la restauration de se produire.

De plus, si vous effectuez un script d'installation et que vous avez plusieurs lots dans un fichier, une erreur dans un lot n'empêchera pas le script de continuer à s'exécuter, ce qui peut laisser un désordre. (Toujours sauvegarder avant l'installation.)

En lien avec ce que Dave Markel a souligné, il y a des cas où l'analyse échoue car SQL Server recherche dans le dictionnaire de données les objets créés plus tôt dans le lot, mais l'analyse peut se produire avant l'exécution des instructions. Parfois, c'est un problème, parfois non. Je ne peux pas trouver un bon exemple. Mais si jamais vous obtenez une erreur «X n'existe pas», alors qu'elle existera clairement par cette instruction, divisez-vous en lots.

Et une note finale. La transaction peut couvrir des lots. (Voir ci-dessus.) Les variables ne couvrent pas les lots.

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

Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".
Indemnité de Shannon
la source
1
C'est ce dont j'avais besoin, merci: "La transaction peut s'étendre sur des lots. Les variables ne couvrent pas les lots."
Gary
3

GO termine un batch, vous n'auriez que très rarement besoin de l'utiliser dans le code. Sachez que si vous l'utilisez dans un proc stocké, aucun code après le GO ne sera exécuté lorsque vous exécuterez le proc.

BEGIN et END sont nécessaires pour toutes les instructions de type procédural avec plusieurs lignes de code à traiter. Vous en aurez besoin pour les boucles WHILE et les curseurs (ce que vous éviterez dans la mesure du possible bien sûr) et les instructions IF (enfin, techniquement, vous n'en avez pas besoin pour une instruction IF qui n'a qu'une seule ligne de code, mais il est plus facile de conserver le code si vous les mettez toujours après un IF). Les instructions CASE utilisent également END mais n'ont pas de BEGIN.

HLGEM
la source
Un code après le GO serait-il réellement stocké par rapport au processus stocké? l'instruction CREATE ou ALTER ne serait-elle pas traitée comme s'il n'y avait pas de code après le GO? Et ALORS, le code après que le GO soit exécuté comme s'il s'agissait de son propre script?
MatBailie
Qu'est-ce que les curseurs ont à voir avec cela?
Gary McGill
3

Après avoir lutté avec ce problème aujourd'hui, mon opinion est la suivante: BEGIN ... END entre crochets, tout comme {....} le fait dans les langages C, par exemple des blocs de code pour if ... else et des boucles

GO est (doit être) utilisé lorsque les instructions suivantes reposent sur un objet défini par une instruction précédente. La base de données USE est un bon exemple ci-dessus, mais ce qui suit vous mordra également:

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.

Il me semble que le problème est le suivant: l'analyseur SQL Server SQL, contrairement à celui d'Oracle, est incapable de se rendre compte que vous définissez un nouveau symbole sur la première ligne et qu'il est correct de le référencer dans les lignes suivantes. Il ne "voit" pas le symbole jusqu'à ce qu'il rencontre un jeton GO qui lui dit d'exécuter le SQL précédent depuis le dernier GO, à quel point le symbole est appliqué à la base de données et devient visible pour l'analyseur.

Pourquoi il ne traite pas simplement le point-virgule comme une rupture sémantique et n'applique pas les déclarations individuellement, je ne sais pas et j'aimerais que ce soit le cas. Le seul bonus que je peux voir est que vous pouvez mettre une instruction print () juste avant le GO et si l'une des instructions échoue, l'impression ne s'exécutera pas. Beaucoup de problèmes pour un gain mineur cependant.

matao
la source