Wprowadzenie
Często istnieje potrzeba poinformowania w jakiś sposób administratorów o problemach z serwerem. Powiadomienia są generalnie podzielone na 2 typy:
1) powiadomienia w czasie rzeczywistym, czyli takie, które muszą nadejść natychmiast po wystąpieniu problemu
2) opóźnione powiadomienia, czyli takie, które pojawiają się po dość długim czasie (ponad 1 godzina) od wystąpienia problemu.
W mojej pracy konieczne było rozszerzenie funkcjonalności zwykłej poczty bazy danych SQL Server.
W tym artykule rozważymy przykład generowania powiadomień w tabelach HTML, a następnie wysyłania ich do administratorów.
Rozwiązanie
1. Skonfiguruj pocztę bazy danych
2. Utwórz tabelę dla odbiorców:
[rozwiń tytuł ="Kod"]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[Odbiorca]( [Recipient_GUID] [unikalny identyfikator] ROWGUIDCOL NOT NULL, [Recipient_Name] [nvarchar](255) NOT NULL, // podstawowy adres e-mail odbiorcy Recipient_Code] [nvarchar](10) NOT NULL, // kod odbiorcy [IsDeleted] [bit] NOT NULL, // wskaźnik usunięcia (czy odbiorca jest używany czy nie) [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_Recipient ] PRIMARY KEY CLUSTERED ( [Recipient_GUID] ASC) Z (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY], CONSTRAINT [AK_EDSC_Code odbiorca_LUS] (PAD_INDEX =WYŁĄCZONE, STATISTICS_NORECOMPUTE =WYŁĄCZONE, IGNORE_DUP_KEY =WYŁĄCZONE, ALLOW_ROW_LOCKS =WŁĄCZONE, ALLOW_PAGE_LOCKS =WŁĄCZONE) WŁĄCZONE [PRIMARY], OGRANICZENIE [AK_Recipient_Name] UNIKALNE NIESKLASTERZOWANE ([Nazwa_odbiorcy] ASC) Z ISTNIEJĄCĄ =WYŁĄCZONE_PAD_MP F, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TABELA GOALTERÓW [srv]. [Odbiorca] DODAJ OGRANICZENIE [DF_Recipient_Recipient_GUID] DEFAULT (nowy identyfikator()) TABELA GUID [GOALTER_GUID] srv].[Odbiorca] DODAJ OGRANICZENIE [DF_Recipient_IsDeleted] DOMYŚLNE ((0)) DLA [IsDeleted]TABELA BRAMKARÓW [srv].[Odbiorca] DODAJ OGRANICZENIE [DF_Recipient_InsertUTCDate] DOMYŚLNE (getutcdate()) DLA [GO[/expand]3. Utwórz tabelę adresów odbiorców:
[rozwiń tytuł ="Kod"]
UŻYJ [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv]. [Adres]( [Address_GUID] [unikalny identyfikator] ROWGUIDCOL NIE NULL, [Recipient_GUID] [unikalny identyfikator] NIE NULL, // var [adres] (n 255) NIE NULL, // e-mail [IsDeleted] [bit] NIE NULL, // wskaźnik usunięcia (niezależnie od tego, czy e-mail jest używany, czy nie) [InsertUTCDate] [data i godzina] NIE NULL, OGRANICZENIE [Adres_PK] KLASTRA KLUCZ PODSTAWOWY ( [Address_GUID] ASC ) Z (PAD_INDEX =WYŁĄCZONE, STATISTICS_NORECOMPUTE =WYŁĄCZONE, IGNORE_DUP_KEY =WYŁĄCZONE, ALLOW_ROW_LOCKS =WŁĄCZONE, ALLOW_PAGE_LOCKS =WŁĄCZONE) WŁĄCZONE [PRIMARY], OGRANICZENIE [AK_Address] UNIKALNE NIEROZKLEJONE ([Recipient_GUID] ASC)_WIEX =(Adres) , STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TABELA GOALTERÓW [srv]. TABELA BRAMKARZA [ srv].[Adres] DODAJ OGRANICZENIE [DF_Address_IsDeleted] DOMYŚLNE ((0)) DLA [IsDeleted]TABELA GOALTERÓW [srv].[Adres] DODAJ OGRANICZENIE [DF_Address_InsertUTCDate] DOMYŚLNE (getutcdate()) DLA [InsertUTCDate]GO[/expand]
4. Utwórz tabelę dla kolejki wiadomości:
[rozwiń tytuł ="Kod"]
UŻYJ [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[ErrorInfo]( [ErrorInfo_GUID] [unikalny identyfikator] NOT NULL, [ERROR_TITLE] [nvarchar](max) NULL, //AGE_title [_varMOR] (maks.) NULL, // wstępne informacje [ERROR_NUMBER] [nvarchar](maks.) NULL, // komunikat (błędu) kod [ERROR_MESSAGE] [nvarchar](maks.) NULL, // komunikat [ERROR_LINE] [nvarchar](maks.) NULL, // numer wiersza [ERROR_PROCEDURE] [nvarchar](max) NULL, // procedura składowana [ERROR_POST_MESSAGE] [nvarchar](max) NULL, // informacje wyjaśniające [RECIPIENTS] [nvarchar](max) NULL, // recipints oddzielone ';' [InsertDate] [datetime] NOT NULL, [StartDate] [datetime] NOT NULL, // data i godzina rozpoczęcia [DataZakończenia] [datatime] NOT NULL, // data i godzina zakończenia [Count] [int] NOT NULL, // liczba razy [Data aktualizacji] [dat etime] NOT NULL, [IsRealTime] [bit] NOT NULL, // wskaźnik czasu rzeczywistego [InsertUTCDate] [datetime] NULL, CONSTRAINT [PK_ErrorInfo] KLUCZ PODSTAWOWY ([ErrorInfo_GUID] ASC) Z (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF IGNORE_DUP_KEY =WYŁ, ALLOW_ROW_LOCKS =WŁ, ALLOW_PAGE_LOCKS =WŁ) WŁ [PRIMARY]) WŁ [PRIMARY] TEXTIMAGE_ON [PRIMARY]TABELA GOALTERÓW [srv].[ErrorInfo] DODAJ OGRANICZENIE [DF_ErrorInfo_ErrorInfo_GUIDneorGO] DEFA TABELA [srv].[ErrorInfo] DODAJ OGRANICZENIE [DF_ErrorInfo_InsertDate] DOMYŚLNE (getdate()) DLA [InsertDate] TABELA BRAMKARÓW [srv].[ErrorInfo] DODAJ OGRANICZENIE [DF_ErrorInfo_StartDate] DOMYŚLNE (getdate()) DLA [StartDate]GOAL srv].[ErrorInfo] DODAJ OGRANICZENIE [DF_ErrorInfo_FinishDate] DOMYŚLNE (getdate()) DLA [FinishDate]TABELI BRAMKARÓW [srv].[ErrorInfo] DODAJ OGRANICZENIE [DF_ErrorInfo_Count] DOMYŚLNE ((1)) DLA [Count]TABELI BRAMKARÓW [srv] .[ErrorInfo] DODAJ OGRANICZENIE [DF__ErrorInfo__Updat__5FFEE747] DEFAU LT (getdate()) DLA [UpdateDate]TABELI BRAMKARÓW [srv].[ErrorInfo] DODAJ OGRANICZENIE [DF_ErrorInfo_IsRealTime] DOMYŚLNE ((0)) DLA [IsRealTime]TABELI BRAMKARÓW [srv].[ErrorInfo] DODAJ OGRANICZENIE [DF_ErrorInfo_IsRealTime] DEFAUT getutcdate()) DLA [InsertUTCDate]GO[/expand]
5. Utwórz tabelę archiwum dla wiadomości wysłanych z kolejki wiadomości:
[rozwiń tytuł ="Kod"]
UŻYJ [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABELA [srv]. [ErrorInfoArchive] ( [ErrorInfo_GUID] [unikalny identyfikator] ROWGUIDCOL NIE NULL, [BŁĄD_TYTUŁ] [nvarchar,(nULLER](MARESSOR) NULL ) NULL, [ERROR_NUMBER] [nvarchar](maks.) NULL, [ERROR_MESSAGE] [nvarchar](maks.) NULL, [ERROR_LINE] [nvarchar](maks.) NULL, [ERROR_PROCEDURE] [nvarchar](maks.) NULL, [ERROR_POST_MESSAGE] [nvarchar](max) NULL, [RECIPIENTS] [nvarchar](max) NULL, [InsertDate] [datetime] NOT NULL, [StartDate] [datetime] NOT NULL, [FinishDate] [datetime] NOT NULL, [Count] [ int] NOT NULL, [UpdateDate] [datetime] NOT NULL, [IsRealTime] [bit] NOT NULL, [InsertUTCDate] [datetime] NULL, CONSTRAINT [PK_ArchiveErrorInfo] KLUCZ PODSTAWOWY ([ErrorInfo_GUID] ASC) Z (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GOALTE TABELA R [srv]. [ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_ErrorInfo_GUID] DOMYŚLNE (newsectionid()) DLA [ErrorInfo_GUID]TABELI GOALTERÓW [srv].[ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ArchiveErrorInfo_GUID] (NERRORGATEERT) TABLES DEFATED [srv].[ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_StartDate] DOMYŚLNE (getdate()) DLA [Data początkowa]TABELI BRAMKARÓW [srv].[ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_FinishDate] DEFAULTrGOALTERFigetDTABLE [srv].[ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_FinishDate] ].[ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_Count] DOMYŚLNE ((1)) DLA [Count]TABELA BRAMKARÓW [srv].[ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_UpdateDate] DOMYŚLNE (getdate()) DLA [UpdateDate]GOAL [ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_IsRealTime] DOMYŚLNE ((0)) DLA [IsRealTime] TABELI BRAMKARÓW [srv]. [ErrorInfoArchive] DODAJ OGRANICZENIE [DF_ErrorInfoArchive_InsertUTCDate] DOMYŚLNE (CD)pIngotcdate()) ponownie>[/expand]
Te informacje są potrzebne do tworzenia historii. Poza tym ta tabela musi zostać usunięta z bardzo starych danych (na przykład starszych niż miesiąc).
6. Utwórz procedurę składowaną, która rejestruje nową wiadomość w kolejce wiadomości:
[rozwiń tytuł ="Kod"]
UŻYJ [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[ErrorInfoIncUpd] @ERROR_TITLE nvarchar(max), @ERROR_PRED_MESSAGE nvarchar(max), @varAGEROROR_max ), @varAGERROR_LINE nvarchar(max), @ERROR_PROCEDURE nvarchar(max), @ERROR_POST_MESSAGE nvarchar(max), @RECIPIENTS nvarchar(max), @StartDate datetime=null, @FinishDate datetime=null, @IsRealTime bit =0ASBEGIN /* Błąd podczas logowania tabela do wysłania e-mailem, jeśli w tabeli jest już wpis o tym samym tytule, treści i nadawcy, zmieni się data zakończenia błędu, data aktualizacji rekordu oraz liczba błędów */ USTAW NR. NA; zadeklaruj unikalny identyfikator @ErrorInfo_GUID; wybierz top 1 @ErrorInfo_GUID=ErrorInfo_GUID z srv.ErrorInfo gdzie ([email protected]_TITLE lub @ERROR_TITLE ma wartość null) i [email protected] i ([email protected]_MESSAGE lub @ERROR_MESSAGE ma wartość null) i (przykład@sqldat_AGE_s) lub @ERROR_PRED_MESSAGE ma wartość null) i ([email protected]_POST_MESSAGE lub @ERROR_POST_MESSAGE ma wartość null) i ([email protected] lub @IsRealTime ma wartość null); if (@ERRORINFO_GUID IS NULL) Rozpocznij wstaw do srv.errorinfo (błąd_title, error_pred_message, error_number, error_message, error_line, error_procedure, error_post_message, odbiorcy, isrealtime, steralDate, FinansDate) Wybierz @error_title,@error_pred_message, error_number, error_numer, error_number, error_message, ERROR_LINE ,@ERROR_PROCEDURE ,@ERROR_POST_MESSAGE ,@RECIPIENTS ,@IsRealTime ,isnull(@StartDate, getdate()) ,isnull(@FinishDate,getdate()) end else rozpocznij aktualizację srv.ErrorInfo set FinishDate=getdate(), [Count]=[Count]+1, UpdateDate=getdate() gdzie [email protected]_GUID; koniecENDGO[/expand]
7. Utwórz procedurę składowaną, która zwraca ciąg z adresów według kodu lub podstawowego adresu e-mail odbiorcy:
[rozwiń tytuł ="Kod"]
UŻYJ [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER PROCEDURA ONGOCREATE [srv].[GetRecipients]@Nazwa_odbiorcy nvarchar(255)=NULL,@Kod_odbiorcy nvarchar(10)=NULL,@zmienna*Procedura(max) n tworzenie powiadomień e-mail*/ASBEGIN SET NOCOUNT ON; ustaw @Odbiorcy=''; wybierz @[email protected]+d.[Adres]+';' from srv.Recipient jako r inner join srv.[Adres] jako d na r.Recipient_GUID=d.Recipient_GUID gdzie (przykł[email protected]_Name lub @Recipient_Name JEST NULL) i (przykł[email protected]_Code lub @Recipient_Code JEST NULL) oraz r.IsDeleted=0 i d.IsDeleted=0; --order by r.InsertUTCDate desc, d.InsertUTCDate desc; if(len(@Recipients)>0) set @Recipients=substring(@Recipients,1,len(@Recipients)-1);ENDGO[/expand]
8. Utwórz niezbędne funkcje do pracy z datami i godzinami:
[rozwiń tytuł ="Kod"]
UŻYJ [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [rep].[GetDateFormat] ( @dt datetime, // data wejściowa @format int=0 // ustawiony format) ZWRACA nvarchar(255)AS/* Zwraca datę jako ciąg znaków zgodnie z podanym formatem i datą wejścia W razie potrzeby wstawia zera:format data wejścia wynik 0 17.4.2014 "17.04.2014" 1 17.4.2014 "04.2014" 1 8.11.2014 "11.2014" 2 17.04.2014 "2014" */POCZĄTEK ZGŁOSZENIA @res nvarchar(255); ZADEKLARUJ @dzień int=DZIEŃ(@dt); ZADEKLARUJ @miesiąc int=MIESIĄC(@dt); ZADEKLARUJ @rok int=ROK(@dt); if(@format=0) rozpocznij ustaw @res=IIF(@day<10,'0'+cast(@day as nvarchar(1)), cast(@day as nvarchar(2)))+'.'; set @[email protected]+IIF(@miesiąc<10,'0'+cast(@miesiąc jako nvarchar(1)), rzut(@miesiąc jako nvarchar(2)))+'.'; ustaw @[email protected]+cast(@year as nvarchar(255)); end else if(@format=1) begin set @res=IIF(@month<10,'0'+cast(@month as nvarchar(1)), cast(@month as nvarchar(2)))+'. '; ustaw @[email protected]+cast(@year as nvarchar(255)); end else if(@format=2) begin set @res=cast(@year as nvarchar(255)); end RETURN @res;ENDGOUSE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [rep].[GetTimeFormat] ( @dt datetime, // input time @format int=0 // preset format)RETURNS nvarchar(255)AS/* Zwraca czas jako ciąg zgodnie z podanym formatem i czasem wejścia Wstawia zera tam, gdzie to konieczne:format czasu wejścia wynik 0 17:04 "17:04:00" 1 17:04 "17:04" 1 8:04 "08:04 " 2 17:04 "17"*/POCZĄTEK ZGŁOSZENIA @res nvarchar(255); ZADEKLARUJ @godzina int=DATACZĘŚĆ(GODZINA, @dt); ZADEKLARUJ @min int=DATACZĘŚĆ(MINUTA, @dt); ZADEKLARUJ @sec int=DATACZĘŚĆ(DRUGA, @dt); if(@format=0) begin set @res=IIF(@hour<10,'0'+cast(@hour as nvarchar(1)), cast(@hour as nvarchar(2)))+':'; set @[email protected]+IIF(@min<10,'0'+cast(@min jako nvarchar(1)), rzut(@min jako nvarchar(2)))+':'; ustaw @[email protected]+IIF(@sec<10,'0'+cast(@sec jako nvarchar(1)), cast(@sec jako nvarchar(2))); end else if(@format=1) begin set @res=IIF(@hour<10,'0'+cast(@hour as nvarchar(1)), cast(@hour as nvarchar(2)))+':'; ustaw @[email protected]+IIF(@min<10,'0'+cast(@min jako nvarchar(1)), cast(@min jako nvarchar(2))); end else if(@format=2) begin set @res=IIF(@hour<10,'0'+cast(@hour as nvarchar(1)), cast(@hour as nvarchar(2))); koniec RETURN @res;ENDGO[/expand]
9. Utwórz procedurę składowaną, która tworzy raport HTML dotyczący wiadomości w formie tabeli:
[rozwiń tytuł ="Kod"]
UŻYJ [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[GetHTMLTable] @recipients nvarchar(max) ,@dt datetime // do której daty czytać ASBEGIN /* generuje kod HTML dla tabeli */ SET NOCOUNT ON; zadeklaruj @body nvarchar(max); zadeklaruj @tbl table(ID int identity (1,1) ,[ERROR_TITLE] nvarchar(max) ,[ERROR_PRED_MESSAGE] nvarchar(max) ,[ERROR_NUMBER] nvarchar(max) ,[ERROR_MESSAGE] nvarchar(max) ,[nvarchar_LINE] (max) ,[ERROR_PROCEDURE] nvarchar(max) ,[ERROR_POST_MESSAGE] nvarchar(max) ,[InsertDate] datetime ,[StartDate] datetime ,[FinishDate] datetime ,[Count] int ); zadeklaruj @ID int ,@ERROR_TITLE nvarchar(max) ,@ERROR_PRED_MESSAGE nvarchar(max) ,@ERROR_NUMBER nvarchar(max) ,@ERROR_MESSAGE nvarchar(max) ,@ERROR_LINE nvarchar(MESSAGE) nvarchar(max) (maks.) ,@InsertDate datetime ,@StartDate datetime ,@FinishDate datetime ,@Count int wstaw do @tbl( [ERROR_TITLE] ,[ERROR_PRED_MESSAGE] ,[ERROR_NUMBER] ,[ERROR_MESSAGE] ,[ERRORERRESSORAGE]_PRO,[COS ] ,[InsertDate] ,[StartDate] ,[FinishDate] ,[Count] ) wybierz pierwszą setkę [ERROR_TITLE] ,[ERROR_PRED_MESSAGE] ,[ERROR_NUMBER] ,[ERROR_MESSAGE] ,[ERROR_LINE] ,[ERROR_PROCEDURE] ,[ERROR_POST_MESSAGE] ,[InsertDate] ,[StartDate] ,[FinishDate] ,[Count] from [srv].[ErrorInfo], gdzie ([@RECIQlDAT].com ) lub (@recipients IS NULL) i InsertDate'; ustaw @example@sqldat.com+' '; ustaw @[email protected]+' '; while((wybierz top 1 1 z @tbl)>0) rozpocznij set @[email protected]+''; ustaw @[email protected]+'№ п/п'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'DATA'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'BŁĄD'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'OPIS'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'KOD BŁĘDU'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'WIADOMOŚĆ'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'START'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'FINISH'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'LICZBA'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'NUMER LINII'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'PROCEDURA'; ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+'UWAGA'; ustaw @[email protected]+' '; ustaw @[email protected]+''; wybierz top 1 @ID =[ID] ,@ERROR_TITLE =[ERROR_TITLE] ,@ERROR_PRED_MESSAGE=[ERROR_PRED_MESSAGE] ,@ERROR_NUMBER =[ERROR_NUMBER] ,@ERROR_MESSAGE =[ERROR_MESSAGE]_PROEDRORCELL =[ERROR_MESSAGE] =[ERROR_LINE] ] ,@ERROR_POST_MESSAGE=[ERROR_POST_MESSAGE] ,@InsertDate =[InsertDate] ,@StartDate =[StartDate] ,@FinishDate =[FinishDate] ,@Count =[Liczba] z @tbl zamówienia według daty wstawienia asc; ustaw @[email protected]+' '; koniec zestawu @[email protected]+''; wybierz @body;ENDGO'; ustaw @[email protected]+cast(@ID jako nvarchar(max)); ustaw @[email protected]+' '; ustaw @[email protected]+''; set @[email protected]+rep.GetDateFormat(@InsertDate, domyślnie)+' '+rep.GetTimeFormat(@InsertDate, domyślnie); // cast(@InsertDate as nvarchar(max)); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+isnull(@ERROR_TITLE,''); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+isnull(@ERROR_PRED_MESSAGE,''); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+isnull(@ERROR_NUMBER,''); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+isnull(@KOMUNIKAT_BŁĘDU,''); ustaw @[email protected]+' '; ustaw @[email protected]+''; set @[email protected]+rep.GetDateFormat(@StartDate, default)+' '+rep.GetTimeFormat(@StartDate, default); //cast(@DataRozpoczęcia jako nvarchar(max)); ustaw @[email protected]+' '; ustaw @[email protected]+''; set @[email protected]+rep.GetDateFormat(@FinishDate, domyślnie)+' '+rep.GetTimeFormat(@FinishDate, default); //cast(@DataZakończenia jako nvarchar(max)); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+cast(@Count as nvarchar(max)); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+isnull(@ERROR_LINE,''); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+isnull(@ERROR_PROCEDURE,''); ustaw @[email protected]+' '; ustaw @[email protected]+''; ustaw @[email protected]+isnull(@ERROR_POST_MESSAGE,''); ustaw @[email protected]+' '; usuń z @tbl gdzie [email protected]; ustaw @[email protected]+'[/expand]
10. Utwórz procedurę składowaną, która wysyła wiadomości:
[rozwiń tytuł ="Kod"]
USE [DATABAE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[RunErrorInfoProc] @IsRealTime bit =0 // tryb wysyłania (1-w czasie rzeczywistym)ASBEGIN /* wysyłanie powiadomień o błędach w określonym trybie */ SET NOCOUNT ON; zadeklaruj @dt datetime=getdate(); zadeklaruj @tbl table(Odbiorcy nvarchar(max)); zadeklaruj @odbiorcy nvarchar(max); zadeklaruj @ odbiorca nvarchar(255); zadeklaruj @result nvarchar(max)=''; zadeklaruj @recp nvarchar(max); zadeklaruj @ind int; zadeklaruj @recipients_key nvarchar(max); // odbierz wszystkie potrzebne wiadomości wstaw do @tbl(Odbiorcy) wybierz [ODBIORCY] z srv.ErrorInfo gdzie InsertDate0) begin //odbierz odbiorców select top (1) @recipients=Recipients from @tbl; ustaw @[email protected]; ustaw @wynik=''; // dla każdego odbiorcy while(len(@recipients)>0) begin set @ind=CHARINDEX(';', @recipients); if(@ind>0) begin set @recipient=substring(@recipients,1, @ind-1); set @recipients=substring(@recipients,@ind+1,len(@recipients)[email protected]); koniec inny początek ustaw @[email protected]; ustaw @odbiorcy=''; koniec; // odbierz e-maile od odbiorców exec [srv].[GetRecipients] @[email protected], @[email protected] out; if(len(@recp)=0) begin exec [srv].[GetRecipients] @[email protected], @[email protected] out; if(len(@recp)=0) ustaw @[email protected]; koniec // oddzielone symbolem ';' ustaw @[email protected]@sqldat.com+';'; end set @result=substring(@result,1,len(@result)-1); ustaw @[email protected]; // odbierz raport HTML z określonymi odbiorcami i datą wstaw do @rec_body(Body) exec srv.GetHTMLTable @[email protected]_key, @[email protected]; // odbierz raport HTML select top (1) @body=Body from @rec_body; // rzeczywisty wysyłający EXEC msdb.dbo.sp_send_dbmail // e-mailowy profil administratora, który utworzyliśmy @profile_name ='ALARM', //e-mail odbiorcy @recipients =@recipients, // tekst wiadomości @body =@body, // Temat @subject =N'INFORMACJE O BŁĘDACH WYKONANIA', @body_format='HTML'--, // Na przykład dodajmy wyniki losowego zapytania SQL do wiadomości [email protected] =@query--'SELECT TOP 10 nazwa Z sys.objects'; usuń z @tbl gdzie [email protected]_key; usuń z @rec_body; zakończ // zarchiwizuj wysłane wiadomości INSERT INTO [srv].[ErrorInfoArchive] ([ErrorInfo_GUID] ,[ERROR_TITLE] ,[ERROR_PRED_MESSAGE] ,[ERROR_NUMBER] ,[ERROR_MESSAGE] ,[ERROR_LINE] ,[CESSROR_AGE] ODBIORCY] ,[DataRozpoczęcia] ,[DataZakończenia] ,[Liczba] ,IsRealTime ) SELECT [ErrorInfo_GUID] ,[ERROR_TITLE] ,[ERROR_PRED_MESSAGE] ,[ERROR_NUMBER] ,[ERROR_MESSAGE] ,[ERROR_MESSAGE] ,[ERROR],[ERROR_MESSAGE] [ODBIORCY] ,[DataRozpoczęcia] ,[DataZakończenia] ,[Liczba] ,IsRealTime FROM [srv].[ErrorInfo] gdzie [email protected] i InsertDate [/expand]
Ta procedura składowana pobiera każdą wiadomość z kolejki wiadomości i umieszcza ją w raporcie HTML w formie tabeli. Dla odbiorców, na podstawie ich kodu lub podstawowego adresu e-mail, tworzy ciąg składający się z adresów e-mail, na które wysyłana jest wiadomość. W ten sposób przetwarzane są wszystkie wybrane wiadomości. Tutaj używana jest procedura składowana msdb.dbo.sp_send_dbmail.
11. Utwórz dwa zadania w Agencie (pierwsze dla powiadomień w czasie rzeczywistym (zaplanuj 1 raz na minutę), drugie dla prostych powiadomień (zaplanuj 1 raz na godzinę)). Dodaj następujące elementy do kodu zadania:
WYKONAJ [NAZWA_BAZY_DANYCH].[srv].[RunErrorInfoProc] @IsRealTime=0; // 0 - dla prostych wiadomości i 1 - dla wiadomości w czasie rzeczywistymOto przykład zgłaszania błędów:
[rozwiń tytuł=”Kod”]
rozpocznij wykonywanie exec [NAZWA_BAZY_DANYCH].[srv].[KillFullOldConnect];zakończ trybegin catch zadeklaruj @str_mess nvarchar(max)=KOMUNIKAT_BŁĘDU(), @str_num nvarchar(max)=cast(NUMER_BŁĘDU() jako nvarchar(max) ), @str_line nvarchar(max)=cast(ERROR_LINE() as nvarchar(max)), @str_proc nvarchar(max)=ERROR_PROCEDURE(), @str_title nvarchar(max)='USUWANIE PROCESÓW NIE ODPOWIADAJĄCYCH NA SERWERZE'przykład @sqldat.com@nazwa_serwera, @str_pred_mess nvarchar(max)='BŁĄD USUNIĘCIA PROCESÓW NIE ODPOWIADAJĄCYCH NA SERWERZE '[email protected]@nazwa_serwera+'; exec [DATABASE_NAME].srv.ErrorInfoIncUpd @ERROR_TITLE =@str_title, @ERROR_PRED_MESSAGE =@str_pred_mess, @ERROR_NUMBER =@str_num, @ERROR_MESSAGE =@str_mess, @ERROR_LINE =@ROR_PRED_MESSAGE=ODBIORCY ='ODBIORCA1;ODBIORCA2'; zadeklaruj @err [email protected]@error; raiserror(@str_mess,16,1);zatrzask końcowy[/expand]
Tutaj używana jest procedura składowana svr.KillFullOldConnect.
Wynik
Ten artykuł zawiera przykład rozszerzenia funkcjonalności zwykłej poczty bazy danych oraz przykład generowania powiadomień w tabelach HTML, a następnie wysyłania ich pocztą elektroniczną do administratorów. Takie podejście umożliwia powiadamianie administratorów o różnych problemach w czasie rzeczywistym lub po określonym czasie, minimalizując w ten sposób wystąpienie krytycznego problemu i awarii DBMS i serwera, co z kolei chroni produkcję przed opóźnieniami w przepływie pracy.
Odniesienia:
- Sp_send_dbmail
- Poczta bazy danych
- Srv.KillFullOldConnect