简体   繁体   中英

SQL Server Aggregating Rows based on Date and Status

Hi I want to know the job execution time based on the table below. For example 1/24/17 , The time difference between Running and Completed is 17min.

**JobName**     **CurrentJobStatus**    **TimeOfChange**
    Customer    Completed           1/24/17 0:17
    Customer    Running             1/24/17 0:00
    Customer    Waiting             1/23/17 20:30
    Customer    Completed           1/21/17 0:47
    Customer    Idle               1/21/17 16:00
    Customer    Running             1/21/17 0:30
    Customer    Completed           1/20/17 0:31
    Customer    Idle                1/20/17 16:00
    Customer    Running             1/20/17 0:15
    Customer    Waiting             1/20/17 20:30
    Customer    Completed           1/19/17 0:37
    Customer    Idle                1/19/17 16:00
    Customer    Running             1/19/17 0:20
    Customer    Waiting             1/19/17 20:30

Assuming there's only 1 Running and Completed job status per day and you want the time difference between the two, you can use conditional aggregation by putting a case statement inside max or min :

select * , datediff(minute, completed, running) 
from (
    select 
        convert(date, TimeOfChange) change_date,
        max(case when CurrentJobStatus = 'Completed' then TimeOfChange end) completed,
        min(case when CurrentJobStatus = 'Running' then TimeOfChange end) running
    from mytable
    group by convert(date, TimeOfChange)
) t order by change_date

I've selected rows with CurrentJobStatus in ('Completed', 'Running'), and then I've set a rank by CurrentJobStatus ordered by TimeOfChange. This adds a sequenced number for every pair of ('Completed', 'Running')

Finally grouping by this rank, get datediff between max and min date.

with tm as
(
    select JobName, CurrentJobStatus, TimeOfChange,
    rank() over (partition by CurrentJobStatus order by TimeOfChange desc) rn
    from jobs
    where CurrentJobStatus in ('Completed', 'Running')
)
select
    rn, DateDiff(minute, min(TimeOfChange), max(TimeOfChange)) as min
from tm
group by rn;

Check it here: http://rextester.com/NZFWXO47289

This can be tricky. If we assume that "Running" and "Completed" are completely interwoven (no two "Running" followed by a "Completed"), then you can identify matches by counting the number of "Running" records on or before each record. The rest is just aggregation:

select min(case when CurrentJobStatus = 'Running' then TimeOfChange end) as running_time,
       max(case when CurrentJobStatus = 'Completed' then TimeOfChange end) as completed_time,
       datediff(minute, 
                min(case when CurrentJobStatus = 'Running' then TimeOfChange end),
                max(case when CurrentJobStatus = 'Completed' then TimeOfChange end)
                ) as diff_in_minutes
from (select t.*,
             sum(case when CurrentJobStatus = 'Running' then 1 else 0 end) over (order by TimeOfChange) as running_running
      from t
     ) t
group by running_running;

If the assumption is not true and you can have multiple "running" in a row or "completed" in a row, then you should ask another question with appropriate sample data and the description of the rules.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM