Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

erreur sql dynamique :'CREATE TRIGGER' doit être la première instruction d'un lot de requêtes

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