Send Email for Service Restarts in SQL server

 --Send Email for Service Restarts in SQL server


USE msdb

GO

-- Declare variables for necessary email content

DECLARE @ServerName VARCHAR(128),

@ComputerNamePhysicalNetBIOS VARCHAR(128),

@Datetime DATETIME,

@EmailRecipients VARCHAR(512),

@EmailSubject VARCHAR(128),

@MessageBody VARCHAR(512)


-- Set variables to proper values

SELECT @ComputerNamePhysicalNetBIOS = CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(128)),

@ServerName = CAST(SERVERPROPERTY('ServerName') AS VARCHAR(128)),

@Datetime = GETDATE(),

@EmailRecipients = 'bajeyudu@sqldbanow.com', -- if more than one email address use ; between email addresses

@EmailSubject = 'SQL Server Services Have Been Started!!!'


SELECT @MessageBody = 'SQL Server services have been started on a SQL Server Instance named ' + @ServerName + CHAR(13) +

'running on windows server ' + @ComputerNamePhysicalNetBIOS + '.' + CHAR(13) + CHAR(13) +

'Investigate the service restart if it has not been communicated.'


EXEC sp_send_dbmail

@recipients = @EmailRecipients,

@subject = @EmailSubject,

@body = @MessageBody,

@body_format = 'TEXT'


Suspect Pages Alert in SQL Server

 --By using below mentioned script will get suspect pages report via email 

declare @count integer

declare @tableHTML  nvarchar(MAX);

declare @subj nvarchar(100)


select @count=count(1)

from msdb.dbo.suspect_pages;


set @subj = 'Suspect Pages Found in ' + @@SERVERNAME;


set @tableHTML =

    N'<H1>Suspect Pages Found in ' + @@SERVERNAME + ', details are below.</H1>' +

    N'<table border="1">' +

    N'<tr><th>Database ID</th><th>Database</th>' +

    N'<th>File ID</th><th>File</th><th>Page ID</th>' +

    N'<th>Event Desc</th><th>Error Count</th><th>Last Updated</th></tr>' +

    cast ( ( select td = sp.database_id,       '',

       td = d.name,       '',

       td = sp.file_id,       '',

       td = mf.physical_name,       '',

       td = sp.page_id,       '',

       td = case when sp.event_type = 1 then '823 or 824 error other than a bad checksum or a torn page'

            when sp.event_type = 2 then 'Bad checksum'

            when sp.event_type = 3 then 'Torn Page'

            when sp.event_type = 4 then 'Restored (The page was restored after it was marked bad)'

            when sp.event_type = 5 then 'Repaired (DBCC repaired the page)'

            when sp.event_type = 7 then 'Deallocated by DBCC'

       end,       '',

       td = sp.error_count,       '',

       td = sp.last_update_date

from msdb.dbo.suspect_pages sp

inner join sys.databases d on d.database_id=sp.database_id

inner join sys.master_files mf on mf.database_id=sp.database_id and mf.file_id=sp.file_id

              for xml path('tr'), TYPE 

    ) as nvarchar(max) ) +

    N'</table>' ;


IF @count > 0

  exec msdb.dbo.sp_send_dbmail

    @recipients=N'bandaruajeyudu@outlook.com',

    @body= @tableHTML, 

    @subject = @subj,

    @body_format = 'HTML',

    @profile_name ='SQLMail'



GO


delete from msdb.dbo.suspect_pages

where last_update_date < getdate()-90;

Monitoring SQL Server Jobs: Script to Report Failed Jobs

Managing and monitoring SQL Server jobs is crucial for maintaining the health and performance of your SQL Server environment. One of the key aspects is to ensure that failed jobs are promptly reported and addressed. Below is a script that creates a report of failed SQL Server jobs and sends it via email. This script can be particularly useful for DBAs to automate the monitoring process.

Script Overview

The script performs the following tasks:

  1. Create a Table: A temporary table Failed_Jobs is created to store details of the failed jobs.
  2. Insert Data: Job failure details are inserted into the Failed_Jobs table. This includes jobs that failed in the last 24 hours.
  3. Check for Failures: The script checks if there are any failed jobs.
  4. Send Email: If there are any failures, an HTML-formatted email is sent, listing the details of the failed jobs.
  5. Drop Table: The temporary table is dropped at the end of the script.

Here’s the complete script:

Automatic alert when cluster fail over happened

When  fail over happen, both SQL server and Agent service will get restarted, Then we will get Notification Alert When Fail Over Happened 


DECLARE @importance AS VARCHAR(6)

DECLARE @body AS NVARCHAR(1000)

DECLARE @Subject  AS NVARCHAR(1000)

DECLARE @InstanceName AS VARCHAR(100)DECLARE @NodeName AS NVARCHAR(100)

DECLARE @recipients VARCHAR(100)

SELECT  @InstanceName =@@SERVERNAME

SELECT  @NodeName = CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS NVARCHAR(200))

SELECT  @Subject  = 'Fail over Happened for Instance '+@InstanceName

SELECT  @body = 'Fail over Happened for Instance '+@InstanceName + '. This instance is currently running on the node '+@NodeName

SELECT  @importance ='High'

EXEC msdb.dbo.sp_send_dbmail

     @profile_name ='sqlmail',

         @recipients ='bajeyudu@SQLDBANOW.com;',

     --@recipients=@recipientsList,

     @subject = @subject ,

     @body = @body,

     @body_format = 'HTML' ,

     @importance=@importance

Automating SQL Server Job Status Monitoring with Triggers

As a DBA, it's crucial to stay informed about changes in your SQL Server environment, especially when it comes to job status. Jobs being enabled or disabled can have significant impacts on operations, and timely alerts can help in taking necessary actions. Here, I’ll share a trigger script that automatically sends an email notification whenever a job is enabled or disabled in your SQL Server instance.

Script Overview

This trigger script is designed to:

  1. Monitor Job Status Changes: It detects when a job is enabled or disabled.
  2. Generate Alerts: It sends an email alert with details of the change, including the user who made the change, session ID, and host name.

Here's the complete trigger script:

Blocking alert from SQL Server

Below mentioned script will send the blocking queries which are blocked for more than 5 minutes and we need to create job for below script to run every 10 minutes

SET NOCOUNT ON

DECLARE @xml nvarchar(max)

SELECT @xml = Cast((SELECT @@SERVICENAME AS 'td','',b.session_id AS 'td',

'',

(b.wait_duration_ms/1000)/60 AS 'td',

'',

b.wait_type AS 'td',

'',

b.blocking_session_id AS 'td',

'',

t.text AS 'td'

FROM sys.dm_os_waiting_tasks b inner join sys.dm_exec_requests r on r.session_id= b.session_id

OUTER APPLY

sys.dm_exec_sql_text(sql_handle) t

WHERE b.blocking_session_id <> 0 and b.wait_duration_ms>300000

FOR xml path('tr'), elements) AS NVARCHAR(max))

Declare @body nvarchar(max)

SET @body =

'<html>

<head>

<style>

table, th, td

 {

border: 1px solid black;

border-collapse: collapse;

text-align: center;

}

</style>

</head>

<body>

<H2>

Blocking queries

</H2>

<table>

 <tr>

<th>Instance Name</th><th> Blocked Session ID </th> <th> Wating in minutes </th> <th> Wait type</th>

 <th> Blocking Session ID</th><th>Query waiting to execute</th>

</tr>'

SET @body = @body + @xml + '

</table>

</body>

</html>'

if(@xml is not null)

BEGIN

EXEC msdb.dbo.Sp_send_dbmail

@profile_name = 'sqlmail',

@body = @body,

@body_format ='html',

@recipients = 'bajeyudu@sqldbanow.com',

@copy_recipients ='ajay@sqldbanow.com', -- list of Email recipients

@subject = 'Blocking queries Alert-SQLDBANOWDB01';

END

SET NOCOUNT OFF


If you are not able to shrink tempdb execute below query and try again

  -----If you are not able to shrink tempdb execute below query and try again

USE TempDB

GO

--Use below query for clearing plan cache in the server.

DBCC FREEPROCCACHE

go

--Use below query for clearing buffers from bufferpool.

DBCC DROPCLEANBUFFERS

go

-- Use below query, this will Releases all unused cache entries from all caches.

DBCC FREESYSTEMCACHE ('ALL')

go

Before Database refresh script out user permissions

--Before Database refresh script out user permissions

DECLARE 


    @sql VARCHAR(2048)


    ,@sort INT 

DECLARE tmp CURSOR FOR


/*********************************************/


/*********   DB CONTEXT STATEMENT    *********/


/*********************************************/


SELECT '-- [-- DB CONTEXT --] --' AS [-- SQL STATEMENTS --],


        1 AS [-- RESULT ORDER HOLDER --]


UNION


SELECT  'USE' + SPACE(1) + QUOTENAME(DB_NAME()) AS [-- SQL STATEMENTS --],


        1 AS [-- RESULT ORDER HOLDER --]




UNION




SELECT '' AS [-- SQL STATEMENTS --],


        2 AS [-- RESULT ORDER HOLDER --]


UNION


/*********************************************/


/*********     DB USER CREATION      *********/


/*********************************************/




SELECT '-- [-- DB USERS --] --' AS [-- SQL STATEMENTS --],


        3 AS [-- RESULT ORDER HOLDER --]


UNION


SELECT  'IF NOT EXISTS (SELECT [name] FROM sys.database_principals WHERE [name] = ' + SPACE(1) + '''' + [name] + '''' + ') BEGIN CREATE USER ' + SPACE(1) + QUOTENAME([name]) + ' FOR LOGIN ' + QUOTENAME([name]) + ' WITH DEFAULT_SCHEMA = ' + QUOTENAME([default_schema_name]) + SPACE(1) + 'END; ' AS [-- SQL STATEMENTS --],


        4 AS [-- RESULT ORDER HOLDER --]


FROM    sys.database_principals AS rm


WHERE [type] IN ('U', 'S', 'G') -- windows users, sql users, windows groups




UNION


/*********************************************/


/*********    DB ROLE PERMISSIONS    *********/


/*********************************************/


SELECT '-- [-- DB ROLES --] --' AS [-- SQL STATEMENTS --],


        5 AS [-- RESULT ORDER HOLDER --]


UNION


SELECT  'EXEC sp_addrolemember @rolename ='


    + SPACE(1) + QUOTENAME(USER_NAME(rm.role_principal_id), '''') + ', @membername =' + SPACE(1) + QUOTENAME(USER_NAME(rm.member_principal_id), '''') AS [-- SQL STATEMENTS --],


        6 AS [-- RESULT ORDER HOLDER --]


FROM    sys.database_role_members AS rm


WHERE   USER_NAME(rm.member_principal_id) IN (  


                                                --get user names on the database


                                                SELECT [name]


                                                FROM sys.database_principals


                                                WHERE [principal_id] > 4 -- 0 to 4 are system users/schemas


                                                and [type] IN ('G', 'S', 'U') -- S = SQL user, U = Windows user, G = Windows group


                                              )


--ORDER BY rm.role_principal_id ASC


UNION


SELECT '' AS [-- SQL STATEMENTS --],


        7 AS [-- RESULT ORDER HOLDER --]

UNION


/*********************************************/


/*********  OBJECT LEVEL PERMISSIONS *********/


/*********************************************/


SELECT '-- [-- OBJECT LEVEL PERMISSIONS --] --' AS [-- SQL STATEMENTS --],


        8 AS [-- RESULT ORDER HOLDER --]


UNION


SELECT  CASE 


            WHEN perm.state <> 'W' THEN perm.state_desc 


            ELSE 'GRANT'


        END


        + SPACE(1) + perm.permission_name + SPACE(1) + 'ON ' + QUOTENAME(SCHEMA_NAME(obj.schema_id)) + '.' + QUOTENAME(obj.name) --select, execute, etc on specific objects


        + CASE


                WHEN cl.column_id IS NULL THEN SPACE(0)


                ELSE '(' + QUOTENAME(cl.name) + ')'


          END


        + SPACE(1) + 'TO' + SPACE(1) + QUOTENAME(USER_NAME(usr.principal_id)) COLLATE database_default


        + CASE 


                WHEN perm.state <> 'W' THEN SPACE(0)


                ELSE SPACE(1) + 'WITH GRANT OPTION'


          END


            AS [-- SQL STATEMENTS --],


        9 AS [-- RESULT ORDER HOLDER --]


FROM    


    sys.database_permissions AS perm


        INNER JOIN


    sys.objects AS obj


            ON perm.major_id = obj.[object_id]


        INNER JOIN


    sys.database_principals AS usr


            ON perm.grantee_principal_id = usr.principal_id


        LEFT JOIN


    sys.columns AS cl


            ON cl.column_id = perm.minor_id AND cl.[object_id] = perm.major_id


--WHERE usr.name = @OldUser


--ORDER BY perm.permission_name ASC, perm.state_desc ASC


UNION


SELECT '' AS [-- SQL STATEMENTS --],


    10 AS [-- RESULT ORDER HOLDER --]



UNION


/*********************************************/


/*********    DB LEVEL PERMISSIONS   *********/


/*********************************************/


SELECT '-- [--DB LEVEL PERMISSIONS --] --' AS [-- SQL STATEMENTS --],


        11 AS [-- RESULT ORDER HOLDER --]


UNION


SELECT  CASE 


            WHEN perm.state <> 'W' THEN perm.state_desc --W=Grant With Grant Option


            ELSE 'GRANT'


        END


    + SPACE(1) + perm.permission_name --CONNECT, etc


    + SPACE(1) + 'TO' + SPACE(1) + '[' + USER_NAME(usr.principal_id) + ']' COLLATE database_default --TO <user name>


    + CASE 


            WHEN perm.state <> 'W' THEN SPACE(0) 


            ELSE SPACE(1) + 'WITH GRANT OPTION' 


      END


        AS [-- SQL STATEMENTS --],


        12 AS [-- RESULT ORDER HOLDER --]


FROM    sys.database_permissions AS perm


    INNER JOIN


    sys.database_principals AS usr


    ON perm.grantee_principal_id = usr.principal_id


--WHERE usr.name = @OldUser


WHERE   [perm].[major_id] = 0


    AND [usr].[principal_id] > 4 -- 0 to 4 are system users/schemas


    AND [usr].[type] IN ('G', 'S', 'U') -- S = SQL user, U = Windows user, G = Windows group


UNION


SELECT '' AS [-- SQL STATEMENTS --],


        13 AS [-- RESULT ORDER HOLDER --]

UNION 


SELECT '-- [--DB LEVEL SCHEMA PERMISSIONS --] --' AS [-- SQL STATEMENTS --],


        14 AS [-- RESULT ORDER HOLDER --]


UNION


SELECT  CASE


            WHEN perm.state <> 'W' THEN perm.state_desc --W=Grant With Grant Option


            ELSE 'GRANT'


            END


                + SPACE(1) + perm.permission_name --CONNECT, etc


                + SPACE(1) + 'ON' + SPACE(1) + class_desc + '::' COLLATE database_default --TO <user name>


                + QUOTENAME(SCHEMA_NAME(major_id))


                + SPACE(1) + 'TO' + SPACE(1) + QUOTENAME(USER_NAME(grantee_principal_id)) COLLATE database_default


                + CASE


                    WHEN perm.state <> 'W' THEN SPACE(0)


                    ELSE SPACE(1) + 'WITH GRANT OPTION'


                    END


            AS [-- SQL STATEMENTS --],


        15 AS [-- RESULT ORDER HOLDER --]


from sys.database_permissions AS perm


    inner join sys.schemas s


        on perm.major_id = s.schema_id


    inner join sys.database_principals dbprin


        on perm.grantee_principal_id = dbprin.principal_id


WHERE class = 3 --class 3 = schema


ORDER BY [-- RESULT ORDER HOLDER --]


OPEN tmp


FETCH NEXT FROM tmp INTO @sql, @sort


WHILE @@FETCH_STATUS = 0


BEGIN


        PRINT @sql


        FETCH NEXT FROM tmp INTO @sql, @sort    

END

CLOSE tmp


DEALLOCATE tmp 

Known issues with Azure SQL Managed Instance

Known issues with Azure SQL Managed Instance