Find error in jobsteps of all jobs that ran over night [duplicate] - sql

I want write a query to get the last 24 hours worth of job record from the "msdb.dbo.sysjobhistory" table, but I can't get because I get the "run_date" and "run_time" columns are returned as a number. How can I convert the "run_date" and "run_time" columns into a datetime variable, and use this to get the last 24 hour job history?

Check out this post - it shows how to "decode" those run_date columns from sysjobhistory.
You should be able to get the entries from the last 24 hours with a query something like this:
SELECT
j.name as JobName,
LastRunDateTime =
CONVERT(DATETIME, CONVERT(CHAR(8), run_date, 112) + ' '
+ STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(8), run_time), 6), 5, 0, ':'), 3, 0, ':'), 121)
FROM
msdb..sysjobs j
INNER JOIN
msdb..sysjobhistory jh ON j.job_id = jh.job_id
WHERE
CONVERT(DATETIME, CONVERT(CHAR(8), run_date, 112) + ' '
+ STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(8), run_time), 6), 5, 0, ':'), 3, 0, ':'), 121) > DATEADD(HOUR, -24, GETDATE())

For databases after 2000, there is a function in the msdb database you can call that will return datetime:
msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime'
If you are using sql 2000, you can copy the source of that function from a later version and create it in your instance of 2000. I wish I could take credit for all of this, but I originally found it here: mssqltips.com

A co-worker of mine pointed out that the other given solutions only find jobs that we're started 24 hours ago (or less), not jobs that were completed 24 hours ago (or less). He proposed something along the lines of the following to location completed jobs:
SELECT j.name AS JobName
,LastCompletedDateTime = DATEADD(day, (run_duration / 240000), CONVERT(DATETIME, msdb.dbo.agent_datetime(run_date, run_time))) +
STUFF(STUFF(REPLACE(STR((run_duration % 240000), 7, 0), ' ', '0'), 4, 0, ':'), 7, 0, ':')
FROM msdb..sysjobs j
INNER JOIN msdb..sysjobhistory jh ON j.job_id = jh.job_id
WHERE DATEADD(day, (run_duration / 240000), CONVERT(DATETIME, msdb.dbo.agent_datetime(run_date, run_time))) +
STUFF(STUFF(REPLACE(STR((run_duration % 240000), 7, 0), ' ', '0'), 4, 0, ':'), 7, 0, ':') > DATEADD(HOUR, - 24, GETDATE())
I believe part of this comes from a blog, but we cannot locate it, when I do I'll link that as well...

Related

How do I covert a number to a date in SQL?

I have a field named SECURED that has dates listed as 123120, 040320 which is actually 12/31/20 or 4/03/20.
I was able to convert the date in the SELECT area with:
SELECT LEFT(SECURED, 2) + '/' + replace(replace(SECURED, LEFT(SECURED, 2), ''),
RIGHT(SECURED, 2), '') + '/' + RIGHT(SECURED, 2) as 'Modified SECURED as Date'
WHERE CONVERT(date, SECURED, 101)
BETWEEN CONVERT(date, getdate() - 30, 101)
AND CONVERT(date, getdate(), 101)
How can I pull in information from the SECURED column with a date of 30 days ago?
It doesn't work and still sees a date as a number.
You can use datefromparts() to convert your string to a date:
datefromparts(
concat('20', substring(secured, 5, 2)),
substring(secured, 1, 2),
substring(secured, 3, 2)
)
Then you can check it against a given interval:
datefromparts(
concat('20', substring(secured, 5, 2)),
substring(secured, 1, 2),
substring(secured, 3, 2)
) between dateadd(day -30, cast(getdate() as date)) and cast(getdate() as date)
If secured is a string, you can do a little manipulation and a simple cast():
select convert(date, concat('20', right(secured, 2), left(secured, 4))
You might find it convenient to actually create a computed column so this is always available:
alter table t add secured_date as (try_convert(date, concat('20', right(secured, 2), left(secured, 4))
You can even persist the column and create an index, so your queries are more efficient.
There're many ways to convert a 6 digits INT to DATE:
You can do a convertion using LTRIM and CAST like this:
SELECT CAST(RIGHT(LTRIM(123120),2) + LEFT(LTRIM(123120),4) AS DATE)
Using LTRIM with SUBSTRING:
SELECT CAST(SUBSTRING(LTRIM(040320), 5, 2) + SUBSTRING(LTRIM(040320), 1, 4) AS DATE)
Using CONVERT:
SELECT CAST((RIGHT(CONVERT(VARCHAR(6), 123120),2) +
LEFT(CONVERT(VARCHAR(6), 123120),4)) AS DATE)
Or using CONVERT with SUBSTRING:
SELECT CAST(SUBSTRING(CONVERT(VARCHAR(6), 040320), 5, 2) +
SUBSTRING(CONVERT(VARCHAR(6), 040320), 1, 4) AS DATE)
Using STR:
SELECT CAST(RIGHT(STR(123120, 6) ,2) + LEFT(STR(123120, 6) ,4) AS DATE)
Or using STR with SUBSTRING:
SELECT CAST(SUBSTRING(STR(040320, 6), 5, 2) + SUBSTRING(STR(040320, 6), 1, 4) AS DATE)
This casting will format the date as expected but your dates need be
in format mmddyy
Standard EUA (style 10) DATE format (mm-dd-yy) without century (yy)
Edit after comments:
What's the table name of this query?
What's the SECURED field datatype? INT? VARCHAR?
You need convert a date and compare between last 30 days and today?
The query below resolve your problem? (change TABLE_NAME to your table name)
SELECT LEFT(SECURED, 2) + '/' + replace(replace(SECURED, LEFT(SECURED, 2), ''),
RIGHT(SECURED, 2), '') + '/' + RIGHT(SECURED, 2) as 'Modified SECURED as Date'
FROM TABLE_NAME
WHERE CAST(RIGHT(LTRIM(SECURED), 2) + LEFT(LTRIM(SECURED), 4) AS DATE)
BETWEEN GETDATE() - 30 AND GETDATE()

Varchar to Datetime in TSQL

How can I convert date and time value stored like
20200406151341
to DATETIME value 2020/04/06 15:31:41 (YYYY/MM/DD HH:MM:SS.000)? I am unable to find suitable CONVERT() format and the only way so far is to parse the VARCHAR like below.
select dateadd(second, cast(substring('20200406151341',13,2) as int),dateadd(minute, cast(substring('20200406151341',11,2) as int), dateadd(hour,cast(substring('20200406151341',9,2) as int),convert(datetime, left('20200406151341',8), 112)))).
It works yet it's hard to read and understand especially when I have to use it within SELECT statement multiple times.
Also I am surprised query with above conversions is as fast the one with dates stored directly in DATETIME format. Does MSSQL server uses some kind of cache so it does have to do the conversion only once per row?
I use MSSQL Server 2016.
I don't think there is a built in, simple way to do this.
You don't have to go to seconds to do this. You can easily convert the first 8 characters to a date. With some string manipulation, you can convert the last six to a time -- and then add time (as datetime values):
select convert(datetime, left(dt, 8)) + convert(datetime, stuff(stuff(right(dt, 6), 5, 0, ':'), 3, 0, ':'))
from (values ('20200406151341')) v(dt);
You can also use arithmetic rather than 3 dateadd()s:
select dateadd(second,
right(dt, 2) + 60*substring(dt, 11, 2) + 60*60*substring(dt, 9, 2),
convert(datetime, left(dt, 8)))
from (values ('20200406151341')) v(dt)
Note: This uses implicit conversion from a string to an integer (as does your version).
You can use stuff() :
select convert(datetime,
stuff(stuff(stuff(stuff(col, 9, 0, ' '), 10, 0, ''), 12, 0, ':'), 15, 0, ':'
)
Let's throw in a couple more options to the mix:
DECLARE #StrDate varchar(14) = '20200406151341'
SELECT DATETIMEFROMPARTS(
LEFT(#StrDate, 4), -- year
SUBSTRING(#StrDate, 5, 2), -- month
SUBSTRING(#StrDate, 7, 2), -- day
SUBSTRING(#StrDate, 9, 2), -- hour
SUBSTRING(#StrDate, 11, 2), -- minute
SUBSTRING(#StrDate, 13, 2), -- second
0 -- millisecond
) As [Using DateTimeFromParst],
CONVERT(DateTime, LEFT(#StrDate, 8), 112) + -- Date
CONVERT(DateTime, STUFF(STUFF(RIGHT(#StrDate, 6), 5, 0, ':'), 3, 0, ':'), 114) -- Time
As [Using convert and stuff]
Results:
Using DateTimeFromParst Using convert and stuff
2020-04-06 15:13:41 2020-04-06 15:13:41
I suggest using try_convert() or try_cast() in case your strings are invalid, and if invalid they will return NULL instead of raising an error. Refer to the links for further detail on these functions.
declare #val varchar(20)
set #val = '20200416151341'
select try_convert(datetime,
stuff(stuff(stuff(stuff(#val, 9, 0, ' '), 10, 0, ''), 12, 0, ':'), 15, 0, ':')
);
select try_cast(
stuff(stuff(stuff(stuff(#val, 9, 0, ' '), 10, 0, ''), 12, 0, ':'), 15, 0, ':')
as datetime);

Get List of all failed SSIS package on a particuar date

Hi everyone is there any way we can get list of all failed packages on any particular date , can we do this with a SQL query ?
We are using SSIS 2017 .
Assuming the package is deployed to SSISDB and ran from the catalog, query the SSISDB.CATALOG.EXECUTIONS DMV for executions with a status of 4. Packages with a status of 4 resulted in failure, as specified in the documentation. Since the start_time column is of the datetimeoffset date type and I'm assuming you only want to query by the date, not time, that a package failed, this column is cast to a date below in order for it to default to midnight.
SELECT EXECUTION_ID
,FOLDER_NAME
,PROJECT_NAME
,PACKAGE_NAME
,REFERENCE_ID
,REFERENCE_TYPE
,ENVIRONMENT_FOLDER_NAME
,ENVIRONMENT_NAME
,[OBJECT_ID]
,[STATUS]
,START_TIME
,END_TIME
,CALLER_SID
,CALLER_NAME
,SERVER_NAME
,MACHINE_NAME
FROM SSISDB.CATALOG.EXECUTIONS
--4 for failed packages
WHERE [STATUS] = 4 AND CAST(START_TIME AS DATE) = '2019-01-01'
Hi try this sql query for sql agents jobs Link:
SELECT sj.name,
sh.run_date,
sh.step_name,
STUFF(STUFF(RIGHT(REPLICATE('0', 6) + CAST(sh.run_time as varchar(6)), 6), 3, 0, ':'), 6, 0, ':') 'run_time',
STUFF(STUFF(STUFF(RIGHT(REPLICATE('0', 8) + CAST(sh.run_duration as varchar(8)), 8), 3, 0, ':'), 6, 0, ':'), 9, 0, ':') 'run_duration (DD:HH:MM:SS) ',
sh.run_status
FROM msdb.dbo.sysjobs sj
JOIN msdb.dbo.sysjobhistory sh
ON sj.job_id = sh.job_id
WHERE sh.run_status = 0
AND sh.run_date = '20190122'

SQL Server Agent - Unique ID for Each Job Execution

I have this query that provides a lot of useful info for my scheduled jobs but there is one thing I am still missing. I am trying to locate a unique ID for every job execution, not the instance or schedule ID. Does this exist, and of so how would I join it to the current tables I'm using? Any assistance is appreciated.
Thanks!
Edit: I know I can create a unique ID for jobs that run once per day but most of the jobs run multiple time per day. Some run every 2 minutes.
SELECT h.instance_id
, j.job_id
,j.name AS JobName
,CASE
WHEN h.step_name = '(Job outcome)'
THEN 'Job Run Time'
ELSE h.step_name
END AS StepName
,h.step_id
,CAST(STR(h.run_date, 8, 0) AS DATETIME) + CAST(STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR(6)), 6), 5, 0, ':'), 3, 0, ':') AS DATETIME) AS StartDatetime
,DATEADD(SECOND, ((h.run_duration / 1000000 * 86400 + (h.run_duration - h.run_duration / 1000000 * 1000000) / 10000 * 3600) + (h.run_duration - h.run_duration / 10000 * 10000) / 100 * 60) + (h.run_duration - h.run_duration / 100 * 100), CAST(STR(h.run_date, 8, 0) AS DATETIME) + CAST(STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR(6)), 6), 5, 0, ':'), 3, 0, ':') AS DATETIME)) AS EndDatetime
,CASE
WHEN STUFF(STUFF(REPLACE(STR(h.run_duration, 6, 0), ' ', '0'), 3, 0, ':'), 6, 0, ':') > '23:59:00'
THEN '23:59:00'
ELSE STUFF(STUFF(REPLACE(STR(h.run_duration, 6, 0), ' ', '0'), 3, 0, ':'), 6, 0, ':')
END AS run_duration_formatted
,((h.run_duration / 1000000 * 86400 + (h.run_duration - h.run_duration / 1000000 * 1000000) / 10000 * 3600) + (h.run_duration - h.run_duration / 10000 * 10000) / 100 * 60) + (h.run_duration - h.run_duration / 100 * 100) AS RunDurationInSeconds
,CASE h.run_status
WHEN 0
THEN 'Failed'
WHEN 1
THEN 'Succeded'
WHEN 2
THEN 'Retry'
WHEN 3
THEN 'Cancelled'
WHEN 4
THEN 'In Progress'
END AS ExecutionStatus
FROM msdb.dbo.sysjobhistory AS h
INNER JOIN msdb.dbo.sysjobs AS j ON j.job_id = h.job_id
LEFT JOIN [msdb].[dbo].[sysjobactivity] A ON A.job_id = h.job_id
WHERE (j.enabled = 1)
AND A.session_id = 1053
AND (CAST(STR(h.run_date, 8, 0) AS DATETIME) + CAST(STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR(6)), 6), 5, 0, ':'), 3, 0, ':') AS DATETIME) >= DATEADD(dd, - 1, CAST(GETDATE() AS DATE)))
Order by instance_id
Maybe use with dense_rank() and using distinct?
SELECT distinct h.instance_id
, dense_rank() over (order by j.job_id, h.run_date, h.run_time)
, j.job_id
,j.name AS JobName
,CASE
WHEN h.step_name = '(Job outcome)'
THEN 'Job Run Time'
ELSE h.step_name
END AS StepName
,h.step_id
,CAST(STR(h.run_date, 8, 0) AS DATETIME) + CAST(STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR(6)), 6), 5, 0, ':'), 3, 0, ':') AS DATETIME) AS StartDatetime
,DATEADD(SECOND, ((h.run_duration / 1000000 * 86400 + (h.run_duration - h.run_duration / 1000000 * 1000000) / 10000 * 3600) + (h.run_duration - h.run_duration / 10000 * 10000) / 100 * 60) + (h.run_duration - h.run_duration / 100 * 100), CAST(STR(h.run_date, 8, 0) AS DATETIME) + CAST(STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR(6)), 6), 5, 0, ':'), 3, 0, ':') AS DATETIME)) AS EndDatetime
,CASE
WHEN STUFF(STUFF(REPLACE(STR(h.run_duration, 6, 0), ' ', '0'), 3, 0, ':'), 6, 0, ':') > '23:59:00'
THEN '23:59:00'
ELSE STUFF(STUFF(REPLACE(STR(h.run_duration, 6, 0), ' ', '0'), 3, 0, ':'), 6, 0, ':')
END AS run_duration_formatted
,((h.run_duration / 1000000 * 86400 + (h.run_duration - h.run_duration / 1000000 * 1000000) / 10000 * 3600) + (h.run_duration - h.run_duration / 10000 * 10000) / 100 * 60) + (h.run_duration - h.run_duration / 100 * 100) AS RunDurationInSeconds
,CASE h.run_status
WHEN 0
THEN 'Failed'
WHEN 1
THEN 'Succeded'
WHEN 2
THEN 'Retry'
WHEN 3
THEN 'Cancelled'
WHEN 4
THEN 'In Progress'
END AS ExecutionStatus
FROM msdb.dbo.sysjobhistory AS h
INNER JOIN msdb.dbo.sysjobs AS j ON j.job_id = h.job_id
LEFT JOIN [msdb].[dbo].[sysjobactivity] A ON A.job_id = h.job_id
WHERE (j.enabled = 1)
--AND A.session_id = 1053
AND (CAST(STR(h.run_date, 8, 0) AS DATETIME) + CAST(STUFF(STUFF(RIGHT('000000' + CAST(h.run_time AS VARCHAR(6)), 6), 5, 0, ':'), 3, 0, ':') AS DATETIME) >= DATEADD(dd, - 1, CAST(GETDATE() AS DATE)))
Order by j.job_id, instance_id
Edit: The table I used in this query is populated every 5 minutes with the data from the first query I posted.
OK, I couldn't find a unique ID for each schedule execution so I had to rethink what I could do. The query is below.
This solved my problem. I have a Google chart embedded in SharePoint that lists the jobs and the run times. Each bar represents how long the job took to run. Prior to this solution the chart only showed a failed status if the last step failed. Now with this incorporated I can see if any step failed withing each job execution. This is fantastic! In the image below you can see the red executions had a step failure within the job.
SELECT D.[instance_id]
,[JobName]
,[StepName]
,[step_id]
,[Run_Date]
,[StartDatetime]
,[StartTime]
,[EndDatetime]
,[End_Time]
,[Run_Duration_Formatted]
,[RunDurationInSeconds]
,MAX(CASE WHEN C.ExecutionStatus IS NULL THEN D.[ExecutionStatus] ELSE C.ExecutionStatus END) AS ExecutionStatus
FROM [STG_EDW].[dbo].[Job_Runs_FINAL] AS D
LEFT JOIN
(
SELECT Step0.Instance_ID
,'Failed' AS ExecutionStatus
FROM(
SELECT [instance_id]
,[JobName]
,[StartDatetime]
,[EndDatetime]
FROM [My Table]
WHERE step_id = 0) AS Step0
INNER JOIN(
SELECT Instance_ID, JobName, [StartDatetime], [EndDatetime]
FROM [My Table]
WHERE ExecutionStatus = 'Failed') AS B ON Step0.JobName = B.JobName AND B.StartDatetime >= Step0.StartDatetime AND B.EndDatetime <= Step0.EndDatetime
) AS C ON D.instance_id = C.instance_id
Group By D.[instance_id]
,[JobName]
,[StepName]
,[step_id]
,[Run_Date]
,[StartDatetime]
,[StartTime]
,[EndDatetime]
,[End_Time]
,[Run_Duration_Formatted]
,[RunDurationInSeconds]

SQL Server : format 700 as time

I've run an import which has updated many records in my tblRota.StartTime and tblRota.EndTime in the format 900 and 1700.
How can I reformat these to 09:00 and 17:00?
The datatypes of both columns is varchar.
Thank you.
You could use this query:
select stuff(right('0' + replace([StartTime], ':', ''), 4), 3, 0, ':'),
stuff(right('0' + replace([EndTime], ':', ''), 4), 3, 0, ':')
from [tblRota]
The steps are:
Remove the :: replace([StartTime], ':', '')
Get the time on 4 digits: right('0' + <3Or4DigitTime>, 4)
Insert the :: stuff(<4DigitTime>, 3, 0, ':')
Use some string manipulation:
UPDATE tblRota
SET StartTime = LEFT(RIGHT('0'+StartTime , 4),2)+':'+RIGHT(StartTime ,2),
EndTime = LEFT(RIGHT('0'+EndTime , 4),2)+':'+RIGHT(EndTime ,2)