Kaum ein Projekt kommt ohne die Auftragssteuerung des SQL Server-Agent aus. Dabei wird für einen Auftrag immer genau angegeben was für eine Funktionalität wann auszuführen ist. Dabei wird das „Was“ über einzelne Schritte des Auftrags eingestellt und das „Wann“ über einen Zeitplan.
Es gibt aber auch die Möglichkeit, SQL-Server-Agent-Aufträge ereignisgesteuert auszuführen. Das soll hier kurz vorgestellt werden.
Die Ereignissteuerung der SQL-Server-Agent-Aufträge basiert auf Warnungen und Fehlermeldungen. D.h. die Technik ist im SQL-Server implementiert, um auf bestimmte Fehler reagieren zu können. Fehlermeldungen in SQL-Server besitzen immer auch eine bestimmte Schwere. Es können also auch ‚Fehler‘ konfiguriert werden, die eher den Status eines Hinweises haben, als dass sie tatsächliche Fehler sind. Diese Technik kann also auch in Fällen hilfreich sein, wo nicht unbedingt ein echter Fehlerfall auftritt.
Im Fenster der Eigenschaften eines Auftrags finden sich 5 Seiten: Allgemein, Schritte, Zeitpläne, Warnungen, Benachrichtigungen und Ziele. Bei Aufträgen, die ereignisgesteuert ausgeführt werden sollen, wird anstatt einen Zeitplanes eine entsprechende Warnung (auf der Seite Warnungen) eingestellt. Bevor an der Stelle eine Warnung eingesetzt werden kann, muss diese definiert sein. Für die Definition von Warnungen gibt es den Ordner Warnungen unter SQL Server-Agent im Management Studio. Das Eigenschaften-Fenster einer Warnung ist ähnlich aufgebaut, wie das eines Auftrags, hat aber nur 3 Seiten: Allgemein, Antwort und Optionen. Auf der Seite Allgemein wird der Warnung ein Name gegeben und mit einem Ereignis verbunden. Als Ereignisse gelten dabei SQL-Server-Fehlermeldungen, SQL Server-Leistungsstatus oder WMI-Ereignisse. In diesem Beispiel wird das Verwenden einer benutzerdefinierten Fehlermeldung gezeigt (also eine SQL-Server-Fehlermeldung). Diese Fehlermeldung muss als erstes angelegt werden und an entsprechender Stelle auch ausgelöst werden.
Das ist, grob skizziert, der Weg zu einer ereignisgesteuerten Auftragsausführung vom Auftrag aus zurück zur Ereignisquelle, der Fehlermeldung.
Als erstes wird also eine benutzerdefinierte Fehlermeldung benötigt. Diese wird mit der Prozedur sp_addmessage angelegt:
sp_addmessage @msgnum = 50010 ,@lang = 'us_english' ,@with_log = 'True' ,@severity = 7 ,@msgtext = 'this is an english message.' go sp_addmessage @msgnum = 50010 ,@with_log = 'True' ,@severity = 7 ,@msgtext = 'Deutscher Fehlermeldungstext.'
Hier noch ein paar Hinweise zu Fehlermeldungen:
- Die Fehlernummern bis 50000 sind für SQL Server reserviert. Benutzerdefinierte Fehlermeldungen besitzen die Nummer 50001 oder höher.
- Für jede Fehlermeldung wird ein Schweregrad definiert. Es gibt 25 Schweregrade, die von Hinweisen und Warnungen bis hin zu schweren Systemfehlern gehen. In diesem Fall ist ein Schweregrad 7 eingestellt worden, was etwas zwischen Hinweis und Warnung bedeutet.
- Egal, in welcher Sprache SQL Server installiert ist, es muss immer erst die ‚us_english‘ – Version einer Fehler-Meldung angelegt werden. Für SQL Server-Agent-Warnungen sind auch nur die ‚us_english‘-Versionen der Fehlermeldungen relevant.
- Fehlermeldungen, die Warnungen des SQL Server-Agent auslösen sollen, müssen im Windows-Anwendungsprotokoll erfasst werden. Das wird durch den Parameter @with_log = ‚True‘ eingestellt. Default-Einstellung ist hier ‚False‘.
Der nächste Schritt wäre, Situationen zu bestimmen, in denen die Meldung ausgelöst werden soll. Dies geschieht in SQL-Text mit der Funktion RAISERROR. Der Funktion wird die Fehlernummer der auszulösenden Meldung, ein Schweregrad und ein Status übergeben:
Create TRIGGER [dbo].[TR_T_WriteTable_Plan_BUKRS] ON [dbo].[T_WriteTable_Plan_BUKRS] AFTER INSERT AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for trigger here IF (Select Max(EAR_PositionID_11) from inserted) = 99999502 Raiserror (50010, 7, 1) END
In diesem Fall wird die Meldung in einem Trigger ausgelöst. Das wirkt auf den ersten Blick seltsam, da Trigger eine andere Art ereignisgesteuerter Programmierung darstellen. Warum also nochmal ein Ereignis auslösen, wenn das primäre Ereignis bereits ausgelöst wurde und entsprechender SQL-Code gestartet ist. Warum den Ereignis-Code nicht gleich in den Trigger integrieren?
Die Antwort ist: Trigger laufen immer (auch AFTER-Trigger!) in derselben Transaktion, wie das auslösende Ereignis. Trigger sind nur geeignet, wenn der entsprechende Code wenig Ressourcen in Anspruch nimmt. Braucht der SQL-Code, der ausgeführt werden soll, längere Zeit und ist die Integrität der Daten auch ohne diese Transaktion sichergestellt, kann das Auslösen von benutzerdefinierten Meldungen eine Lösung sein.
Nachdem das Auslösen einer Meldung implementiert ist, wird im SQL Server-Agent eine Warnung eingerichtet, die diese Meldung abfängt. Das geschieht am schnellsten im SQL Server-Agent im Management-Studio:
Der neuen Warnung wird auf der Seite ‚Allgemein‘ ein Name vergeben. Dann wird der Typ auf ‚SQL Server-Ereigniswarnung‘ gestellt und die Fehlernummer der entsprechenden benutzerdefinierten Meldung eingetragen.
Die Warnung bringt aber nichts, außer deren Protokollierung, wenn sie nicht auch noch weiterverarbeitet wird. Das wird ein SQL Server-Agent-Auftrag angelegt, der diese Warnung als Auslöser implementiert:
Die Verknüpfung des Jobs mit der Warnung passiert dann wieder in den Eigenschaftenseiten der Warnung (Seite Antwort):
Das war’s schon, die benutzerdefinierte Ereignissteuerung ist bereit. Ein weiterer Vorteil dieses Vorgehen ist, dass das Auslösen des Ereignisses immer gut dokumentiert ist.