Jeśli używasz programu SSMS (lub innego podobnego narzędzia) do uruchomienia kodu utworzonego przez to skrypt, otrzymasz dokładnie ten sam błąd. Może działać poprawnie po wstawieniu ograniczników partii (GO
), ale teraz, gdy tego nie zrobisz, napotkasz ten sam problem w SSMS.
Z drugiej strony powód, dla którego nie możesz umieścić GO
w twoich dynamicznych skryptach jest to, że GO
nie jest instrukcją SQL, jest jedynie ogranicznikiem rozpoznawanym przez SSMS i inne narzędzia. Prawdopodobnie już o tym wiesz.
W każdym razie punkt GO
służy do tego, aby narzędzie wiedziało, że kod powinien zostać podzielony, a jego części uruchamiane oddzielnie . I to oddzielnie , jest to również to, co powinieneś zrobić w swoim kodzie.
Masz więc następujące opcje:
-
wstaw
EXEC sp_execute @sql
tuż po części, która upuszcza wyzwalacz, a następnie zresetuj wartość@sql
aby następnie przechowywać i uruchamiać z kolei część definicji; -
użyj dwóch zmiennych,
@sql1
i@sql2
, zapisz część IF EXISTS/DROP w@sql1
, CREATE TRIGGER w@sql2
, a następnie uruchom oba skrypty (ponownie, osobno).
Ale potem, jak już się przekonałeś, staniesz przed innym problemem:nie możesz utworzyć wyzwalacza w innej bazie danych bez uruchomienia instrukcji w kontekście tej bazy danych .
Teraz istnieją 2 sposoby zapewnienia niezbędnego kontekstu:
1) użyj USE
oświadczenie;
2) uruchom instrukcję(e) jako dynamiczne zapytanie za pomocą EXEC targetdatabase..sp_executesql N'…'
.
Oczywiście pierwsza opcja nie zadziała tutaj:nie możemy dodać USE …
przed CREATE TRIGGER
, ponieważ ta ostatnia musi być jedyną instrukcją w partii.
Druga opcja może być używany, ale będzie wymagał dodatkowej warstwy dynamiczności (nie jestem pewien, czy to słowo). Dzieje się tak, ponieważ nazwa bazy danych jest tutaj parametrem i dlatego musimy uruchomić EXEC targetdatabase..sp_executesql N'…'
jako skrypt dynamiczny, a ponieważ sam skrypt do uruchomienia powinien być skryptem dynamicznym, zostanie on zagnieżdżony dwukrotnie.
Tak więc przed (drugim) EXEC sp_executesql @sql;
wiersz dodaj następujące:
SET @sql = N'EXEC ' + @dbname + '..sp_executesql N'''
+ REPLACE(@sql, '''', '''''') + '''';
Jak widać, zintegrować zawartość @sql
jako poprawnie zagnieżdżony skrypt dynamiczny, muszą być ujęte w pojedyncze cudzysłowy. Z tego samego powodu każdy cudzysłów w @sql
musi zostać podwojona (np. przy użyciu REPLACE()
funkcja
, jak w powyższym oświadczeniu).