web-dev-qa-db-fra.com

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

Quelqu'un peut-il me dire quand et où j'ai besoin d'utiliser des blocs begin et end dans SQL Server?
Aussi, que fait exactement le mot clé Go?

96
Tarik

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 bloc.


BEGIN et END ressemblent à {et} en C/++/#, Java, etc.

Ils ont lié un bloc de code logique. 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 là-bas. Où il IS est nécessaire 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
104
MatBailie

Vous avez besoin de BEGIN ... END pour créer un bloc couvrant plusieurs instructions. Donc, si vous vouliez faire deux choses dans une seule étape d'une instruction IF, ou si vous vouliez faire plus d'une chose dans le corps d'une boucle WHILE, il vous faudrait mettre entre crochets ces déclarations avec BEGIN ... FIN.

Le mot clé GO ne fait pas partie de SQL. Query Analyzer ne l'utilise que pour diviser les scripts en "lots" exécutés indépendamment.

34
Gary McGill

GO n'est pas un mot clé dans SQL Server; c'est un séparateur de lot. GO met fin à un lot de relevés. 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 forcément que la chose soit exécutée chaque fois que vous terminez une instruction. SQL Server ne fait rien tant que vous n'avez pas entré "GO".

De même, avant que votre lot ne commence, vous devez souvent avoir certains objets visibles. Par exemple, supposons 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 lot qui exécute CREATE TABLE. Vous devez faire ceci:

CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;
25
Dave Markle

BEGIN et END ont été bien répondus par d’autres.

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

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

Certaines déclarations doivent être la première déclaration d'un lot.

select 1
create procedure #Zero as
    return 0

Sur SQL Server 2000, l'erreur est la suivante:

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.

Utilisez donc GO pour séparer les instructions devant constituer le début d’un lot des instructions qui la précèdent dans un script.

Lors de l'exécution d'un script, de nombreuses erreurs entraînent l'arrêt de l'exécution du lot. Toutefois, le client envoie simplement le prochain lot. L'exécution du script ne s'arrête pas. Je l'utilise souvent dans les tests. Je vais commencer le script par begin transaction et terminer par l'annulation, en effectuant tous les tests au milieu:

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

Ainsi, 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, une erreur de syntaxe empêcherait la transaction de début, puisqu'un traitement est analysé comme une unité. Et une erreur d'exécution empêcherait la restauration.

De même, 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 l'exécution du script, ce qui risque de causer des dégâts. (Toujours sauvegarder avant d'installer.)

Par rapport à ce que Dave Markel a souligné, il peut arriver que l’analyse échoue parce que SQL Server recherche dans le dictionnaire de données des objets créés précédemment dans le lot, mais cette analyse peut avoir lieu avant l’exécution d’instructions. Parfois, c'est un problème, parfois non. Je ne peux pas trouver un bon exemple. Mais si vous obtenez une erreur 'X n’existe pas', alors qu’elle existera clairement par cette instruction, divisez-la en lots.

Et une note finale. La transaction peut s'étendre sur 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".
10
Shannon Severance

Après avoir résolu ce problème aujourd’hui, mon opinion est la suivante: COMMENCEZ ... FIN le code entre crochets, comme le fait {....} dans les langues 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 de SQL Server, contrairement à Oracle, ne peut pas 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 tant qu'il ne rencontre pas un jeton GO lui indiquant d'exécuter le code SQL précédent depuis le dernier GO. À ce stade, le symbole est appliqué à la base de données et devient visible pour l'analyseur.

Pourquoi ne traite-t-il pas simplement le point-virgule comme une rupture sémantique et applique-t-il des déclarations individuellement? Je ne le sais pas et je voudrais bien. Le seul bonus que je vois est que vous pouvez mettre une instruction print () juste avant le GO et que si l'une de ces déclarations échoue, l'impression ne sera pas exécutée. Beaucoup de problèmes pour un gain mineur cependant.

2
matao

GO met fin à un lot, 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é lors de l'exécution du proc.

BEGIN et END sont nécessaires pour toute instruction de type procédural avec plusieurs lignes de code à traiter. Vous en aurez besoin pour les boucles WHILE et les curseurs (que vous éviterez si possible bien entendu) et les instructions IF (bien techniquement, vous n'en avez pas besoin pour une instruction IF ne comportant qu'une seule ligne de code, mais il est plus facile de conservez le code si vous les mettez toujours après un IF). Les instructions CASE utilisent également une fin, mais pas un début.

2
HLGEM