4

Does anyone have a good Sql Alert which sends email notifications, when query Blocking has occurred over many minutes? I know how to write my own, however seems to be a good code library on internet. Please also give answer without event notification if possible.

I like this one below: Email Notification when Blocking Occurs

I refrain from these as they utilize sys.processes which I hear is being deprecated: Automatically Detect Blocking

Email Notification when Blocking Occurs

This is similar as first, however does not have as much detail: Find Long Running Queries

Trying to locate good solution or consensus, before implementing. Feel free to send solution or edit one below.

Thanks,

Note: One below seems to have an unnecessary temp table step, which probably can be eliminated, with just one sql email.

*/
 SET NOCOUNT ON

-- Checked for currently running queries by putting data in temp table
SELECT s.session_id
    ,r.STATUS
    ,r.blocking_session_id
    ,r.wait_type
    ,wait_resource
    ,r.wait_time / (1000.0) 'WaitSec'
    ,r.cpu_time
    ,r.logical_reads
    ,r.reads
    ,r.writes
    ,r.total_elapsed_time / (1000.0) 'ElapsSec'
    ,Substring(st.TEXT, (r.statement_start_offset / 2) + 1, (
            (
                CASE r.statement_end_offset
                    WHEN - 1
                        THEN Datalength(st.TEXT)
                    ELSE r.statement_end_offset
                    END - r.statement_start_offset
                ) / 2
            ) + 1) AS statement_text
    ,Coalesce(Quotename(Db_name(st.dbid)) + N'.' + Quotename(Object_schema_name(st.objectid, st.dbid)) + N'.' + Quotename(Object_name(st.objectid, st.dbid)), '') AS command_text
    ,r.command
    ,s.login_name
    ,s.host_name
    ,s.program_name
    ,s.host_process_id
    ,s.last_request_end_time
    ,s.login_time
    ,r.open_transaction_count
INTO #temp_requests
FROM sys.dm_exec_sessions AS s
INNER JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
WHERE r.session_id != @@SPID
ORDER BY r.cpu_time DESC
    ,r.STATUS
    ,r.blocking_session_id
    ,s.session_id

IF (
        SELECT count(*)
        FROM #temp_requests
        WHERE blocking_session_id > 50
        ) <> 0
BEGIN
    -- blocking found, sent email. 
    DECLARE @tableHTML NVARCHAR(MAX);

    SET @tableHTML = N'<H1>Blocking Report</H1>' + N'<table border="1">' + N'<tr>' + N'<th>session_id</th>' + N'<th>Status</th>' + 
                     N'<th>blocking_session_id</th><th>wait_type</th><th>wait_resource</th>' + 
                     N'<th>WaitSec</th>' + N'<th>cpu_time</th>' + 
                     N'<th>logical_reads</th>' + N'<th>reads</th>' +
                     N'<th>writes</th>' + N'<th>ElapsSec</th>' + N'<th>statement_text</th>' + N'<th>command_text</th>' + 
                     N'<th>command</th>' + N'<th>login_name</th>' + N'<th>host_name</th>' + N'<th>program_name</th>' + 
                     N'<th>host_process_id</th>' + N'<th>last_request_end_time</th>' + N'<th>login_time</th>' + 
                     N'<th>open_transaction_count</th>' + '</tr>' + CAST((
                SELECT td = s.session_id
                    ,''
                    ,td = r.STATUS
                    ,''
                    ,td = r.blocking_session_id
                    ,''
                    ,td = r.wait_type
                    ,''
                    ,td = wait_resource
                    ,''
                    ,td = r.wait_time / (1000.0)
                    ,''
                    ,td = r.cpu_time
                    ,''
                    ,td = r.logical_reads
                    ,''
                    ,td = r.reads
                    ,''
                    ,td = r.writes
                    ,''
                    ,td = r.total_elapsed_time / (1000.0)
                    ,''
                    ,td = Substring(st.TEXT, (r.statement_start_offset / 2) + 1, (
                            (
                                CASE r.statement_end_offset
                                    WHEN - 1
                                        THEN Datalength(st.TEXT)
                                    ELSE r.statement_end_offset
                                    END - r.statement_start_offset
                                ) / 2
                            ) + 1)
                    ,''
                    ,td = Coalesce(Quotename(Db_name(st.dbid)) + N'.' + Quotename(Object_schema_name(st.objectid, st.dbid)) +
                        N'.' + Quotename(Object_name(st.objectid, st.dbid)), '')
                    ,''
                    ,td = r.command
                    ,''
                    ,td = s.login_name
                    ,''
                    ,td = s.host_name
                    ,''
                    ,td = s.program_name
                    ,''
                    ,td = s.host_process_id
                    ,''
                    ,td = s.last_request_end_time
                    ,''
                    ,td = s.login_time
                    ,''
                    ,td = r.open_transaction_count
                FROM sys.dm_exec_sessions AS s
                INNER JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id
                CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
                WHERE r.session_id != @@SPID
                    AND blocking_session_id > 0
                ORDER BY r.cpu_time DESC
                    ,r.STATUS
                    ,r.blocking_session_id
                    ,s.session_id
                FOR XML PATH('tr')
                    ,TYPE
                ) AS NVARCHAR(MAX)) + N'</table>';

    EXEC msdb.dbo.sp_send_dbmail @body = @tableHTML
        ,@body_format = 'HTML'
        ,@profile_name = N'Database Mail'
        ,@recipients = N'blakhani@outlook.com'
        ,@Subject = N'Blocking Detected'
END

DROP TABLE #temp_requests
4

I wrote Blocking Detector which uses event notification. You can find it here

Below is how it works :

This script will create 
    - a blocking detection alert
    - table to hold blocking information
    - modify the 'blocked process threshold' sp_configure option to 5 mins (300 sec) 
    - create a sql agent job that will fire in resonse to the alert to capture blocking info

Full script :

/**************************************************************************************
Author:     KIN SHAH
Date    :   03/02/2011

Adapt the script as per your env --> places to change ---- CHANGE HERE !!

This script will create 
    - a blocking detection alert
    - table to hold blocking information
    - modify the 'blocked process threshold' sp_configure option to 5 mins (300 sec) 
    - create a sql agent job that will fire in resonse to the alert to capture blocking info

Disclaimer
The views expressed on my posts on this site are mine alone and do not reflect the views of my company. All posts of mine are provided "AS IS" with no warranties, and confers no rights.

The following disclaimer applies to all code, scripts and demos available on my posts:

This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 

I grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute the object code form of the Sample Code, provided that You agree: 

(i)     to use my name, logo, or trademarks to market Your software product in which the Sample Code is embedded; 
(ii)    to include a valid copyright notice on Your software product in which the Sample Code is embedded; and 
(iii)   to indemnify, hold harmless, and defend me from and against any claims or lawsuits, including attorneys’ fees, that arise or result from the use or distribution of the Sample Code.

************************************************************************************/
USE [dbaalert] ---- CHANGE HERE !!
GO

IF OBJECT_ID('dbo.Scores', 'U') IS NOT NULL
 drop table [dbo].[BlockingInfo];
-- *************change the blocking threshold to 5mins (300sec) ********** ---- 
EXEC sp_configure 'blocked process threshold', 300 ---- CHANGE HERE !!
go
reconfigure with override
go
--------- **** create table to hold blocking data ********* ----------

/****** Object:  Table [dbo].[BlockingInfo]    Script Date: 02/17/2011 15:41:35 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[BlockingInfo](
    [RecordId] [int] IDENTITY(1,1) NOT NULL,
    [AlertTime] [datetime] NOT NULL,
    [BlockingDetails] [xml] NULL,
    [Notified] [int] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [RecordId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[BlockingInfo] ADD  CONSTRAINT [DF_blocking_flag]  DEFAULT ((0)) FOR [Notified]
GO
SET QUOTED_IDENTIFIER OFF;
GO
---------------------------- disable old and create new job---------------------------------------------
USE [msdb]
GO

--- disable old job on the server
IF  EXISTS (SELECT name FROM msdb.dbo.sysjobs WHERE name = N'DBA Group - Monitoring - Blocking Detector')
EXEC msdb.dbo.sp_update_job @job_name=N'DBA Group - Monitoring - Blocking Detector', @enabled = 0
GO

USE [msdb]
GO

/****** Object:  Job [DBA Group - Monitoring - Blocked Process Detector]    Script Date: 03/02/2011 11:47:32 ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [[Uncategorized (Local)]]]    Script Date: 03/02/2011 11:47:33 ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

END

DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'DBA Group - Monitoring - Blocked Process Detector', 
        @enabled=1, 
        @notify_level_eventlog=0, 
        @notify_level_email=0, 
        @notify_level_netsend=0, 
        @notify_level_page=0, 
        @delete_level=0, 
        @description=N'Authors: Kin Shah', 
        @category_name=N'[Uncategorized (Local)]', 
        @owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Insert Blocking info]    Script Date: 03/02/2011 11:47:34 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Insert Blocking info', 
        @step_id=1, 
        @cmdexec_success_code=0, 
        @on_success_action=3, 
        @on_success_step_id=0, 
        @on_fail_action=2, 
        @on_fail_step_id=0, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'TSQL', 
        @command=N'INSERT INTO dbo.BlockingInfo (

AlertTime,

BlockingDetails

)

VALUES (

GETDATE(),

''$(ESCAPE_NONE(WMI(TextData)))''

)', 
        @database_name=N'dbaalert', 
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Send Email]    Script Date: 03/02/2011 11:47:35 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Send Email', 
        @step_id=2, 
        @cmdexec_success_code=0, 
        @on_success_action=3, 
        @on_success_step_id=0, 
        @on_fail_action=2, 
        @on_fail_step_id=0, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'TSQL', 
        @command=N'
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO
if exists (select 1 from dbo.BlockingInfo where Notified = 0 ) 
begin

DECLARE @AlertTime datetime
DECLARE @BlockingDetails xml
DECLARE @RecordID int
-- Block Events table.
if object_id (''tempdb..#BlockEvents'') > 0 drop table #BlockEvents
create table #BlockEvents (
AlertTime datetime,
BlockingDetails xml,
RecordID int
) ;
if object_id (''tempdb..#dba_job_name'') > 0 
drop table #dba_job_name
create table #dba_job_name
(
 id int identity (1,1),
 job_sid varchar(256) NULL,
 job_name varchar(256) NULL 
)
-- Block Info table.
if object_id (''tempdb..#BlockInfo'') > 0 
drop table #BlockInfo
create table #BlockInfo (
RecordID int,
BlockedDBName  sysname null,
BlockedHostName sysname null,
BlockingDBName  sysname null,
BlockingHostName sysname null,
BlockedWaitResource varchar (256) NULL,
WaitTime_sec int null,
BlockedTransactionName varchar(256) NULL,
BlockedSPID int NULL,
BlockedProgram varchar(256) NULL,
BlockedProgram_sid varchar(256) NULL,
BlockedProgram_jn varchar(256) NULL,
BlockingSPID int NULL,
BlockingProgram varchar(256) NULL,
BlockingProgram_sid varchar(256) NULL,
BlockingProgram_jn varchar(256) NULL

) ;

-- Get all blocking events within selected period.
INSERT INTO #BlockEvents (
AlertTime,
BlockingDetails,
RecordID
)

SELECT
AlertTime,
BlockingDetails,
RecordID
FROM dbo.BlockingInfo where Notified = 0;

WHILE EXISTS (SELECT RecordID FROM #BlockEvents)

BEGIN
    SELECT TOP 1 @AlertTime = AlertTime,
    @BlockingDetails = BlockingDetails,
    @RecordID = RecordID
    FROM #BlockEvents
    ORDER BY RecordID DESC

    -- Insert into temporary table for processing.

    INSERT INTO #BlockInfo
    SELECT @RecordID,db_name(a.BlockedCurrentDb),a.BlockedHostName,db_name(a.BlockingCurrentDb),a.BlockingHostName, a.BlockedWaitResource
    ,a.BlockedWaitTime/(1000) as WaitTime_sec,a.BlockedTransactionName,a.BlockedSPID,a.BlockedProgram,null,null
    ,a.BlockingSPID,a.BlockingProgram,null,null
    FROM
    (SELECT
    ref.value(''./blocked-process[1]/process[1]/@waitresource'', ''varchar(512)'') AS BlockedWaitResource,
    ref.value(''./blocked-process[1]/process[1]/@waittime'', ''int'') AS BlockedWaitTime,
    ref.value(''./blocked-process[1]/process[1]/@transactionname'', ''sysname'') AS BlockedTransactionName,
    ref.value(''./blocked-process[1]/process[1]/@spid'', ''int'') AS BlockedSPID,
    ref.value(''./blocked-process[1]/process[1]/@clientapp'', ''varchar(256)'') AS BlockedProgram,
    ref.value(''./blocked-process[1]/process[1]/@hostname'', ''varchar(256)'') AS BlockedHostName,
    ref.value(''./blocked-process[1]/process[1]/@loginname'', ''varchar(256)'') AS BlockedLoginName,
    ref.value(''./blocked-process[1]/process[1]/@currentdb'', ''varchar(256)'') AS BlockedCurrentDb,

    ref.value(''./blocking-process[1]/process[1]/@waitresource'', ''varchar(512)'') AS BlockingWaitResource,
    ref.value(''./blocking-process[1]/process[1]/@waittime'', ''int'') AS BlockingWaitTime,
    ref.value(''./blocking-process[1]/process[1]/@transactionname'', ''sysname'') AS BlockingTransactionName,
    ref.value(''./blocking-process[1]/process[1]/@spid'', ''int'') AS BlockingSPID,
    ref.value(''./blocking-process[1]/process[1]/@clientapp'', ''varchar(256)'') AS BlockingProgram,
    ref.value(''./blocking-process[1]/process[1]/@hostname'', ''varchar(256)'') AS BlockingHostName,
    ref.value(''./blocking-process[1]/process[1]/@loginname'', ''varchar(256)'') AS BlockingLoginName,
    ref.value(''./blocking-process[1]/process[1]/@currentdb'', ''varchar(256)'') AS BlockingCurrentDb
    FROM @BlockingDetails.nodes(''//blocked-process-report'')
    AS node(ref)) AS a

    DELETE FROM #BlockEvents
    WHERE RecordID = @RecordID

END

insert into #dba_job_name (job_sid)
select distinct left(right(([BlockedProgram]),44),34) from #BlockInfo where lower(BlockedProgram) like ''sqlagent%''
union
select distinct left(right(([BlockingProgram]),44),34) from #BlockInfo where lower(BlockingProgram) like ''sqlagent%''

-- update job_name on #dba_job_name
-- Due to uniqueidentifier problem, we need to run under @sqltext
declare @cur int,@tol int
select @cur=1,@tol =0
select @tol= max(id) from #dba_job_name
declare @job_id varchar(max),@sqltext varchar(max)

while (@cur<=@tol)
begin
    select @job_id = job_sid from #dba_job_name where id = @cur
    select @sqltext=''update #dba_job_name set job_name  = (select [name]  from msdb..sysjobs with (nolock) where job_id = ''+@job_id+'') where id =''+convert(varchar(max),@cur)
    exec (@sqltext);
   select @cur=@cur+1
end

-- strip out job_id
update #BlockInfo 
set BlockedProgram_sid = case when (lower(BlockedProgram) like ''sqlagent%'') then left(right(([BlockedProgram]),44),34) end,
    BlockingProgram_sid = case when (lower(BlockingProgram) like ''sqlagent%'') then left(right(([BlockingProgram]),44),34) end

-- update job_name for BlockedProgram
update b
set b.BlockedProgram_jn = j.job_name
from #BlockInfo b join #dba_job_name j
on b.BlockedProgram_sid = j.job_sid

-- update job_name for BlockingProgram
update b
set b.BlockingProgram_jn = j.job_name
from #BlockInfo b join #dba_job_name j
on b.BlockingProgram_sid = j.job_sid

declare @tableHTML nvarchar(max)
set @tableHTML =N''<H3><FONT SIZE="3" FACE="Tahoma">Blocking Has occured.. Please Investigate on ''+ @@servername +''</FONT></H3>''
set @tableHTML = @tableHTML + N''<table border="1">'' +
           N''<FONT SIZE="2" FACE="Calibri">'' +            
            N''<tr><th align="center">RecordId</th>'' +
            N''<th align="center">BlockedDBName</th>'' +
            N''<th align="center">BlockedHostName</th>'' +
            N''<th align="center">BlockingDBName</th>'' +
            N''<th align="center">BlockingHostName</th>'' +
        N''<th align="center">BlockedWaitResource</th>'' +
        N''<th align="center">WaitTime_sec</th>'' +
        N''<th align="center">BlockedTransactionName</th>'' +
        N''<th align="center">BlockedSPID</th>'' +
        N''<th align="center">BlockedProgram</th>'' +
        N''<th align="center">BlockingSPID</th>'' +
        N''<th align="center">BlockingProgram</th>'' +
            N''</tr>'' +
           ISNULL(CAST ( ( 
                            select  td = '''',
                                    td = ISNULL(RecordId,''''),'''',
                                    td = ISNULL(BlockedDBName,''**No data available**''),'''',
                                    td = ISNULL(BlockedHostName,''**No data available**''),'''',
                                    td = ISNULL(BlockingDBName,''**No data available**''),'''',
                                    td = ISNULL(BlockingHostName,''**No data available**''),'''',
                                    td = ISNULL(BlockedWaitResource,''**No data available**''),'''',
                                    td = ISNULL(WaitTime_sec,''''),'''',
                                    td = ISNULL(BlockedTransactionName,''**No data available**''),'''',
                                    td = ISNULL(BlockedSPID,''''),'''',
                                    td = ISNULL(COALESCE(BlockedProgram_jn,BlockedProgram),''**No data available**''),'''',
                                    td = ISNULL(BlockingSPID,''''),'''',
                                    td = ISNULL(COALESCE(BlockingProgram_jn,BlockingProgram),''**No data available**''),''''
                              from #BlockInfo where  BlockingDBName is not null 

    FOR XML PATH(''tr''), TYPE 

            ) AS NVARCHAR(MAX) ),'''') +
            N''</FONT>'' +
            N''</table>'' ;
   ------------ send email         
declare @subject1 varchar(50)
set @subject1 = ''Blocked Process Report for ''+@@servername
EXEC msdb.dbo.sp_send_dbmail 
            @profile_name = ''You db mail profile'',            ---- CHANGE HERE !!
            @recipients=''yourcompanyDBATEAM@company.com'',     ---- CHANGE HERE !!
            @subject = @subject1,
            @body = @tableHTML,
            @body_format = ''HTML'' ;
end
go

-- drop all temp tables
if object_id (''tempdb..#BlockEvents'') > 0 drop table #BlockEvents
if object_id (''tempdb..#dba_job_name'') > 0 drop table #dba_job_name
if object_id (''tempdb..#BlockInfo'') > 0 drop table #BlockInfo

-- update the BlockingInfo table so that when the job runs it wont send out alert
update  dbo.BlockingInfo
set Notified = 1 where Notified = 0

', 
        @database_name=N'dbaalert', ---- CHANGE HERE !!
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Trim Records Older than 15 days]    Script Date: 03/02/2011 11:47:35 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Trim Records Older than 15 days', 
        @step_id=3, 
        @cmdexec_success_code=0, 
        @on_success_action=1, 
        @on_success_step_id=0, 
        @on_fail_action=2, 
        @on_fail_step_id=0, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'TSQL', 
        @command=N'use dbaalert   ---- CHANGE HERE !!
go
declare @starttime datetime
-- trim records older than 15 days
select @starttime = CONVERT(varchar,GETDATE()-15,112) 
--select @starttime
delete from BlockingInfo where convert(varchar, AlertTime, 112) <= @starttime and Notified =1', 
        @database_name=N'master', 
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO

------------ create alert (this is dynamic for default and named instances)
USE [msdb]
GO
-- create an WMI alert to respond to blocking 
IF EXISTS (SELECT name FROM msdb.dbo.sysalerts WHERE name = N'Respond to Blocking')
EXEC msdb.dbo.sp_delete_alert @name=N'Respond to Blocking'
GO
DECLARE @server_namespace varchar(255)
IF ISNULL(CHARINDEX('\', @@SERVERNAME), 0) > 0
SET @server_namespace = N'\\.\root\Microsoft\SqlServer\ServerEvents\' + SUBSTRING(@@SERVERNAME, ISNULL(CHARINDEX('\', @@SERVERNAME), 0) + 1, LEN(@@SERVERNAME) - ISNULL(CHARINDEX('/', @@SERVERNAME), 0))
ELSE
SET @server_namespace = N'\\.\root\Microsoft\SqlServer\ServerEvents\MSSQLSERVER'
EXEC msdb.dbo.sp_add_alert @name=N'Respond to Blocking',
@wmi_namespace=@server_namespace,
@wmi_query=N'SELECT * FROM BLOCKED_PROCESS_REPORT', 
@job_name=N'DBA Group - Monitoring - Blocked Process Detector' ---- CHANGE HERE  job name!!
GO

Another alternatives that uses DMVs are (Customize as per your needs) :

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy