Is there a way to query usage statistics in one go? - sql

SQL flavor: PostgreSQL
Data table (tpm_data)
(Actual table uses JSONB fields and those have the from, to fields, however it is not relevant to the question)
Table represent a user usage of some kind (like a subscription). Example data:
I am trying to query usage statistics for a specific range of time and for a specific interval.
Example:
parameters: from 2023-02-10 11:00 to 2023-02-10 18:00 and interval value: 1 hour
expected rows:
From
To
Duration
2023-02-10 11:00
2023-02-10 12:00
0
2023-02-10 12:00
2023-02-10 13:00
4 min 45 s
2023-02-10 13:00
2023-02-10 14:00
36 min 15 s
2023-02-10 14:00
2023-02-10 15:00
51 min 23 s
2023-02-10 15:00
2023-02-10 16:00
1 hour
2023-02-10 16:00
2023-02-10 17:00
1 hour
2023-02-10 17:00
2023-02-10 18:00
1 hour
I am fiddling around with date_bin and generate_series however I am unable to produce a result which I want.

Related

Exclude overlapped time period

I wish to write a query for below problem.
The problem is, I want to eliminate all overlapping periods, so that I get the total amount of time which is not taken in any other row.
Example:
NAME
Start Date Time
End Date time
Load shed
21-03-2020 12:30
21-03-2020 13:30
Shutdown
21-03-2020 13:00
21-03-2020 14:00
breakdown
21-03-2020 13:10
21-03-2020 14:10
Load shed
24-03-2020 12:30
24-03-2020 13:30
Shutdown
24-03-2020 11:00
24-03-2020 19:00
breakdown
24-03-2020 13:10
24-03-2020 14:10
Now what we have to do is:
Return time period between start date time and end date time but exclude overlapped time.
Expected result will be:
NAME
Start Date Time
End Date time
Time_interval
Load shed
21-03-2020 12:30
21-03-2020 13:30
01:00
Shutdown
21-03-2020 13:30
21-03-2020 14:00
00:30
breakdown
21-03-2020 14:00
21-03-2020 14:10
00:10
Shutdown
24-03-2020 11:00
24-03-2020 19:00
08:00
Now we can see in result,
First row: As it is because it has the lowest start date time in all
overlapped rows.
Second row: 30 minutes already used in first row so
we exclude 30 minutes here and write left time interval.
Third row:
we exclude till time 14:00 because its already used in row 2 so now time
interval has 10 minutes only.
Fourth row: We exclude all rows from
given table because they all overlapped and they are within start date
time 24-3-2020 11:00 and 24:03:2020 19:00 .
Hope you understand the problem.
Thanks in advance.
You can calculate the previous enddt before each row. Then, if that is larger than the start date, use that for the row. And, if the duration of the row is negative, then filter out the row.
The code looks like:
select name, imputed_startdt, enddt, prev_enddt,
convert(time, dateadd(minute, datediff(minute, imputed_startdt, enddt), 0)) as duration
from (select t.*, max(enddt) over (order by startdt rows between unbounded preceding and 1 preceding) as prev_enddt
from t
) t cross apply
(values (case when prev_enddt > startdt then prev_enddt else startdt end)
) v(imputed_startdt)
where prev_enddt < enddt or prev_enddt is null;
Here is a db<>fiddle.

Generate rows with time intervals between 2 dates in Oracle

I have table in which Sunday to Saturdy "Doctor Start" and "End Time" is given.
I want to create time slots of 15 minutes.
On the basis of that, the patient clicks on calendar datetime interval which shows slots that have already been booked.
The following example shows how to split time into slices of 15 minutes. It uses hierarchical query. A little bit of explanation:
line 2: trunc function, applied to a date value, returns "beginning" of that day (at midnight). Adding 15 / (24*60) adds 15 minutes (as there are 24 hours in a day and 60 minutes in an hour). Multiplying 15 by level works as a "loop", i.e. adds 15-by-15-by-15 ... minutes to previous value.
line 4: similar to line 2, but it makes sure that a day (24 hours * 60 minutes) is divided to 15-minutes parts
line 6: start time is trivial
line 7: end time just adds 15 minutes to start_time
line 9: return only time between 10 and 16 hours (you don't have patients at 02:15 AM, right?)
SQL> with fifteen as
2 (select trunc(sysdate) + (level * 15)/(24*60) c_time
3 from dual
4 connect by level <= (24*60) / 15
5 )
6 select to_char(c_time, 'hh24:mi') start_time,
7 to_char(c_time + 15 / (24 * 60), 'hh24:mi') end_time
8 from fifteen
9 where extract(hour from cast (c_time as timestamp)) between 10 and 15;
START_TIME END_TIME
---------- ----------
10:00 10:15
10:15 10:30
10:30 10:45
10:45 11:00
11:00 11:15
11:15 11:30
11:30 11:45
11:45 12:00
12:00 12:15
12:15 12:30
12:30 12:45
12:45 13:00
13:00 13:15
13:15 13:30
13:30 13:45
13:45 14:00
14:00 14:15
14:15 14:30
14:30 14:45
14:45 15:00
15:00 15:15
15:15 15:30
15:30 15:45
15:45 16:00
24 rows selected.
SQL>

Split a time duration into time segments

I have an incident start time and end time e.g Sr=tart time of 15/01/2018 11:30 and end time of 16/01/2018 02:40 in an excel table.
How can I split this time range into different time segments. The segments are:-
06:00 - 11:59, 12:00 - 14:59, 15:00 - 17:59, 18:00 - 22:59, 23:00 - 05:59
For 06:00 - 11:59 I would expect 0.50 as this is 30 mins.
For 12:00 - 14:59 I would expect 3.0 for 3 hours.
For 15:00 - 17:59 I would expect 3.0 for 3 hours again.
For 18:00 - 22:59 this should be 5hrs
and for 23:00 - 02:40 should be 3.67 hrs.
What formula would I need to achieve this?
For the example you give with the layout as shown below this formula should work:
=MIN($D3-F$1,MIN(F$2-F$1,IF($C3<F$2,F$2-$C3+SUM($E3:E3),)))
The formula in C3 is:
=24*(MOD(A3,1))
and in D3:
=24*(MOD(B3,1)+INT(B3>INT(A3)))

How to count the records per half hour from a period (datetimefrom and datetimeto) field?

I have a table which looks like you can see below:
Id Date ScheduledTimeFrom ScheduledTimeTo ActualTimeFrom ActualTimeTo
1 2013-01-01 1899-12-30 07:00:00 1899-12-30 18:00:00 1899-12-30 07:23:00 1899-12-30 17:15:00
I need to calculate per half hour how many records exists, the output should be like:
Time Actual Count:
7:00 4
7:30 4
8:00 4
8:30 4
9:00 4
9:30 5
10:00 5
10:30 6
11:00 7
11:30 8
12:00 8
12:30 8
13:00 8
13:30 8
14:00 8
14:30 8
15:00 7
15:30 7
16:00 7
16:30 6
17:00 5
17:30 4
18:00 4
I already tried to make a helper table which should hold the times per halfhour. I have joined this helpertable with the table that contains the data and after that I tried to use a group by function but it was not working.
My query was like:
Create table period (timefrom datetime, timeto datetime)
insert into period
select '1899-12-30 07:00:00.000', '1899-12-30 07:30:00.000'
Union all
select '1899-12-30 07:30:00.000', '1899-12-30 08:00:00.000'
select *
from period p left join table1 t on t.ActualTimeFrom < p.timeto and t.ActualTimeTo >=p.timefrom
Grouping this give me no desired result....
Anyone an idea how to come to the result?
P.s. I am using sql server 2005.
After snooping around and testing it on my side, looks like this date function could be the answer:
DATEADD(mi,DATEDIFF(mi,0,YOUR_DATE_COLUMN)/30*30,0)

SQL code for Comparing date fields in different rows and combining the results

I need help for proper Oracle SQL code to combine rows for a crystal reports command object. This is a part of the bigger query I'm working on and got stuck for the past couple of days.
for eg. if the columns are like below
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/01/2012 10:00:00 am
151 01/01/2012 11:00:00 am 01/02/2012 08:00:00 am
151 01/02/2012 11:00:00 am 01/02/2012 01:00:00 pm
151 01/03/2012 08:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/14/2012 07:00:00 am
167 01/14/2012 11:30:00 am 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
Within a PatId, the code should compare the Out_time of one row to the In_time of the next row, and check whether the time gap is greater than 48 hours. If not, then it is considered part of the same visit. I want one result row per PatID & visit, with min(In_time) and max(Out_time). The time span of the visit (result row) itself may be greater than 48 hours.
For this example, for PatId 151 the time difference between the out_time of 1st row and In_time of 2nd row is less than 48 hours. The difference between Out_time of second row and In_time of 3rd row, as well as between the 3rd and 4th rows, is also less than 48 hours. After this the gap between Out_time of the 4th row and In_time of 5th row is greater than 48 hours. The result for PatId 151 should be as below and same for EmpId 167, the chaining should continue until a gap greater than 48 hours is found.
So the result for the above table should be displayed as,
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
I could not get the logic on how to compare and merge rows.
Thanks in Advance, Abhi
General example of subtracting time - copy/paste to see the output. This example will give you differences in hours, minutes, seconds between two dates. The basic formula is (end_date - start_date) * 86400 (number of seconds in 24 hrs)...:
SELECT trunc(mydate / 3600) hr
, trunc(mod(mydate, 3600) / 60) mnt
, trunc(mod(mydate, 3600) / 60 /60) sec
FROM
(
SELECT (to_date('01/03/2012 10:00:00', 'mm/dd/yyyy hh24:mi:ss') -
to_date('01/01/2012 07:00:00', 'mm/dd/yyyy hh24:mi:ss')) * 86400 mydate
FROM dual
)
/
HR | MNT | SEC
---------------
51 | 0 | 0
You need to check your example and logic. I could not understand what needs to be comnpared with what...