Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Min and max by ID over group and other condition

Tags:

sql

max

min

I've got a table that is similar to below in MS SQL Server.

      id | Timestamp | active
    -----+-----------+--------
      1  |    1:00   |    1
      1  |    2:00   |    1
      1  |    3:00   |    1
      1  |    4:00   |    0
      1  |    5:00   |    0
      1  |    6:00   |    1
      1  |    7:00   |    0
      1  |    8:00   |    0
      1  |    9:00   |    0
      1  |   10:00   |    1
      1  |   11:00   |    1
      1  |   12:00   |    0
      1  |   13:00   |    1
      2  |    2:00   |    1
      2  |    3:00   |    1
      2  |    4:00   |    0
      2  |    5:00   |    0
      3  |    8:00   |    0
      3  |    9:00   |    0
      4  |    1:00   |    1
      4  |    2:00   |    1
      5  |   16:00   |    0

What I want to do find out when each ID was inactive (active = 0) for how long. What I tried to do was group it by id when active = 0, and do a datediff on the min and max time. But that would give me a result for id 1 that said it was offline for 8 hours (12:00 - 4:00) @ 12:00. When I really want is a query that will give me the following result set.

    id | approx. offline in hours |  at time
    ---+--------------------------+-----------
     1 |            1             |    5:00
     1 |            2             |    9:00
     1 |            0             |   12:00
     2 |            1             |    5:00
     3 |            0             |    9:00
     5 |            0             |   16:00

The wrong query I initially tried is

SELECT id as [Inactive],
       DATEDIFF(hour, MIN(Timestamp), MAX(Timestamp)) as [approx. offline in hours],
       MAX(Timestamp) as [at time]
FROM table
WHERE active = 0
GROUP BY [Inactive]

But the problem with that query is that it skips the Active times in between. I've been looking at THIS question that's been asked and answered using PARTITION, but it looks like the question is different enough and the answer is too specific to the question that I can't make sense of it.

Any help is appreciated.

like image 258
claudekennilol Avatar asked Oct 21 '22 19:10

claudekennilol


People also ask

Can we use MAX function in GROUP BY clause?

Max() function with Group by In this page we are discussing, how the GROUP BY clause along with the SQL MAX() can be used to find the maximum value of a column over each group.

Can we use max and min together in SQL?

You can use both the MIN and MAX functions in one SELECT . If you use only these functions without any columns, you don't need a GROUP BY clause.

Can min and max functions be used with character and date columns?

MAX and MIN operate on columns that contain character, graphic, numeric, date/time, and binary data (except for binary large object, or BLOB, data). The parentheses are required.

What is the purpose of MIN () and MAX () aggregate functions?

The MIN() function returns the smallest value of the selected column. The MAX() function returns the largest value of the selected column.


1 Answers

One way to approach this, that works in any database, is to use a correlated subquery. The idea is to assign a groupname to each consecutive string of active values. The particular groupname is the time of the next change in value.

select id, active, min(TimeStamp), max(TimeStamp)
from (select t.*,
             (select min(timeStamp) from t t2 where t2.id = t.id and t2.timeStamp > t.timeStamp and t2.active <> t.active
             ) groupName
      from t
     ) t
group by id, groupName, active

One caveats how you get turn timestamps into durations depends on the database. Since you don't specify the database, I'll let you add that logic.

Also, if the last record for a given id is inactive, the groupname is NULL. That is not a problem.

like image 54
Gordon Linoff Avatar answered Nov 02 '22 12:11

Gordon Linoff