W ramach niektórych zadań administracyjnych mamy wiele tabel, z których każda wymaga utworzenia wyzwalacza. Spust ustawi flagę i datę w bazie danych audytu, gdy obiekt zostanie zmodyfikowany. Dla uproszczenia, mam tabelę ze wszystkimi obiektami, które wymagają utworzonych wyzwalaczy.dynamiczny błąd sql: 'CREATE TRIGGER' musi być pierwszą instrukcją w grupie zapytań
Próbuję wygenerować dynamicznego SQL, aby to zrobić dla każdego obiektu, ale ja dostaję ten błąd:
'CREATE TRIGGER' must be the first statement in a query batch.
Oto kod, aby wygenerować SQL.
CREATE PROCEDURE [spCreateTableTriggers]
AS
BEGIN
DECLARE @dbname varchar(50),
@schemaname varchar(50),
@objname varchar(150),
@objtype varchar(150),
@sql nvarchar(max),
@CRLF varchar(2)
SET @CRLF = CHAR(13) + CHAR(10);
DECLARE ObjectCursor CURSOR FOR
SELECT DatabaseName,SchemaName,ObjectName
FROM Audit.dbo.ObjectUpdates;
SET NOCOUNT ON;
OPEN ObjectCursor ;
FETCH NEXT FROM ObjectCursor
INTO @dbname,@schemaname,@objname;
WHILE @@FETCH_STATUS=0
BEGIN
SET @sql = N'USE '+QUOTENAME(@dbname)+'; '
SET @sql = @sql + N'IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'''+QUOTENAME(@schemaname)+'.[Tiud_'[email protected]+'_AuditObjectUpdates]'')) '
SET @sql = @sql + N'BEGIN DROP TRIGGER '+QUOTENAME(@schemaname)+'.[Tiud_'[email protected]+'_AuditObjectUpdates]; END; '[email protected]
SET @sql = @sql + N'CREATE TRIGGER '+QUOTENAME(@schemaname)+'.[Tiud_'[email protected]+'_AuditObjectUpdates] '[email protected]
SET @sql = @sql + N' ON '+QUOTENAME(@schemaname)+'.['[email protected]+'] '[email protected]
SET @sql = @sql + N' AFTER INSERT,DELETE,UPDATE'[email protected]
SET @sql = @sql + N'AS '[email protected]
SET @sql = @sql + N'IF EXISTS(SELECT * FROM Audit.dbo.ObjectUpdates WHERE DatabaseName = '''[email protected]+''' AND ObjectName = '''[email protected]+''' AND RequiresUpdate=0'[email protected]
SET @sql = @sql + N'BEGIN'[email protected]
SET @sql = @sql + N' SET NOCOUNT ON;'[email protected]
SET @sql = @sql + N' UPDATE Audit.dbo.ObjectUpdates'[email protected]
SET @sql = @sql + N' SET RequiresUpdate = 1'[email protected]
SET @sql = @sql + N' WHERE DatabaseName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N' AND ObjectName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N'END' [email protected]
SET @sql = @sql + N'ELSE' [email protected]
SET @sql = @sql + N'BEGIN' [email protected]
SET @sql = @sql + N' SET NOCOUNT ON;' [email protected]
SET @sql = @sql + @CRLF
SET @sql = @sql + N' -- Update ''SourceLastUpdated'' date.'[email protected]
SET @sql = @sql + N' UPDATE Audit.dbo.ObjectUpdates'[email protected]
SET @sql = @sql + N' SET SourceLastUpdated = GETDATE() '[email protected]
SET @sql = @sql + N' WHERE DatabaseName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N' AND ObjectName = '''[email protected]+''' '[email protected]
SET @sql = @sql + N'END; '[email protected]
--PRINT(@sql);
EXEC sp_executesql @sql;
FETCH NEXT FROM ObjectCursor
INTO @dbname,@schemaname,@objname;
END
CLOSE ObjectCursor ;
DEALLOCATE ObjectCursor ;
END
Jeśli używam PRINT
kod i wklej go w nowym oknie zapytań, kod wykonuje bez żadnego problemu.
Usunąłem oświadczenia GO
ponieważ to również dawało błędy.
Czego mi brakuje?
Dlaczego pojawia się błąd przy użyciu EXEC(@sql);
lub nawet EXEC sp_executesql @sql;
?
Czy ma to coś wspólnego z kontekstem w ramach EXEC()
?
Wielkie dzięki za pomoc.
Wielkie dzięki za to. Teraz podzieliłem kod na dwie części, jak sugerujesz w pierwszej opcji powyżej, w następujący sposób: – MarkusBee
[EDYTOWAJ limit czasu dla poprzedniego komentarza.] Wielkie dzięki. Podzielę kod na dwie części, jak sugerujesz w pierwszej opcji. Pierwsza część wykonuje się doskonale. Wyjaśnię, że procedura jest wykonywana z bazy danych "Audyt", a obiekty wymagające wyzwalaczy znajdują się w innych bazach danych. Wykonywanie instrukcji "CREATE TRIGGER" powoduje zgłoszenie następującego błędu, nawet przy użyciu w pełni kwalifikowanej nazwy tabeli: "Nie można utworzyć wyzwalacza w [...], ponieważ obiekt docelowy nie znajduje się w bieżącej bazie danych." Czy jest jakiś sposób obejścia tego? Jak mogę go uruchomić w kontekście innej bazy danych? Dzięki. – MarkusBee
@markb: Zobacz moją aktualizację. Nie jestem pewien, czy wszystko jest tak jasne, jak bym chciał, więc proszę, nie wahaj się zapytać. –