http://www.sqldisco.com

Comments: (0)

Generic SSRS 2008 report to display job history of SQL Server Agent jobs

Category : SQL Server, SSRS, T-SQL, Uncategorized

I have made a generic report in Reporting Services 2008 to browse and display the job history of SQL Server Agent. This is very useful if you want to see what jobs fail the most, when do jobs overlap, is execution time increasing for a specific job etc. If you have many jobs, it can be quite useful to set up a subscription on this report, so you can see every day the status of alle the SQL Server Agent jobs. I use this report on all SQL Server Instances i control. I also recommend increasing the number of log entries stored in the log table on msdb to increase the usefulness of the report.  The report is made in Reporting Services 2008, but the query against log data works against 2005 and up.

The user account accessing the SQL Server database needs read-acces to msdb, and the report has two parameters:

  • Search – For entering search strings. Useful if your project for example as prefixed job names with the project name
  • Include Subscriptions – This parameter is useful if SQL Server has many reporting services subscriptions running. SSRS Subscriptions has a GUID as the name of the SQL Server Agent job, so they are quite easy to filter out.

Download here: http://www.sqldisco.com/files/Jobstatus.zip

Let me know if you find it useful, or if you have any recommended improvements I can implement.

Comments: (0)

Search sql server metadata quickly

Category : SQL Server, T-SQL

Just figured out a neat way to quickly search metadata easily when working with SQL. If you use SQL Prompt from Red Gate, I suggest adding the following as a new snippet (I use FF):

1
2
3
SELECT RTRIM(so.name) + '.' + RTRIM(sc.name) AS DBObjectName 
FROM SYSOBJECTS so INNER JOIN syscolumns sc ON so.id = sc.id
WHERE so.type = 'U' AND (sc.name+' '+so.name) LIKE '%

Very handy to always have search ready at your fingertips, especially when working with data extraction from unfamiliar databases.

Comments: (0)

Alerts on subscriptions failing

Category : SQL Server, SSRS, T-SQL

I have a customer that have hundreds of subscriptions on their report server. Sometimes subscriptions fail, but there’s no built in solutions to recieve alerts when subscriptions are failing as far as I know. For this customer we use SQL Server 2008, and to recieve alerts on failed subscriptions, I used the following SQL to make a report (copied from http://www.theruntime.com):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
WITH    [SUBJECT] ( [SubscriptionID], [SubjectLine] )
	AS ( SELECT   I.[SubscriptionID],
	I1.ROWS.VALUE('Value [1]', 'VARCHAR(500)') AS [SubjectLine]
FROM	(SELECT    S.[SubscriptionID],
                        CONVERT(XML, N'<Root>'
                        + CONVERT(NVARCHAR(MAX), S.[ExtensionSettings])
                        + N'&lt;/Root&gt;') AS [ExtensionSettings]
              FROM      ReportServer.dbo.[Subscriptions] S WITH ( NOLOCK )
              WHERE     S.[DeliveryExtension] = 'Report Server Email'
            ) I
            CROSS APPLY I.ExtensionSettings.nodes('/Root/ParameterValues/ParameterValue')
            AS I1 ( ROWS )
			WHERE    I1.ROWS.VALUE('Name [1]', 'VARCHAR(100)') = 'Subject'
         )
SELECT  S.[SubscriptionID],
        S.[InactiveFlags],
        S.[ExtensionSettings],
        [SUBJECT].[SubjectLine],
        S.[ModifiedDate],
        S.[Description],
        S.[LastStatus],
        S.[EventType],
        S.[MatchData],
        S.[LastRunTime],
        S.[DeliveryExtension],
        SC.[StartDate],
        SC.[EndDate],
        SC.[Flags],
        SC.[RecurrenceType],
        SC.[STATE],
        C.[PATH],
        C.[Name],
        [U1].[UserName] AS [Owner],
        [U2].[UserName] AS [ModifiedBy],
        [URL] = 'http://SERVER/Reports_Sql2008/Pages/SubscriptionProperties.aspx?ItemPath='
        + C.[PATH] + '&IsDataDriven=False&SubscriptionID='
        + CAST(S.[SubscriptionID] AS VARCHAR(80)),
        [URL2] = 'http://SERVER/Reports_Sql2008/Pages/Report.aspx?ItemPath='
        + C.[PATH] + '&SelectedTabId=SubscriptionsTab'
FROM    ReportServer.dbo.[Subscriptions] S WITH ( NOLOCK )
        LEFT OUTER JOIN ReportServer.dbo.[CATALOG] C WITH ( NOLOCK ) ON S.[Report_OID] = C.[ItemID]
        LEFT OUTER JOIN ReportServer.dbo.[Users] [U1] WITH ( NOLOCK ) ON S.[OwnerID] = [U1].[UserID]
        LEFT OUTER JOIN ReportServer.dbo.[Users] [U2] WITH ( NOLOCK ) ON S.[ModifiedByID] = [U2].[UserID]
        LEFT OUTER JOIN ReportServer.dbo.[ReportSchedule] RS WITH ( NOLOCK )
			ON S.[SubscriptionID] = RS.[SubscriptionID]
        LEFT OUTER JOIN ReportServer.dbo.[Schedule] SC WITH ( NOLOCK ) ON RS.[ScheduleID] = SC.[ScheduleID]
        LEFT OUTER JOIN [SUBJECT] ON S.[SubscriptionID] = [SUBJECT].[SubscriptionID]
WHERE   UPPER(LEFT(S.[LastStatus], 7)) = 'FAILURE'

I also used the URL2-field to make a link from the subscription report to the actual subscription that has failed to make it easier for the customer to correct the mistakes in the subscription.

When the subscription report was ready, I set it up as a one time / run once subscription. I found the name of the SQL Server Agent job by running this query (it should be the top one) :

1
2
3
4
5
SELECT  schedule.scheduleid
FROM    subscriptions
        LEFT JOIN reportschedule ON subscriptions.subscriptionid = reportschedule.subscriptionid
        LEFT JOIN schedule ON schedule.scheduleid = reportschedule.scheduleid
ORDER BY subscriptions.modifieddate DESC

I then copied the SQL from the step in the Server Agent Job, and wrapped it in a “IF EXISTS”. The resulting query was put into a new sql server agent job which run daily:

1
2
3
4
5
6
7
8
9
10
11
IF EXISTS (SELECT  *
                FROM    Subscriptions
                WHERE  UPPER(LEFT(Subscriptions.[LastStatus], 7)) = 'FAILURE' AND
                            LastRunTime>=DATEADD(dd,-1,GETDATE()) 
              )
    BEGIN
        --SQL From the run-once SQL Server Agent Job should look something like this:
        EXEC ReportServer.dbo.AddEvent @EventType='TimedSubscription',
        @EventData='0326035a-ed10-4bd3-9b37-14341d49d3dc'
 
    END

This triggers the report every morning only if there have been failed subscriptions during the last 24 hours, and make it easy for the customer to fix the failed subscriptions. They can also change who recieves the subscription alert by changing the subscription of the “subscription report”

Comments: (0)

Beware of the <> operator

Category : SQL Server, T-SQL

I noticed somthing interesting today about NULL handling. This is very basic stuff, but if it’s new to me, then it’s disco material.

Say you have a table with one integer column:

CREATE TABLE Table1(Column1 INT)

With the following values:

INSERT INTO Table1 VALUES (NULL) 
INSERT INTO Table1 VALUES (0) 
INSERT INTO Table1 VALUES (1)

You might think that the following two queries produce inverse results, but they don’t:

SELECT Column1, 
 CASE WHEN Column1&lt;&gt;0 THEN 'TRUE' ELSE 'FALSE' END AS Column2 
 FROM Table1      
 
NULL	FALSE 
0	FALSE 
1	TRUE      
 
SELECT Column1, 
 CASE WHEN Column1=0 THEN 'TRUE' ELSE 'FALSE' END AS Column2 
 FROM Table1      
 
NULL	FALSE 
0	TRUE 
1	FALSE

Comments: (6)

Grouping datetime by date in T-SQL

Category : SQL Server, T-SQL

In reporting it is very common to group a datetime by date / day. There are several ways to do this, and I have done some testing on a large table I have. Listed here are four ways, from best to worst. The performance increase by changing a query from the worst (Which I have seen being used several times!) to the best might be the difference between a query taking 10 minutes and a query taking 10 seconds. CRETS is a datetime column.

--Use this: :)
SELECT DATEADD(dd,(DATEDIFF(dd,0,CRETS)),0),
COUNT(*)
FROM Table1 GROUP BY DATEADD(dd,(DATEDIFF(dd,0,CRETS)),0)
 
SELECT CAST(DATEDIFF(dd,0,CRETS) AS DATETIME),
COUNT(*)
FROM Table1 GROUP BY CAST(DATEDIFF(dd,0,CRETS) AS DATETIME)
 
SELECT DATEPART(dd,CRETS) AS [DAY],
DATEPART(mm,CRETS) AS [MONTH],
DATEPART(yyyy,CRETS) AS [YEAR],
COUNT(*)
FROM Table1
GROUP BY DATEPART(dd,CRETS), DATEPART(mm,CRETS), DATEPART(yyyy,CRETS)
 
--Don't use this:
SELECT CONVERT(DATETIME, CONVERT(NCHAR(10), CRETS, 121)),
COUNT(*)
FROM Table1
GROUP BY CONVERT(DATETIME, CONVERT(NCHAR(10), CRETS, 121))