sql >> Databasteknik >  >> RDS >> Sqlserver

dynamisk sql-fel:'CREATE TRIGGER' måste vara den första satsen i en frågebatch

Om du använder SSMS (eller annat liknande verktyg) för att köra koden som produceras av denna skriptet får du exakt samma fel. Det kunde fungera bra när du infogade batchavgränsare (GO ), men nu när du inte gör det kommer du att möta samma problem i SSMS också.

Å andra sidan, anledningen till att du inte kan lägga GO i dina dynamiska skript beror på att GO är inte en SQL-sats, det är bara en avgränsare som känns igen av SSMS och några andra verktyg. Förmodligen är du redan medveten om det.

Hur som helst, poängen med GO är för verktyget att veta att koden ska delas och dess delar köras separat . Och det, separat , är vad du bör göra i din kod också.

Så du har dessa alternativ:

  • infoga EXEC sp_execute @sql precis efter den del som släpper utlösaren, återställ sedan värdet på @sql för att sedan lagra och köra definitionsdelen i sin tur;

  • använd två variabler, @sql1 och @sql2 , lagra IF EXISTS/DROP-delen i @sql1 , CREATE TRIGGER-en till @sql2 , kör sedan båda skripten (igen, separat).

Men sedan, som du redan har fått reda på, kommer du att ställas inför ett annat problem:du kan inte skapa en utlösare i en annan databas utan att köra satsen i sammanhanget för den databasen .

Nu finns det två sätt att tillhandahålla det nödvändiga sammanhanget:

1) använd en USE uttalande;

2) kör satsen/satserna som en dynamisk fråga med EXEC targetdatabase..sp_executesql N'…' .

Uppenbarligen kommer det första alternativet inte att fungera här:vi kan inte lägga till USE … före CREATE TRIGGER , eftersom det senare måste vara det enda uttalandet i partiet.

Det andra alternativet kan användas, men det kommer att kräva ett extra lager av dynamik (osäker på om det är ett ord). Det beror på att databasnamnet är en parameter här och därför måste vi köra EXEC targetdatabase..sp_executesql N'…' som ett dynamiskt skript, och eftersom det faktiska skriptet som ska köras i sig är tänkt att vara ett dynamiskt skript, kommer det därför att kapslas två gånger.

Så före (andra) EXEC sp_executesql @sql; rad lägg till följande:

SET @sql = N'EXEC ' + @dbname + '..sp_executesql N'''
           + REPLACE(@sql, '''', '''''') + '''';

Som du kan se, för att integrera innehållet i @sql som ett kapslat dynamiskt skript på rätt sätt måste de omges av enkla citattecken. Av samma anledning, varenda citattecken in @sql måste fördubblas (t.ex. med REPLACE() funktion , som i ovanstående uttalande).



  1. Java Oracle localhost anslutningsfel (ORA-12505)

  2. Hur anger jag "dagens början" i en specifik tidszon?

  3. Stora MySQL-tabeller

  4. Var ska jag lagra en databasanslutningssträng?