Friday, 26 July 2019

SQL Server Agent Jobs that Have No Notification and Notification Change


SQL Server Agent Jobs that Have No Notification and Notification Change

If you want to verify each of your SQL Agent jobs have email notification then you can run this code:


USE msdb
SELECT name, notify_email_operator_id  
FROM dbo.sysjobs 

This code will display each SQL Server Agent job that doesn’t have an operator associated with an email notification operator.

USE msdb
SELECT name, notify_email_operator_id  
FROM dbo.sysjobs 
WHERE notify_email_operator_id = 0;

OR


SELECT @@servername as Server_name, j.name AS JobName,
      e.name AS EmailOperator
         ,j.enabled As Enabled
FROM msdb.dbo.sysjobs j
  LEFT JOIN msdb.dbo.sysoperators e
     on j.notify_email_operator_id = e.id
        where j.enabled=1
1=enabled
0=Disabled

Based on requirement please change the where condition.

IF server doesn't have any operator use below script to create a new operator. Below script I created an operator named "DBA-SQL" and associated it with the email address “DBA-SQL@Company.com” or else use GUI from SSMS.

USE [msdb]

GO
EXEC msdb.dbo.sp_add_operator @name=N'DBA-SQL',
                    @enabled=1,
                    @email_address=N'DBA-SQL@compenay.com'
GO


Automatically Updating SQL Agent Jobs to Have Notification:


If you already have a number of SQL Server agent jobs in one server where notification hasn’t been set up you might want to set up each job to notify someone.   
If you have a lot of SQL Agent jobs it might take a while for you to go through each job to define an email notification operator manually through the SQL Agent GUI.  
A better way to change a bunch of SQL Agent jobs to send email notifications would be to run a script.  

Here is a sample script for defining an operator on each job that doesn’t already have an email operator:


USE [msdb]

SET NOCOUNT ON;
DECLARE @Operator varchar(50) = 'DBA-SQL' -- place your operator name here
SELECT 'EXEC sp_update_job @job_name = ''' + j.[name] +
''', @notify_email_operator_name = ''' + @Operator +
''', @notify_level_email = 2'-- 1=On Success, 2=On Faulure,3=always
FROM dbo.sysjobs j
WHERE j.enabled = 1
AND j.notify_level_email <> 1

This script doesn’t actually add the operators to SQL Agent jobs that don’t have email notification.   But instead it just creates a series of EXEC statements that when executed add the email notifications.  The series of EXEC statements that this script generates will run the sp_update_job system stored procedures to add an email operator.  This particular script only adds email notification on a job that doesn’t already have email notification.  Additionally, it only sets up notification to occur when the job execution fails.   If you should happen to want different operators to be notified for different jobs then you will either need to add some special code to place the appropriate operator on each job, or run the above script then modify the operators for each job prior to executing the generated script.


If you have multiple servers to change the notification use below script and run using batch command or power-shell.

set nocount on

DECLARE @strsql    NVARCHAR(MAX)
DECLARE @job_list cursor

set @job_list = cursor for
SELECT     'EXEC msdb..sp_update_job @job_name = ''' + j.[name] + ''', @notify_email_operator_name = ''DBA-SQL'', @notify_level_email = 2' [exec_sql]
FROM msdb.dbo.sysjobs j
  LEFT JOIN msdb.dbo.sysoperators e
     on j.notify_email_operator_id = e.id
        where j.enabled =--Change according to you requirement
      
open @job_list
fetch next from @job_list into @strsql
while @@FETCH_STATUS = 0
begin
       exec sp_executesql @strsql
       fetch next from @job_list into @strsql
end
close @job_list
deallocate @job_list

Please test in test\dev server then use in prodcution.

Find the run-time status for all SQL Server Agent jobs

Use below script to Find the run-time status for all SQL Server Agent jobs

use msdb
go



SELECT
        sj.Name,
                 CASE
                      WHEN sja.start_execution_date IS NULL THEN 'Not running'
                      WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL THEN 'Running'
                      WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NOT NULL THEN 'Not running'
                      END  AS 'RunStatus'
FROM   msdb.dbo.sysjobs sj
JOIN   msdb.dbo.sysjobactivity sja
ON     sj.job_id = sja.job_id
WHERE  sja.session_id =
                    (SELECT MAX (session_id) FROM msdb.dbo.sysjobactivity)
order by RunStatus desc

Search SQL Agent Job using Specific keyword text or SP - 2000\2005\08\08R2\12\14\16\17\19

SQL Server 2000 Job Step Search

USE [msdb]
GO
SELECT    jb.job_id,
       jb.originating_server,
       jb.name,
       js.step_id,
       js.command,
       jb.enabled
FROM    dbo.sysjobs jb
JOIN    dbo.sysjobsteps js
       ON    js.job_id = jb.job_id
WHERE    js.command LIKE N'%KEYWORD_SEARCH%'

Search SQL Server Agent Job Steps for Specific Keyword Text or Stored Procedure-2005\08\08R2\12\14\16\17\19

SELECT 
       jb.job_id,
       js.srvname,
       jb.name,
       js.step_id,
       js.command,
       jb.enabled
FROM    msdb.dbo.sysjobs jb
JOIN    msdb.dbo.sysjobsteps js
       ON    js.job_id = jb.job_id
JOIN    master..sysservers s
       ON    js.srvid = jb.originating_server_id
WHERE    js.command LIKE N'%KEYWORD_SEARCH%'
GO



How to find Job owner for all SQL Server Agent Jobs and change the owner

How to find Job owner for all SQL Server Agent Jobs and change the owner

We got below error from so many servers in my organisation.

Error: "The job failed.  The owner '' of job '' does not have server access."

Causes: Most of the below cases.
1. Logins does not exists
2. Job owner left from the organization
3. Jobs owner disabled state.

That means a DBA had created a SQL Server Agent  job with his name as owner. Once he/she will leave the company and account will be removed from AD, the jobs will start failing.

It is good to use 'service account' or 'sa' as SQL Server Job owner, so you don't have to worry in case owner leave the company.

Fix:

Single job we can fix manually but multiple servers multiple jobs how can we fix this issue, so that we found a way using below script by joining the below tables and query.

master.sys.syslogins--Find the login Name
msdb..sysjobs--Find the jobs Name

Below query will return your server job names and respective job owners.


SELECT SJ.NAME AS JobName
    ,SL.NAME AS OwnerName
FROM msdb..sysjobs SJ
LEFT JOIN master.sys.syslogins SL ON SJ.owner_sid = SL.sid
  
Or

Adding little more stuff for serverName, job which is enabled\disabled state.

SELECT                     @@servername as Server_name,

                                 sj.name, CASE
                                                      WHEN sj.enabled = 1 THEN 'Enable'
                                                      ELSE 'Disable'
                                               END             AS JobStatus,
                                 SUSER_SNAME(sj.owner_sid) AS owner
from                msdb..sysjobs_view sj
left outer join master.sys.syslogins sl on sj.owner_sid = sl.sid
where               SUSER_SNAME(sj.owner_sid) <> 'sa'
or                         SUSER_SNAME(sj.owner_sid)  is null


Now if we would like to update all the job where owner is not 'sa', we can use below query. So you can also modify the query to filter the jobs for which you would like to update owner.

--Please provide the New Owner for The Jobs you like to Change, I am using sa

DECLARE @OWNERName VARCHAR(100)
SET @OWNERName = 'sa'--please change SA or SQL Instance service account
DECLARE @OldJobOwner VARCHAR(100)
DECLARE @JobName VARCHAR(1000)
DECLARE Job_Cursor CURSOR
FOR

--Change your Query as per requirements, I am selecting all Job where owner<>sa

SELECT SJ.NAME AS JobName
    ,SL.NAME
AS OwnerName
FROM msdb..sysjobs SJ
LEFT JOIN master.sys.syslogins SL ON SJ.owner_sid = SL.sid
WHERE L.NAME <> @OWNERName

OPEN Job_Cursor --Open a cursor
FETCH NEXT FROM Job_Cursor  --Fetch Data from cursor

INTO @JobName
    ,@OldJobOwner
WHILE (@@FETCH_STATUS <> - 1)

BEGIN
   
EXEC msdb..sp_update_job @job_name         = @JobName
                            ,@owner_login_name = @OWNERName

PRINT 'Ownerd Change for ' + @JobName + 'Job from ' + @OldJobOwner + ' to '
 + @OWNERName

FETCH NEXT
   
FROM Job_Cursor
   
INTO @JobName
        ,@OldJobOwner
END

CLOSE Job_Cursor -- Close the cursor
DEALLOCATE Job_Cursor --De-allocate the cursor

You can wrap up by creating the stored procedure with @OWNERName parameter and use that stored procedure as a job in every server to change the job owners to 'sa' or 'service account'. 

Just to be safe side please initially test is 'TEST\DEV' server and then move to production.

Disable CDC at table level

 How to Disable CDC( Change Data Capture) for tables Change Data Capture (cdc) property is disabled as default.  here I will Query you how t...