SQL - How to find currently running job steps through TSQL - sql

I am writing a query to find currently running job in SQL (I know we can view it in Job Active Monitor, but I've a need to do in TSQL). Though I can query sysjobactivity table to find currently running job, it's nowhere telling what job step is running (because my job might have more than 1 step).
Query I used:
SELECT s.name AS [JOB_NAME],
'' AS [STEP_ID],
'' AS STEP_NAME,
'Processing' AS STATUS,
sja.run_requested_date AS START_TIME,
null AS END_DATE,
convert(varchar, (getdate() - sja.run_requested_date), 8) AS Duration
FROM sysjobactivity sja, sysjobs s
WHERE sja.job_id = s.job_id
AND sja.run_requested_date > getdate() - 1
AND sja.stop_execution_date IS NULL
Please help me finding the step ID & Step name in which the job is currently progressing.

I think below script help to get SQL Jobs with current execution step, try this
msdb.dbo.sp_help_job #execution_status = 1

DECLARE #StepCount INT
SELECT #StepCount = COUNT(1)
FROM msdb.dbo.sysjobsteps
WHERE job_id = '0523333-5C24-1526-8391-AA84749345666' --JobID
SELECT
[JobName]
,[JobStepID]
,[JobStepName]
,[JobStepStatus]
,[RunDateTime]
,[RunDuration]
FROM
(
SELECT
j.[name] AS [JobName]
,Jh.[step_id] AS [JobStepID]
,jh.[step_name] AS [JobStepName]
,CASE
WHEN jh.[run_status] = 0 THEN 'Failed'
WHEN jh.[run_status] = 1 THEN 'Succeeded'
WHEN jh.[run_status] = 2 THEN 'Retry (step only)'
WHEN jh.[run_status] = 3 THEN 'Canceled'
WHEN jh.[run_status] = 4 THEN 'In-progress message'
WHEN jh.[run_status] = 5 THEN 'Unknown'
ELSE 'N/A'
END AS [JobStepStatus]
,msdb.dbo.agent_datetime(run_date, run_time) AS [RunDateTime]
,CAST(jh.[run_duration]/10000 AS VARCHAR) + ':' + CAST(jh.[run_duration]/100%100 AS VARCHAR) + ':' + CAST(jh.[run_duration]%100 AS VARCHAR) AS [RunDuration]
,ROW_NUMBER() OVER
(
PARTITION BY jh.[run_date]
ORDER BY jh.[run_date] DESC, jh.[run_time] DESC
) AS [RowNumber]
FROM
msdb.[dbo].[sysjobhistory] jh
INNER JOIN msdb.[dbo].[sysjobs] j
ON jh.[job_id] = j.[job_id]
WHERE
j.[name] = 'ProcessCubes' --Job Name
AND jh.[step_id] > 0
AND CAST(RTRIM(run_date) AS DATE) = CAST(GETDATE() AS DATE) --Current Date
) A
WHERE
[RowNumber] <= #StepCount
AND [JobStepStatus] = 'Failed'

Try this:
SELECT distinct
cast([sJOB].[job_id] as varchar(max)) AS execution_id
, [sJSTP].[step_name] AS executable_name
, [sJOB].[name] AS package_name
, CASE [sJSTP].[run_date]
WHEN 0 THEN NULL
ELSE
CAST(
CAST([sJSTP].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJSTP].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END AS start_time,
dateadd(ss, run_duration, CASE [sJSTP].[run_date]
WHEN 0 THEN NULL
ELSE
CAST(
CAST([sJSTP].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJSTP].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END) end_time
-- , [sJSTP].[run_duration] [looptijd in minuten]
, CASE [sJSTP].[run_status]
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Success'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Cancelled'
WHEN 5 THEN 'Unknown'
END AS execution_result_description
FROM
[msdb].[dbo].[sysjobhistory] AS [sJSTP]
INNER JOIN [msdb].[dbo].[sysjobs] AS [sJOB]
ON [sJSTP].[job_id] = [sJOB].[job_id]
inner join [msdb].[dbo].[sysjobsteps] steps
ON [sJSTP].[job_id] = [steps].[job_id]
where [sJSTP].[run_date] <> 0
and CASE [sJSTP].[run_date]
WHEN 0 THEN NULL
ELSE
CAST(
CAST([sJSTP].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJSTP].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END between dateadd(hh, -20, getdate()) and getdate()
and [sJSTP].[step_name] not in ('(Job outcome)')
order by start_time desc
Additionally I use this query to see step result from a running SSIS job. However, this only shows you the finished steps, not the running ones. I still have to find an SQL to see the currently running step and merge it with this one.
select distinct
cast(e.execution_id as varchar(max)),
e.executable_name,
e.package_name,
CONVERT(datetime, es.start_time) AS start_time
, CONVERT(datetime, es.end_time) AS end_time
, datediff(mi, es.start_time, es.end_time) [running time]
, case es.execution_result
when 0 then 'Success'
when 1 then 'Failed'
when 2 then 'Completion'
when 3 then 'Cancelled'
else cast(es.execution_result as varchar(max)) end as execution_result_description
from ssisdb.catalog.executables e
left join ssisdb.catalog.executable_statistics es
on e.executable_id = es.executable_id
and e.execution_id = es.execution_id
order by 6 desc

Related

Getting execution status of SQL Server Agent Job in SQL Server 2012

I am trying to get currently executing job status in SQL Server 2012. I have tried using sp_help_job procedure to get it using execution_status as argument also used run_status/status but it is not returning any value.
Please help
SELECT
[sJOB].[job_id] AS [JobID]
, [sJOB].[name] AS [JobName]
, CASE
WHEN [sJOBH].[run_date] IS NULL OR [sJOBH].[run_time] IS NULL THEN NULL
ELSE CAST(
CAST([sJOBH].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJOBH].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END AS [LastRunDateTime]
, CASE [sJOBH].[run_status]
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Canceled'
WHEN 4 THEN 'Running' -- In Progress
END AS [LastRunStatus]
, STUFF(
STUFF(RIGHT('000000' + CAST([sJOBH].[run_duration] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS [LastRunDuration (HH:MM:SS)]
, [sJOBH].[message] AS [LastRunStatusMessage]
, CASE [sJOBSCH].[NextRunDate]
WHEN 0 THEN NULL
ELSE CAST(
CAST([sJOBSCH].[NextRunDate] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJOBSCH].[NextRunTime] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END AS [NextRunDateTime]
FROM
[msdb].[dbo].[sysjobs] AS [sJOB]
LEFT JOIN (
SELECT
[job_id]
, MIN([next_run_date]) AS [NextRunDate]
, MIN([next_run_time]) AS [NextRunTime]
FROM [msdb].[dbo].[sysjobschedules]
GROUP BY [job_id]
) AS [sJOBSCH]
ON [sJOB].[job_id] = [sJOBSCH].[job_id]
LEFT JOIN (
SELECT
[job_id]
, [run_date]
, [run_time]
, [run_status]
, [run_duration]
, [message]
, ROW_NUMBER() OVER (
PARTITION BY [job_id]
ORDER BY [run_date] DESC, [run_time] DESC
) AS RowNumber
FROM [msdb].[dbo].[sysjobhistory]
WHERE [step_id] = 0
) AS [sJOBH]
ON [sJOB].[job_id] = [sJOBH].[job_id]
AND [sJOBH].[RowNumber] = 1
AND [Jobname] = #Jobname
ORDER BY [JobName]

Sql agent job last run status

I have N jobs with M steps in each, that could change any time(Add/delete some steps). Jobs have different schedule to run. I want a query to get last run status, job id, job name of each job. Is it right way to do this scenario by (Job outcome) ?
This is the query I use (a little tuned) to check job status. This variation will select the last job outcome for each job.
SELECT
JobName = J.name,
H.*
FROM
msdb.dbo.sysjobs AS J
CROSS APPLY (
SELECT TOP 1
JobName = J.name,
StepNumber = T.step_id,
StepName = T.step_name,
StepStatus = CASE T.run_status
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Canceled'
ELSE 'Running' END,
ExecutedAt = msdb.dbo.agent_datetime(T.run_date, T.run_time),
ExecutingHours = ((T.run_duration/10000 * 3600 + (T.run_duration/100) % 100 * 60 + T.run_duration % 100 + 31 ) / 60) / 60,
ExecutingMinutes = ((T.run_duration/10000 * 3600 + (T.run_duration/100) % 100 * 60 + T.run_duration % 100 + 31 ) / 60) % 60,
Message = T.message
FROM
msdb.dbo.sysjobhistory AS T
WHERE
T.job_id = J.job_id
ORDER BY
T.instance_id DESC) AS H
ORDER BY
J.name
If you change the TOP 1 for TOP 2, then you will also see the last step executed, aside from the job outcome.
You can not get everything in a single query and need more research. For e.g., to know Job execution information you can try the following query.
SELECT
[sJOB].[job_id] AS [JobID]
, [sJOB].[name] AS [JobName]
, CASE
WHEN [sJOBH].[run_date] IS NULL OR [sJOBH].[run_time] IS NULL THEN NULL
ELSE CAST(
CAST([sJOBH].[run_date] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJOBH].[run_time] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END AS [LastRunDateTime]
, CASE [sJOBH].[run_status]
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Canceled'
WHEN 4 THEN 'Running' -- In Progress
END AS [LastRunStatus]
, STUFF(
STUFF(RIGHT('000000' + CAST([sJOBH].[run_duration] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS [LastRunDuration (HH:MM:SS)]
, [sJOBH].[message] AS [LastRunStatusMessage]
, CASE [sJOBSCH].[NextRunDate]
WHEN 0 THEN NULL
ELSE CAST(
CAST([sJOBSCH].[NextRunDate] AS CHAR(8))
+ ' '
+ STUFF(
STUFF(RIGHT('000000' + CAST([sJOBSCH].[NextRunTime] AS VARCHAR(6)), 6)
, 3, 0, ':')
, 6, 0, ':')
AS DATETIME)
END AS [NextRunDateTime]
FROM
[msdb].[dbo].[sysjobs] AS [sJOB]
LEFT JOIN (
SELECT
[job_id]
, MIN([next_run_date]) AS [NextRunDate]
, MIN([next_run_time]) AS [NextRunTime]
FROM [msdb].[dbo].[sysjobschedules]
GROUP BY [job_id]
) AS [sJOBSCH]
ON [sJOB].[job_id] = [sJOBSCH].[job_id]
LEFT JOIN (
SELECT
[job_id]
, [run_date]
, [run_time]
, [run_status]
, [run_duration]
, [message]
, ROW_NUMBER() OVER (
PARTITION BY [job_id]
ORDER BY [run_date] DESC, [run_time] DESC
) AS RowNumber
FROM [msdb].[dbo].[sysjobhistory]
WHERE [step_id] = 0
) AS [sJOBH]
ON [sJOB].[job_id] = [sJOBH].[job_id]
AND [sJOBH].[RowNumber] = 1
ORDER BY [JobName]
You can get and learn in details - Here and Here

joining select statements?

I would like to do a inner join in my query but I don´t know how to summarize my two select statements into one query.
This is the first query:
select
Machine
, EventDefinition
, Duration
, sum(Duration) over (partition by 1) As Total
, Duration/sum(Duration) over (partition by 1)*100 AS Distribution
,case when EventCategory < 0.05 Then 'NOT INCL' ELSE 'OK' END AS Under3Min
from (
Select
SystemName AS Machine
, EventDefinition
, EventDate
, EventStartDateTime
, IsNull(EventEndDateTime, GETDATE()) as EventEndDateTime
, Sum(cast(EventEndDateTime - EventStartDateTime as float))*24 as Duration
,Sum(case when CustomEvent = 'without Stop' then cast(EventEndDateTime - EventStartDateTime as float)*24 else 0 end) as EventCategory
FROM tDataCategory
WHERE EventDate >= #StartDateTime
AND EventDate <= #EndDateTime
AND SystemName = '201'
Group BY SystemName, eventdefinition, eventstartdatetime, eventenddatetime, EventDefinition, EventDate, CustomEvent
) as t
WHERE CustomEvent <> 'without Stop'
OR (CustomEvent = 'without Stop' AND t.EventCategory >=0.05)
group by EventDefinition
, Duration
,Machine
,EventCategory
output:
and my second query:
SELECT DataValue = case when Prod = 0 then 0 else ISNULL(100.0 / Prod * Scrap, 0) end,
Value = GoodUnits/TheoreticalUnits *100,
FROM (
Select intervaldate as DateValue, intervalDateWeek as Datum, tsystem.Name as Name, ProductName as Product, teamname as Team,
SUM(case when IssueName in ('A1', 'A2') then calculationUnitsInitial else 0 end) as Scrap,
Sum(case when IssueName = 'Prod' then calculationUnitsInitial else 0 end) as Prod,
SUM(GoodUnits)
As GoodUnits,
SUM(TheoreticalUnits) As TheoreticalUnits,
from tCount inner join tsystem ON tCount.systemid = tsystem.id
where IntervalDate >= dateadd(wk, datediff(wk, 1, getdate()), 0)
and IntervalDate <= dateadd(wk, datediff(wk, 0, getdate()), 0)
AND ((DATEPART(dw, IntervalDate) + ##DATEFIRST) % 7) NOT IN (0,1)
and tsystem.Name = '201'
group by intervaldate, tsystem.Name, intervaldateweek, ProductName, teamname
) as s
output:
I tried it to add in my query two select statements. But if I do this the output is wrong. I really don´t know how I should join this two queries.
I would like to do then this calculation: Distribution * (1 - Value)
Distribution from the first query and Value from the second query
I assume the first and second result set has to be joined based on A.Machine=B.Name
Try like this,
SELECT A.Distribution * (1 - B.Value)
FROM (
SELECT Machine
,EventDefinition
,Duration
,sum(Duration) OVER (PARTITION BY 1) AS Total
,Duration / sum(Duration) OVER (PARTITION BY 1) * 100 AS Distribution
,CASE
WHEN EventCategory < 0.05
THEN 'NOT INCL'
ELSE 'OK'
END AS Under3Min
FROM (
SELECT SystemName AS Machine
,EventDefinition
,EventDate
,EventStartDateTime
,IsNull(EventEndDateTime, GETDATE()) AS EventEndDateTime
,Sum(cast(EventEndDateTime - EventStartDateTime AS FLOAT)) * 24 AS Duration
,Sum(CASE
WHEN CustomEvent = 'without Stop'
THEN cast(EventEndDateTime - EventStartDateTime AS FLOAT) * 24
ELSE 0
END) AS EventCategory
FROM tDataCategory
WHERE EventDate >= #StartDateTime
AND EventDate <= #EndDateTime
AND SystemName = '201'
GROUP BY SystemName
,eventdefinition
,eventstartdatetime
,eventenddatetime
,EventDefinition
,EventDate
,CustomEvent
) AS t
WHERE CustomEvent <> 'without Stop'
OR (
CustomEvent = 'without Stop'
AND t.EventCategory >= 0.05
)
GROUP BY EventDefinition
,Duration
,Machine
,EventCategory
) A
INNER JOIN (
SELECT DataValue = CASE
WHEN Prod = 0
THEN 0
ELSE ISNULL(100.0 / Prod * Scrap, 0)
END
,Value = GoodUnits / TheoreticalUnits * 100
,NAME
FROM (
SELECT intervaldate AS DateValue
,intervalDateWeek AS Datum
,tsystem.NAME AS NAME
,ProductName AS Product
,teamname AS Team
,SUM(CASE
WHEN IssueName IN (
'A1'
,'A2'
)
THEN calculationUnitsInitial
ELSE 0
END) AS Scrap
,Sum(CASE
WHEN IssueName = 'Prod'
THEN calculationUnitsInitial
ELSE 0
END) AS Prod
,SUM(GoodUnits) AS GoodUnits
,SUM(TheoreticalUnits) AS TheoreticalUnits
,
FROM tCount
INNER JOIN tsystem ON tCount.systemid = tsystem.id
WHERE IntervalDate >= dateadd(wk, datediff(wk, 1, getdate()), 0)
AND IntervalDate <= dateadd(wk, datediff(wk, 0, getdate()), 0)
AND ((DATEPART(dw, IntervalDate) + ##DATEFIRST) % 7) NOT IN (
0
,1
)
AND tsystem.NAME = '201'
GROUP BY intervaldate
,tsystem.NAME
,intervaldateweek
,ProductName
,teamname
) AS s
) B ON A.Machine = B.NAME

SQL Server : multi-part identifier could not be bound

I need a simple output of fields named "36" - "1" with the extended inventory value for everything in the specified item classes. I don't need itemization.
E.g.
Error is:
"Database Connector Error. '42000:[Microsoft][ODBC SQL Server Driver][SQL Server]The multi-part identifier "InvenFiscPerHistTable.FiscalPeriod" could no be bound. [Database Vendor Code: 4104 ]'
Here's my SQL.
DECLARE #CalMonth INT
DECLARE #CalYear INT
DECLARE #CalMoYear DATETIME
SET #CalMonth = CASE WHEN "InvenFiscPerHistTable"."FiscalPeriod" IN (1,2,3) THEN "InvenFiscPerHistTable"."FiscalPeriod" + 9 ELSE "InvenFiscPerHistTable"."FiscalPeriod" - 3 END
SET #CalYear = CASE WHEN "InvenFiscPerHistTable"."FiscalPeriod" IN (1,2,3) THEN "InvenFiscPerHistTable"."FiscalYear" + 1 ELSE "InvenFiscPerHistTable"."FiscalYear" END
SET #CalMoYear = CAST(CONVERT(NVARCHAR, #CalYear) + '-' + CONVERT(NVARCHAR, #CalMonth) + '-' + CONVERT(NVARCHAR,1) AS DATETIME)
--our fiscal year is not the same as the calendar year
--e.g. FiscalPeriod = 1 and FiscalYear = 2016 will be October 2015
SELECT SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -36, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -35, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "36"
,SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -35, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -34, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "35"
,SUM (CASE WHEN #CalMoYear BETWEEN DATEADD(m, -34, GETDATE()-day(GETDATE()-1)) AND DATEADD(m, -33, GETDATE()-day (GETDATE()-1))-1 THEN"InvenFiscPerHistTable"."QOH" * "InvenTable"."UnitCost" ELSE NULL END) AS "34"
--and so on until I have 36 months of history up through last month
FROM "InvenTable"
INNER JOIN "SKUTable" ON "InvenTable"."SKUKey" = "SKUTable"."SKUKey"
INNER JOIN "InvenFiscPerHistTable" ON ("InvenTable"."SKUKey" = "InvenFiscPerHistTable"."SKUKey")
AND ("InvenTable"."WarehouseKey" = "InvenFiscPerHistTable"."WarehouseKey")
INNER JOIN "SKUClassTable" "SKUClassTable" ON "SKUTable"."ICKey" = "SKUClassTable"."ICKey"
WHERE "SKUClassTable"."ItemClassName" IN (
'105-03'
,'105-04'
,'105-05'
,'105-06'
,'150-01'
)
I played around a bit with your query and think it can be rewritten and simplified (in my opinion) to the query below. The only thing you need to do is add more items in the pivot part at the end to get more columns.
The logic is that it calculates the difference in months between the first day of the current month and the date that is created from the FiscalYear and FiscalPeriod (according to your rules).
I believe it should work, unless I missed something vital, but without any test data there's of course a fair amount of guess work involved ;-)
Please give it a try and if it doesn't work I'll remove my answer.
I formatted it a bit less compact than it could be to make it easier to follow.
;WITH CTE AS
(
SELECT
SKUKey, WarehouseKey, FiscalPeriod, FiscalYear, QOH,
diff = DATEDIFF
(
month,
CASE WHEN FiscalPeriod IN (1,2,3)
THEN
CAST(FiscalYear + 1 AS CHAR(4))
+ '-' + CAST(FiscalPeriod + 9 AS VARCHAR(2))
+ '-' + CAST(1 AS CHAR(1))
ELSE
CAST(FiscalYear AS CHAR(4))
+ '-' + CAST(FiscalPeriod - 3 AS VARCHAR(2))
+ '-' + CAST(1 AS CHAR(1))
END,
DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
)
FROM InvenFiscPerHistTable
)
SELECT * FROM
(
SELECT diff, QOH * UnitCost as TotalCost
FROM InvenTable i
INNER JOIN SKUTable s ON i.SKUKey = s.SKUKey
INNER JOIN cte ON (i.SKUKey = cte.SKUKey) AND (i.WarehouseKey = cte.WarehouseKey)
INNER JOIN SKUClassTable sc ON s.ICKey = sc.ICKey
WHERE sc.ItemClassName IN ('105-03','105-04','105-05','105-06','150-01')
) A
PIVOT ( SUM(TotalCost) FOR diff IN ([36],[35],[2],[1]) ) p -- add more columns here

How to get the last run job details in SQL

How to get the last run job details in SQL Server Agent using SQL including the step details only for the last run job (not the job outcome) as i want to display this in an application
Please help been stuck on this for ages
This is the code I have been using below, this brings back all steps for all Jobs in the Job History,
However, I just want to see the steps from the last run job
thanks
USE msdb
Go
SELECT j.name JobName,h.step_name StepName,
CONVERT(CHAR(10), CAST(STR(h.run_date,8, 0) AS dateTIME), 111) RunDate,
STUFF(STUFF(RIGHT('000000' + CAST ( h.run_time AS VARCHAR(6 ) ) ,6),5,0,':'),3,0,':') RunTime,
h.run_duration StepDuration,
case h.run_status when 0 then 'Failed'
when 1 then 'Succeeded'
when 2 then 'Retry'
when 3 then 'Cancelled'
when 4 then 'In Progress'
end as ExecutionStatus,
h.message MessageGenerated
FROM sysjobhistory h
inner join sysjobs j
ON j.job_id = h.job_id
LEFT JOIN (
SELECT
[job_id]
, [run_date]
, [run_time]
, [run_status]
, [run_duration]
, [message]
, ROW_NUMBER() OVER (
PARTITION BY [job_id]
ORDER BY [run_date] DESC, [run_time] DESC
) AS RowNumber
FROM [msdb].[dbo].[sysjobhistory]
WHERE [step_id] = 0
) AS [sJOBH]
ON j.[job_id] = [sJOBH].[job_id]
AND [sJOBH].[RowNumber] = 1
where j.job_id = 'F04E5D3B-C873-448A-805C-C6309A92DAEC'
ORDER BY j.name, h.run_date, h.run_time desc
GO
Hopefully this helps,
Additional join to msdb.dbo.sysjobactivity shows you the start/end time at a job level. Using this range you can specify to only show you the job steps for the most recent run.
DECLARE #job_id UNIQUEIDENTIFIER
,#job_name VARCHAR(256)
SET #job_id = 'DF4C9555-5B24-4649-97CE-5708C53F762C'
SET #job_name = 'syspolicy_purge_history'
--search for job_id if none was provided
SELECT #job_id = COALESCE(#job_id,job_id)
FROM msdb.dbo.sysjobs
WHERE name = #job_name
SELECT t2.instance_id
,t1.name as JobName
,t2.step_id as StepID
,t2.step_name as StepName
,CONVERT(CHAR(10), CAST(STR(t2.run_date,8, 0) AS DATETIME), 111) as RunDate
,STUFF(STUFF(RIGHT('000000' + CAST ( t2.run_time AS VARCHAR(6 ) ) ,6),5,0,':'),3,0,':') as RunTime
,t2.run_duration
,CASE t2.run_status WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Cancelled'
WHEN 4 THEN 'In Progress'
END as ExecutionStatus
,t2.message as MessageGenerated
FROM msdb.dbo.sysjobs t1
JOIN msdb.dbo.sysjobhistory t2
ON t1.job_id = t2.job_id
--Join to pull most recent job activity per job, not job step
JOIN (
SELECT TOP 1
t1.job_id
,t1.start_execution_date
,t1.stop_execution_date
FROM msdb.dbo.sysjobactivity t1
--If no job_id detected, return last run job
WHERE t1.job_id = COALESCE(#job_id,t1.job_id)
ORDER
BY last_executed_step_date DESC
) t3
--Filter on the most recent job_id
ON t1.job_id = t3.job_Id
--Filter out job steps that do not fall between start_execution_date and stop_execution_date
AND CONVERT(DATETIME, CONVERT(CHAR(8), t2.run_date, 112) + ' '
+ STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(8), t2.run_time), 6), 5, 0, ':'), 3, 0, ':'), 121)
BETWEEN t3.start_execution_date AND t3.stop_execution_date
Edit: Added two parameters to the top, #job_id and #job_name. If #job_id is not provided, first it'll attempt to determine the job_id of the #job_name provided, and return the last run job is no values are provided.