Si vous utilisez SSMS (ou un autre outil similaire) pour exécuter le code produit par ceci script, vous obtiendrez exactement la même erreur. Il peut fonctionner correctement lorsque vous insérez des délimiteurs de lot (GO
), mais maintenant que vous ne le faites pas, vous rencontrerez également le même problème dans SSMS.
Par contre, la raison pour laquelle vous ne pouvez pas mettre GO
dans vos scripts dynamiques est parce que GO
n'est pas une instruction SQL, c'est simplement un délimiteur reconnu par SSMS et d'autres outils. Vous en êtes probablement déjà conscient.
Quoi qu'il en soit, le but de GO
est que l'outil sache que le code doit être divisé et que ses parties doivent être exécutées séparément . Et cela, séparément , est ce que vous devez également faire dans votre code.
Donc, vous avez ces options :
-
insérez
EXEC sp_execute @sql
juste après la partie qui lâche le déclencheur, puis réinitialisez la valeur de@sql
pour ensuite stocker et exécuter à son tour la partie définition ; -
utilisez deux variables,
@sql1
et@sql2
, stockez la partie IF EXISTS/DROP dans@sql1
, celui de CREATE TRIGGER dans@sql2
, puis exécutez les deux scripts (là encore, séparément).
Mais ensuite, comme vous l'avez déjà découvert, vous serez confronté à un autre problème :vous ne pouvez pas créer un déclencheur dans une autre base de données sans exécuter l'instruction dans le contexte de cette base de données .
Maintenant, il y a 2 façons de fournir le contexte nécessaire :
1) utiliser un USE
déclaration ;
2) exécuter la ou les instructions en tant que requête dynamique à l'aide de EXEC targetdatabase..sp_executesql N'…'
.
Évidemment, la première option ne fonctionnera pas ici :nous ne pouvons pas ajouter USE …
avant CREATE TRIGGER
, car cette dernière doit être la seule instruction du lot.
La deuxième option peut être utilisé, mais cela nécessitera une couche supplémentaire de dynamicité (je ne sais pas si c'est un mot). C'est parce que le nom de la base de données est un paramètre ici et nous devons donc exécuter EXEC targetdatabase..sp_executesql N'…'
comme un script dynamique, et puisque le script réel à exécuter est lui-même censé être un script dynamique, il sera donc imbriqué deux fois.
Donc, avant le (deuxième) EXEC sp_executesql @sql;
ligne ajoutez ce qui suit :
SET @sql = N'EXEC ' + @dbname + '..sp_executesql N'''
+ REPLACE(@sql, '''', '''''') + '''';
Comme vous pouvez le voir, pour intégrer le contenu de @sql
en tant que script dynamique imbriqué correctement, ils doivent être placés entre guillemets simples. Pour la même raison, chaque guillemet simple dans @sql
doit être doublé (par exemple, en utilisant le REPLACE()
fonction
, comme dans la déclaration ci-dessus).