web-dev-qa-db-ja.com

テーブルの値がxより大きい場合にsp_send_dbmailを使用してアラートを送信するジョブを作成する

[〜#〜]問題[〜#〜]

SMScounter.Counterは、サービスからの使用量を累積するために使用されます。このサービスのプログラムによる上限は1000です。この上限に違反した場合はユーザーに警告します。

テーブル作成

CREATE TABLE [dbo].[SMSCounter](
  [Counter] [int] NOT NULL,
  [CounterDate] [datetime] NOT NULL )

例のデータ

380, 2012-09-10 00:00:00.000
177, 2012-10-14 00:00:00.000
999, 2012-11-16 00:00:00.000

ジョブスクリプト

以下のスクリプトは、SMScounter.Counterは950より大きい。

USE DATABASEname
select (Counter) as CHECKVALUE from SMSCounter where smscounter.CounterDate  = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()),0)    
IF CHECKVALUE > 950

BEGIN

EXEC msdb.dbo.sp_send_dbmail
  @recipients=N'[email protected]',
  @body='1000 Daily SMS cap near', 
  @subject ='1000 Daily SMS cap near',
  @profile_name ='SCOTT',
  @query =
    'USE DATABASEname
     (select * from SMSCounter where CounterDate = GETDATE())'

END

[〜#〜]質問[〜#〜]

  1. GETDATEをフォーマットして調べるにはどうすればよいですかdd/mm/yyを読み、時間部分を無視するSMScounter.CounterDate? (上記のスクリプトは編集済みで、現在は機能しています)。

  2. IFを950と比較するためにCHECKVALUEステートメントを機能させるにはどうすればよいですか?

SQL Server 2008 Standard Editionを使用しています。

5
scott_lotus

convert (date, GETDATE())を使用して、「日付」部分のみを取得できます。


select GETDATE(), convert (date, GETDATE())
----------------------- ----------
2012-11-16 08:58:20.750 2012-11-16

また、「日付」の部分のみを比較する場合は、クエリを実行するたびに変換する手間を省くために、テーブルのデータ型をDATEに変更することをお勧めします。

IFステートメントの場合、チェックする値を渡し、実行するコードをBEGINおよびENDステートメント内にラップする必要があります。次に、sysobjectsテーブルを使用した例を示します。


declare @cnt integer
select @cnt=COUNT(1) from sysobjects

if @cnt>50
begin
  select 'hello'
end

dBに50を超えるオブジェクトがある場合、こんにちはと言います

だからあなたの場合:


USE DATABASEname
go
declare @counter integer

select @counter=MAX([Counter]) from SMSCounter where convert(date,CounterDate) = convert(date,GETDATE())

IF @counter > 950
BEGIN
  EXEC msdb.dbo.sp_send_dbmail
  @recipients=N'[email protected]',
  @body='1000 Daily SMS cap near',
  @subject ='1000 Daily SMS cap near',
  @profile_name ='SCOTT',
  @query =  '(select * from DATABASEname.dbo.SMSCounter where convert(date,CounterDate) = convert)(Date,GETDATE()))'
END

チェッククエリにMAX関数を追加しました。これにより、その日の最大値を含む単一の行のみが返されます。それ以外の場合は、一致するすべての行からランダムな値が返されます。テーブルに書き込むたびにその日の値を上書きする場合、それは不必要です。

5
Stuart Moore

解決策は悪くありませんが、もっとリアルタイムなものを紹介したいと思います。 SMSカウンターを1時間ごとにチェックするだけではなく、それがいつ最初に発生したかを知っているでしょうか?

私は次のようにします:

  • 新しい列をテーブルに追加します-警告ビットはデフォルトではnullではありません-顧客が大量のSMSについて警告を受けた場合に情報を保持します。これは、950を超えるすべての挿入/更新について顧客に警告が表示されるのではなく、最初の挿入/更新についてのみ警告が表示されるようにするために必要です。

  • カウンターの値が950より大きい場合にアラートを開始する(挿入および更新後)テーブルにトリガーを追加します(アラート列を1に設定して電子メールを送信します)。

トリガーは次のようになります。

ALTER TRIGGER dbo.RaiseAlert
    ON  dbo.SMSCounter
AFTER INSERT, UPDATE
AS 
BEGIN
    SET NOCOUNT ON;
    declare
        @cnt int,
        @today DATE = cast(GETDATE() as DATE),
        @alert bit;

    select @cnt = n.[Counter], @alert = alert
    from inserted n
    where n.CounterDate = @today;

    if @cnt > 950 and @alert = 0
    begin
        update SMSCounter
        set Alert = 1
        from SMSCounter
        where CounterDate = @today;

        declare @subject varchar(1000);
        select @subject = 'The sms counter is near!! It''s value is: ' + CAST(@cnt as varchar);

        EXEC msdb.dbo.sp_send_dbmail @profile_name='SQLAlerts',
            @recipients = '[email protected]',
            @subject = @subject,
            @body = 'blablabla';
    end;
END
GO

単純な更新でそれが発生し、電子メールが送信されます。

update SMSCounter
set [Counter] = 988
where CounterDate = '2012-11-16 00:00:00.000'
1
Marian

これを@queryパラメータで機能させることができなかったため、代わりにHTMLを使用しました

スクリプトは、「sa」またはサービスアカウントを使用してログインしているユーザーを監査します

IF OBJECT_ID ('AuditSqlLogins') IS NOT NULL DROP TABLE AuditSqlLogins 
GO

CREATE TABLE AuditSqlLogins (
    [Counter] [int] IDENTITY(1,1) NOT NULL,
    [Login_name] [varchar](20) NULL,
    [Host_name] [varchar](20) NULL,
    [login_time] [datetime] NULL
) ON [PRIMARY]

INSERT INTO [dbo].[AuditSqlLogins]
    (login_time, login_name, Host_name )

    SELECT login_time, login_name, Host_name 
    FROM sys.dm_exec_sessions 
    WHERE Host_name not like '%APP%'  -- excludeds Apllication server logins
    and Host_name not like '%WWW%'    -- excludeds Web server logins
    and database_id = 5               -- Specify the database you want to audit
    and login_name = 'Appadmin'       -- specify the account you want audited
    or login_name = 'sa'
    ORDER BY Host_name desc

    DELETE FROM AuditSqlLogins
    WHERE Host_name is null

DECLARE @counter integer
SELECT @counter = Counter FROM AuditSqlLogins                         

IF (@counter > 0)
BEGIN 

DECLARE @xml NVARCHAR(MAX)

SET @xml = CAST ( ( SELECT 
          td = login_name  , '',
          td = Host_name, '',
          td = login_time,''

FROM AuditSqlLogins 

FOR XML PATH('tr'), TYPE 
              ) AS NVARCHAR(MAX) )
       DECLARE @body  nvarchar(max);
       SET @body ='
<html>
<body>
<head>
<style>
table {
  border-collapse: collapse;
}
table, th, td {
  border: 1px solid #ea5685;
}
</style>
</head>
<H3>Audit Appadmin and SA Login Event : (Server Name)</H3>  

<table border="1" cellspacing="0" border-spacing="0" style ="text-align:center"> 
<tr style="height:15px; background:#ea8686">
<th border-spacing="0" style="padding:5px 15px;">login_name</th>
<th border-spacing="0" style="padding:5px 15px;">Host_name</th>
<th border-spacing="0" style="padding:5px 15px;">login_time</th>
</tr>
'     
SET @body = @body+@xml+'</table><body>'

EXEC msdb.dbo.sp_send_dbmail
@recipients='[email protected]', 
       @subject = 'Audit itsadmin and SA Login Event',
       @body = @body,
       @body_format = 'HTML' ,
       @profile_name='Your DB Mail profile'        
END
DROP TABLE AuditSqlLogins
1