如何确定工作状态?

时间:2008-10-14 06:46:47

标签: sql sql-server-2005 tsql stored-procedures

我有一个存储过程来安排工作。这项工作需要很长时间才能完成(大约30到40分钟)。我需要了解这份工作的状态。 以下详细信息可以帮助我

1)如何查看已安排在未来时间但尚未开始的所有工作的列表

2)如何查看正在运行的作业列表以及运行时间跨度

3)如何查看作业是否成功完成或由于任何错误而停止作业。

15 个答案:

答案 0 :(得分:74)

我想指出,此页面上的T-SQL都不会正常工作,因为它们都没有加入 syssessions 表只能获取当前会话,因此可能包含误报

请参阅此参考:What does it mean to have jobs with a null stop date?

您还可以通过分析 msdb 中的 sp_help_jobactivity 过程来验证这一点。

我意识到这是SO上的旧消息,但我发现这个消息只是部分有用,因为这个问题。

SELECT
    job.name, 
    job.job_id, 
    job.originating_server, 
    activity.run_requested_date, 
    DATEDIFF( SECOND, activity.run_requested_date, GETDATE() ) as Elapsed
FROM 
    msdb.dbo.sysjobs_view job
JOIN
    msdb.dbo.sysjobactivity activity
ON 
    job.job_id = activity.job_id
JOIN
    msdb.dbo.syssessions sess
ON
    sess.session_id = activity.session_id
JOIN
(
    SELECT
        MAX( agent_start_date ) AS max_agent_start_date
    FROM
        msdb.dbo.syssessions
) sess_max
ON
    sess.agent_start_date = sess_max.max_agent_start_date
WHERE 
    run_requested_date IS NOT NULL AND stop_execution_date IS NULL

答案 1 :(得分:44)

您可以尝试使用系统存储过程sp_help_job。这将返回有关作业,步骤,计划和服务器的信息。例如

EXEC msdb.dbo.sp_help_job @Job_name = 'Your Job Name'

SQL Books Online应该包含很多关于它返回的记录的信息。

要返回有关多个作业的信息,您可以尝试查询以下系统表,这些表保存有关作业的各种信息

  • msdb.dbo.SysJobs
  • msdb.dbo.SysJobSteps
  • msdb.dbo.SysJobSchedules
  • msdb.dbo.SysJobServers
  • msdb.dbo.SysJobHistory

他们的名字是相当不言自明的(除了SysJobServers,其中包含有关作业上次运行和结果的信息)。

同样,有关这些字段的信息可以在MSDN上找到。例如,请查看SysJobs

页面

答案 2 :(得分:27)

这就是我用来获取正在运行的工作(主要是因为我可以杀死可能已挂起的工作):

SELECT
    job.Name, job.job_ID
    ,job.Originating_Server
    ,activity.run_requested_Date
    ,datediff(minute, activity.run_requested_Date, getdate()) AS Elapsed
FROM
    msdb.dbo.sysjobs_view job 
        INNER JOIN msdb.dbo.sysjobactivity activity
        ON (job.job_id = activity.job_id)
WHERE
    run_Requested_date is not null 
    AND stop_execution_date is null
    AND job.name like 'Your Job Prefix%'

正如Tim所说,MSDN / BOL文档在sysjobsX表的内容上相当不错。请记住它们是MSDB中的表。

答案 3 :(得分:10)

-- Microsoft SQL Server 2008 Standard Edition:
IF EXISTS(SELECT 1 
          FROM msdb.dbo.sysjobs J 
          JOIN msdb.dbo.sysjobactivity A 
              ON A.job_id=J.job_id 
          WHERE J.name=N'Your Job Name' 
          AND A.run_requested_date IS NOT NULL 
          AND A.stop_execution_date IS NULL
         )
    PRINT 'The job is running!'
ELSE
    PRINT 'The job is not running.'

答案 4 :(得分:3)

我们可以通过多种方式查询msdb以获取详细信息。

很少是

select job.Name, job.job_ID, job.Originating_Server,activity.run_requested_Date,
datediff(minute, activity.run_requested_Date, getdate()) as Elapsed 
from msdb.dbo.sysjobs_view job 
inner join msdb.dbo.sysjobactivity activity on (job.job_id = activity.job_id) 
where run_Requested_date is not null 
and stop_execution_date is null 
and job.name like 'Your Job Prefix%'

答案 5 :(得分:2)

您尚未指定希望如何查看这些详细信息。

第一眼我建议检查Server Management Studio

您可以在“作业”下的“SQL Server代理”部分中查看作业和当前状态。如果您选择一个作业,“属性”页面会显示一个指向“作业历史记录”的链接,您可以在其中查看开始和结束时间,是否有任何错误,哪个步骤导致错误等等。

您可以指定警告和通知,以便通过电子邮件发送给您,或在作业成功完成或失败时为您寻呼。

有一个Job Activity Monitor,但实际上我从未使用它。你可以尝试一下。

如果你想通过T-SQL检查它,那么我不知道你怎么能这样做。

答案 6 :(得分:2)

这是一个老问题,但我遇到了类似的情况,我需要检查SQL Server上的作业状态。很多人都提到了sysjobactivity表,并指出了MSDN文档很棒。但是,我还要强调Job Activity Monitor,它提供了服务器上定义的所有作业的状态。

答案 7 :(得分:2)

我使用评分最高的答案创建了一个简单的 SQL 函数来检查 SQL 代理作业是否已在运行:

-- ===================================================================================
-- Function: "IsJobAlreadyRunning"  |  Author: Geoff Griswald  |  Created: 2021-05-06
-- Description: Check if a SQL Agent Job is already Running - Return 1 if Yes, 0 if No
-- ===================================================================================
CREATE FUNCTION dbo.IsJobAlreadyRunning (@AgentJobName varchar(140))
RETURNS bit
AS
BEGIN
DECLARE @Result bit = 0
     IF EXISTS (SELECT job.name
                  FROM msdb.dbo.sysjobs_view job
            INNER JOIN msdb.dbo.sysjobactivity activity ON job.job_id = activity.job_id
            INNER JOIN msdb.dbo.syssessions sess ON sess.session_id = activity.session_id
            INNER JOIN (SELECT MAX(agent_start_date) AS max_agent_start_date
                          FROM msdb.dbo.syssessions) sess_max ON sess.agent_start_date = sess_max.max_agent_start_date
                 WHERE run_requested_date IS NOT NULL 
                   AND stop_execution_date IS NULL
                   AND job.name = @AgentJobName)
   SET @Result = 1
RETURN @Result
END;

这很有用,因为我可以调用这个函数并在我尝试启动它之前检查我想要启动的作业是否已经在运行,而不会给我的代码添加很多膨胀。例如:

DECLARE @JobName varchar(140) = 'MyAgentJobName'
     IF (SELECT dbo.IsJobAlreadyRunning(@JobName)) = 0
   EXEC msdb.dbo.sp_start_job @JobName

答案 8 :(得分:1)

上面的任务有效,但我在msdb.dbo.sysjobactivity中看到过很多记录 其中run_Requested_date不为null 和stop_execution_date为空 ----并且该作业当前未运行。

我建议运行以下脚本来清除所有虚假条目(确保当时没有正在运行的作业)。

SQL2008:

    delete activity
    from msdb.dbo.sysjobs_view job  
    inner join msdb.dbo.sysjobactivity activity on job.job_id = activity.job_id 
    where  
        activity.run_Requested_date is not null  
    and activity.stop_execution_date is null  

答案 9 :(得分:1)

这将显示上次运行状态/时间,或者如果正在运行,则显示当前运行时间,步骤编号/信息和SPID(如果它具有关联的SPID)。它还显示启用/禁用和作业用户,它将转换为未解析的用户帐户的NT SID格式。

CREATE TABLE #list_running_SQL_jobs
(
    job_id UNIQUEIDENTIFIER NOT NULL
  , last_run_date INT NOT NULL
  , last_run_time INT NOT NULL
  , next_run_date INT NOT NULL
  , next_run_time INT NOT NULL
  , next_run_schedule_id INT NOT NULL
  , requested_to_run INT NOT NULL
  , request_source INT NOT NULL
  , request_source_id sysname NULL
  , running INT NOT NULL
  , current_step INT NOT NULL
  , current_retry_attempt INT NOT NULL
  , job_state INT NOT NULL
);

DECLARE @sqluser NVARCHAR(128)
      , @is_sysadmin INT;

SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0);

DECLARE read_sysjobs_for_running CURSOR FOR
    SELECT DISTINCT SUSER_SNAME(owner_sid)FROM msdb.dbo.sysjobs;
OPEN read_sysjobs_for_running;
FETCH NEXT FROM read_sysjobs_for_running
INTO @sqluser;

WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO #list_running_SQL_jobs
    EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @sqluser;
    FETCH NEXT FROM read_sysjobs_for_running
    INTO @sqluser;
END;

CLOSE read_sysjobs_for_running;
DEALLOCATE read_sysjobs_for_running;

SELECT j.name
     , 'Enbld' = CASE j.enabled
                     WHEN 0
                         THEN 'no'
                     ELSE 'YES'
                 END
     , '#Min' = DATEDIFF(MINUTE, a.start_execution_date, ISNULL(a.stop_execution_date, GETDATE()))
     , 'Status' = CASE
                      WHEN a.start_execution_date IS NOT NULL
                          AND a.stop_execution_date IS NULL
                          THEN 'Executing'
                      WHEN h.run_status = 0
                          THEN 'FAILED'
                      WHEN h.run_status = 2
                          THEN 'Retry'
                      WHEN h.run_status = 3
                          THEN 'Canceled'
                      WHEN h.run_status = 4
                          THEN 'InProg'
                      WHEN h.run_status = 1
                          THEN 'Success'
                      ELSE 'Idle'
                  END
     , r.current_step
     , spid = p.session_id
     , owner = ISNULL(SUSER_SNAME(j.owner_sid), 'S-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1))) - CONVERT(BIGINT, 256) * CONVERT(BIGINT, UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1)) / 256)) + '-' + CONVERT(NVARCHAR(12), UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 4), 1)) / 256 + CONVERT(BIGINT, NULLIF(UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1)) / 256, 0)) - CONVERT(BIGINT, UNICODE(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 1)) / 256)) + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 5), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 6), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 6), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 7), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 8), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 8), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 9), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 10), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 10), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 11), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 12), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 12), -1)) * 0), '') + ISNULL('-' + CONVERT(NVARCHAR(12), CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 13), 1))) + CONVERT(BIGINT, UNICODE(RIGHT(LEFT(CONVERT(NVARCHAR(256), j.owner_sid), 14), 1))) * CONVERT(BIGINT, 65536) + CONVERT(BIGINT, NULLIF(SIGN(LEN(CONVERT(NVARCHAR(256), j.owner_sid)) - 14), -1)) * 0), '')) --SHOW as NT SID when unresolved
     , a.start_execution_date
     , a.stop_execution_date
     , t.subsystem
     , t.step_name
FROM msdb.dbo.sysjobs j
    LEFT OUTER JOIN (SELECT DISTINCT * FROM #list_running_SQL_jobs) r
        ON j.job_id = r.job_id
    LEFT OUTER JOIN msdb.dbo.sysjobactivity a
        ON j.job_id = a.job_id
            AND a.start_execution_date IS NOT NULL
            --AND a.stop_execution_date IS NULL
            AND NOT EXISTS
            (
                SELECT *
                FROM msdb.dbo.sysjobactivity at
                WHERE at.job_id = a.job_id
                    AND at.start_execution_date > a.start_execution_date
            )
    LEFT OUTER JOIN sys.dm_exec_sessions p
        ON p.program_name LIKE 'SQLAgent%0x%'
            AND j.job_id = SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 7, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 5, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 3, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 1, 2) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 11, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 9, 2) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 15, 2) + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 13, 2) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 17, 4) + '-' + SUBSTRING(SUBSTRING(p.program_name, CHARINDEX('0x', p.program_name) + 2, 32), 21, 12)
    LEFT OUTER JOIN msdb.dbo.sysjobhistory h
        ON j.job_id = h.job_id
            AND h.instance_id = a.job_history_id
    LEFT OUTER JOIN msdb.dbo.sysjobsteps t
        ON t.job_id = j.job_id
            AND t.step_id = r.current_step
ORDER BY 1;

DROP TABLE #list_running_SQL_jobs;

答案 10 :(得分:0)

我发现最简单的方法是创建一个存储过程。输入'JobName'并点击go。

/*-----------------------------------------------------------------------------------------------------------

    Document Title: usp_getJobStatus

    Purpose:        Finds a Current Jobs Run Status     
    Input Example:  EXECUTE usp_getJobStatus 'MyJobName'

-------------------------------------------------------------------------------------------------------------*/

    IF OBJECT_ID ( 'usp_getJobStatus','P' ) IS NOT NULL
    DROP PROCEDURE  usp_getJobStatus;

    GO

        CREATE PROCEDURE  usp_getJobStatus 
                          @JobName NVARCHAR (1000)

    AS

        IF OBJECT_ID('TempDB..#JobResults','U') IS NOT NULL DROP TABLE #JobResults
        CREATE TABLE #JobResults ( Job_ID   UNIQUEIDENTIFIER NOT NULL, 
                                   Last_Run_Date         INT NOT NULL, 
                                   Last_Run_Time         INT NOT NULL, 
                                   Next_Run_date         INT NOT NULL, 
                                   Next_Run_Time         INT NOT NULL, 
                                   Next_Run_Schedule_ID  INT NOT NULL, 
                                   Requested_to_Run      INT NOT NULL,
                                   Request_Source        INT NOT NULL, 
                                   Request_Source_id     SYSNAME 
                                   COLLATE Database_Default      NULL, 
                                   Running               INT NOT NULL,
                                   Current_Step          INT NOT NULL, 
                                   Current_Retry_Attempt INT NOT NULL, 
                                   Job_State             INT NOT NULL ) 

        INSERT  #JobResults 
        EXECUTE master.dbo.xp_sqlagent_enum_jobs 1, '';

        SELECT  job.name                                                AS [Job_Name], 
              ( SELECT  MAX(CAST( STUFF(STUFF(CAST(jh.run_date AS VARCHAR),7,0,'-'),5,0,'-') + ' ' + 
                        STUFF(STUFF(REPLACE(STR(jh.run_time,6,0),' ','0'),5,0,':'),3,0,':') AS DATETIME))
                FROM    msdb.dbo.sysjobs AS j 
                    INNER JOIN msdb.dbo.sysjobhistory AS jh 
                       ON jh.job_id = j.job_id AND jh.step_id = 0 
                WHERE j.[name] LIKE '%' + @JobName + '%' 
                GROUP BY j.[name] )                                     AS [Last_Completed_DateTime], 
              ( SELECT  TOP 1 start_execution_date 
                FROM    msdb.dbo.sysjobactivity
                WHERE   job_id = r.job_id
                ORDER BY start_execution_date DESC )                    AS [Job_Start_DateTime],
            CASE 
                WHEN r.running = 0 THEN
                    CASE 
                        WHEN jobInfo.lASt_run_outcome = 0 THEN 'Failed'
                        WHEN jobInfo.lASt_run_outcome = 1 THEN 'Success'
                        WHEN jobInfo.lASt_run_outcome = 3 THEN 'Canceled'
                        ELSE 'Unknown'
                    END
                        WHEN r.job_state = 0 THEN 'Success'
                        WHEN r.job_state = 4 THEN 'Success'
                        WHEN r.job_state = 5 THEN 'Success'
                        WHEN r.job_state = 1 THEN 'In Progress'
                        WHEN r.job_state = 2 THEN 'In Progress'
                        WHEN r.job_state = 3 THEN 'In Progress'
                        WHEN r.job_state = 7 THEN 'In Progress'
                     ELSE 'Unknown' END                                 AS [Run_Status_Description]
        FROM    #JobResults AS r 
            LEFT OUTER JOIN msdb.dbo.sysjobservers AS jobInfo 
               ON r.job_id = jobInfo.job_id 
            INNER JOIN msdb.dbo.sysjobs AS job 
               ON r.job_id = job.job_id 
        WHERE   job.[enabled] = 1
                AND job.name LIKE '%' + @JobName + '%'

答案 11 :(得分:0)

;WITH CTE_JobStatus
AS (
    SELECT DISTINCT NAME AS [JobName]
        ,s.step_id
        ,s.step_name
        ,CASE 
            WHEN [Enabled] = 1
                THEN 'Enabled'
            ELSE 'Disabled'
            END [JobStatus]
        ,CASE 
            WHEN SJH.run_status = 0
                THEN 'Failed'
            WHEN SJH.run_status = 1
                THEN 'Succeeded'
            WHEN SJH.run_status = 2
                THEN 'Retry'
            WHEN SJH.run_status = 3
                THEN 'Cancelled'
            WHEN SJH.run_status = 4
                THEN 'In Progress'
            ELSE 'Unknown'
            END [JobOutcome]
        ,CONVERT(VARCHAR(8), sjh.run_date) [RunDate]
        ,CONVERT(VARCHAR(8), STUFF(STUFF(CONVERT(TIMESTAMP, RIGHT('000000' + CONVERT(VARCHAR(6), sjh.run_time), 6)), 3, 0, ':'), 6, 0, ':')) RunTime
        ,RANK() OVER (
            PARTITION BY s.step_name ORDER BY sjh.run_date DESC
                ,sjh.run_time DESC
            ) AS rn
        ,SJH.run_status
    FROM msdb..SYSJobs sj
    INNER JOIN msdb..SYSJobHistory sjh ON sj.job_id = sjh.job_id
    INNER JOIN msdb.dbo.sysjobsteps s ON sjh.job_id = s.job_id
        AND sjh.step_id = s.step_id
    WHERE (sj.NAME LIKE 'JOB NAME')
        AND sjh.run_date = CONVERT(CHAR, getdate(), 112)
    )
SELECT *
FROM CTE_JobStatus
WHERE rn = 1
    AND run_status NOT IN (1,4)

答案 12 :(得分:0)

我在我的一台服务器上遇到问题,查询MSDB表(也就是上面列出的代码),因为我的一个工作会运行,但事实并非如此。有一个系统存储过程返回执行状态,但是没有错误就无法执行insert exec语句。其中是另一个系统存储过程,可以与insert exec语句一起使用。

INSERT INTO #Job
EXEC master.dbo.xp_sqlagent_enum_jobs 1,dbo

将表格加载到:

CREATE TABLE #Job 
               (job_id               UNIQUEIDENTIFIER NOT NULL,  
               last_run_date         INT              NOT NULL,  
               last_run_time         INT              NOT NULL,  
               next_run_date         INT              NOT NULL,  
               next_run_time         INT              NOT NULL,  
               next_run_schedule_id  INT              NOT NULL,  
               requested_to_run      INT              NOT NULL, -- BOOL  
               request_source        INT              NOT NULL,  
               request_source_id     sysname          COLLATE database_default NULL,  
               running               INT              NOT NULL, -- BOOL  
               current_step          INT              NOT NULL,  
               current_retry_attempt INT              NOT NULL,  
               job_state             INT              NOT NULL) 

答案 13 :(得分:0)

SELECT sj.name
  FROM msdb..sysjobactivity aj
  JOIN msdb..sysjobs sj
    on sj.job_id = aj.job_id
 WHERE aj.stop_execution_date  IS NULL     -- job hasn't stopped running
   AND aj.start_execution_date IS NOT NULL -- job is currently running
   AND sj.name = '<your Job Name>'
   AND NOT EXISTS( -- make sure this is the most recent run
                   select 1
                     from msdb..sysjobactivity new
                    where new.job_id = aj.job_id
                      and new.start_execution_date > aj.start_execution_date ) )
print 'running'

答案 14 :(得分:0)

以下脚本获取服务器上每个作业的作业状态。它还告诉您有多少个步骤,以及当前正在执行的步骤和节省的时间。

SELECT sj.Name,
    CASE
        WHEN sja.start_execution_date IS NULL THEN 'Never ran'
        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',
    CASE WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL then js.StepCount else null end As TotalNumberOfSteps,
    CASE WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL then ISNULL(sja.last_executed_step_id+1,js.StepCount) else null end as currentlyExecutingStep,
    CASE WHEN sja.start_execution_date IS NOT NULL AND sja.stop_execution_date IS NULL then datediff(minute, sja.run_requested_date, getdate()) ELSE NULL end as ElapsedTime
FROM msdb.dbo.sysjobs sj
JOIN msdb.dbo.sysjobactivity sja
ON sj.job_id = sja.job_id
CROSS APPLY (SELECT COUNT(*) FROM msdb.dbo.sysjobsteps as js WHERE js.job_id = sj.job_id) as js(StepCount)
WHERE session_id = (
    SELECT MAX(session_id) FROM msdb.dbo.sysjobactivity)
ORDER BY RunStatus desc