I have data which is shown below.
stationName
status
startTime
endTime
A
normal
09:00
09:10
A
normal
09:10
09:20
B
normal
09:30
09:40
A
normal
09:30
09:40
B
normal
09:40
09:45
A
warning
09:40
09:45
B
warning
09:45
09:55
A
alert
09:45
09:55
B
normal
09:55
10:05
A
alert
09:55
10:05
B
normal
10:05
10:15
A
normal
10:05
10:15
B
normal
10:15
10:25
A
normal
10:15
10:25
B
normal
10:25
10:35
A
normal
10:25
10:35
and I want to query data into this structure
stationName
status
startTime
endTime
A
normal
09:00
09:40
A
warning
09:40
09:45
A
alert
09:45
10:05
A
normal
10:05
10:35
B
normal
09:30
09:45
B
warning
09:45
09:55
B
normal
09:55
10:35
My data timeline data is split into many parts, but I want to group it into one.
demo
idea: construct a range, test (startTime,endTime) belong to one specific timestamptz range or not,
then group by stationname, status, range(startTime, endTime) belong to.
I would use timestamptz type for startTime, endTime, tstzrange.
If you construct timerange, then range (23:00,0:00) is invalid.
table structure:
CREATE TABLE test102 (
stationName text,
status text,
startTime timestamptz,
endTime timestamptz
);
then query:
WITH cte AS (
SELECT
test102.*,
tstzrange(startTime, endTime) tstzrange_se,
tstzrange(i - interval '1 hour', i)
FROM
test102,
generate_series('2022-05-02'::timestamp, '2022-05-02'::timestamp + interval '24 hour', interval '1 hour') i
)
SELECT
stationname,
status,
min(startTime),
max(endTime)
FROM
cte
WHERE
tstzrange_se <# tstzrange
GROUP BY
1,
2,
tstzrange;
Related
I have a table with interval dates and times. Can i create a full list with this data?
Table example:
Start_Date, End_Date, Start_Time, End_Time, Interval
01-jun-2021 02-jun-2021 08:00 10:00 30
03-jun-2021 04-jun-2021 10:00 12:00 15
Result:
01-jun-2021 08:00
01-jun-2021 08:30
01-jun-2021 09:00
01-jun-2021 09:30
02-jun-2021 08:00
02-jun-2021 08:30
02-jun-2021 09:00
02-jun-2021 09:30
03-jun-2021 10:00
03-jun-2021 10:15
03-jun-2021 10:30
03-jun-2021 11:00
03-jun-2021 11:15
03-jun-2021 11:30
03-jun-2021 11:45
04-jun-2021 10:00
04-jun-2021 10:15
04-jun-2021 10:30
04-jun-2021 11:00
04-jun-2021 11:15
04-jun-2021 11:30
04-jun-2021 11:45
Thanks.
This is a handy place to use a recursive CTE:
with cte (start_date, end_date, interval) as (
select to_date(start_date||start_time, 'DD-Mon-YYYYHH24:MI'), to_date(end_date||end_time, 'DD-Mon-YYYYHH24:MI'), interval
from t
union all
select cte.start_date + cte.interval * interval '1' minute, end_date, interval
from cte
where cte.start_date < end_date
)
select cast(start_date as timestamp)
from cte
order by start_date;
Here is a db<>fiddle.
You can use a recursive CTE, but the logic has to skip to the next day when you reach the end time; so this works:
with rcte (date_time, end_date, start_int, end_int, step_int) as (
select
start_date + to_dsinterval('0 ' || start_time || ':00'),
end_date,
to_dsinterval('0 ' || start_time || ':00'),
to_dsinterval('0 ' || end_time || ':00'),
interval * interval '1' minute
from your_table
union all
select
case
when date_time + step_int < trunc(date_time) + end_int
then date_time + step_int
else trunc(date_time) + interval '1' day + start_int
end,
end_date,
start_int,
end_int,
step_int
from rcte
where date_time + step_int < end_date + end_int
)
select date_time
from rcte
order by date_time
DATE_TIME
-------------------
2021-06-01 08:00:00
2021-06-01 08:30:00
2021-06-01 09:00:00
2021-06-01 09:30:00
2021-06-02 08:00:00
2021-06-02 08:30:00
2021-06-02 09:00:00
2021-06-02 09:30:00
2021-06-03 10:00:00
2021-06-03 10:15:00
2021-06-03 10:30:00
2021-06-03 10:45:00
2021-06-03 11:00:00
2021-06-03 11:15:00
2021-06-03 11:30:00
2021-06-03 11:45:00
2021-06-04 10:00:00
2021-06-04 10:15:00
2021-06-04 10:30:00
2021-06-04 10:45:00
2021-06-04 11:00:00
2021-06-04 11:15:00
2021-06-04 11:30:00
2021-06-04 11:45:00
db<>fiddle showing the anchor member including converting the times and interval to real day to second intervals types for later use; the anchor and recursive members with all the intermediate columns; and finally just this version with a single column.
You can format the resulting date value however you want, of course.
I have a table that holds vehicle activity data. There is a start date and end date columns in the table. I wish to construct a query that will show the amount of time in minutes that each vehicle is active or working on a particular day. My problem is that the time between the start date and end date may span a number of days.
Example:
dwVehicleIDFK StartDate EndDate Minutes HrsMins
731 18/09/2019 08:00 18/09/2019 13:00 300 05:00
797 18/09/2019 08:00 18/09/2019 12:00 240 04:00
687 17/09/2019 16:00 17/09/2019 21:00 300 05:00
826 17/09/2019 16:00 17/09/2019 21:00 300 05:00
734 18/09/2019 10:00 18/09/2019 15:30 330 05:30
843 18/09/2019 14:00 18/09/2019 18:00 240 04:00
662 18/09/2019 09:00 18/09/2019 14:00 300 05:00
662 17/09/2019 09:00 17/09/2019 14:00 300 05:00
662 16/09/2019 09:00 16/09/2019 14:00 300 05:00
817 18/09/2019 14:00 19/09/2019 08:00 1080 18:00
In the data above the vehicle with the ID of 817 extends over two days. How would I get the query to return the time period for the 18/09 only or up until midnight on the 18/09?
The query to return the data above:
Select
dwVehicleIDFK,
StartDate,
EndDate,
DATEDIFF(MINUTE, Convert(DateTime, StartDate, 103),
Convert(DateTime, EndDate, 103)) as Minutes,
CONVERT(varchar(5), DATEADD(minute, DATEDIFF(minute,
Convert(DateTime, StartDate, 103),
Convert(DateTime, EndDate, 103)), 0), 114) as HrsMins
from
VehHistory
Assume you loaded the data for the specified date #Day and converted the start/end date to datetime in temp table #temp:
Select
dwVehicleIDFK,
StartDate,
EndDate,
DATEDIFF(MINUTE, CASE WHEN StartDate<#Day THEN #Day ELSE StartDate END,
CASE WHEN EndDate>DATEADD(DAY,1,#Day) THEN DATEADD(DAY,1,#Day) ELSE EndDate END) AS UsedMinutes
from #temp;
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>
I have the following query that works perfectly well. The query sums the values in a given day.
SELECT
SUM(fldValue) AS 'kWh',
DAY(fldDateTime) AS 'Day',
MONTH(fldDateTime) AS 'Month',
YEAR(fldDateTime) AS 'Year'
FROM
[Data.tblData]
WHERE
tblData_Id IN (SELECT DISTINCT tblData_Id
FROM [Data.tblData])
GROUP BY
YEAR(fldDateTime), MONTH(fldDateTime), DAY(fldDateTime),
tblData_Id,fldDateTime
ORDER BY
YEAR(fldDateTime), MONTH(fldDateTime), DAY(fldDateTime)
The problem I have is that it sums from midnight to midnight, I need it to sum the values after midnight ( >= Midnight) then up to midnight of the next day. The reason for this is the data that comes in for a day, is always after midnight. For example the first logged data will be '2016-01-01 00:01:00', the final logged data will be '2016-01-02 00:00:00'. This is how the hardware works that sends me the data.
I would like to know how to encapsulate >= midnight to midnight in the query.
Dataset:
DateTime Value
20/03/2016 00:30 69.00
20/03/2016 01:00 69.00
20/03/2016 01:30 69.00
20/03/2016 02:00 69.00
20/03/2016 02:30 69.00
20/03/2016 03:00 69.00
20/03/2016 03:30 11.88
20/03/2016 04:00 0.52
20/03/2016 04:30 1.51
20/03/2016 05:00 2.22
20/03/2016 05:30 2.11
20/03/2016 06:00 0.05
20/03/2016 06:30 6.78
20/03/2016 07:00 14.79
20/03/2016 07:30 1.57
20/03/2016 08:00 1.51
20/03/2016 08:30 4.81
20/03/2016 09:00 0.11
20/03/2016 09:30 8.99
20/03/2016 10:00 10.06
20/03/2016 10:30 15.28
20/03/2016 11:00 3.22
20/03/2016 11:30 1.73
20/03/2016 12:00 19.10
20/03/2016 12:30 2.08
20/03/2016 13:00 2.61
20/03/2016 13:30 0.84
20/03/2016 14:00 8.65
20/03/2016 14:30 2.37
20/03/2016 15:00 16.34
20/03/2016 15:30 12.66
20/03/2016 16:00 2.64
20/03/2016 16:30 0.19
20/03/2016 17:00 3.91
20/03/2016 17:30 2.39
20/03/2016 18:00 0.57
20/03/2016 18:30 1.30
20/03/2016 19:00 5.06
20/03/2016 19:30 17.45
20/03/2016 20:00 13.04
20/03/2016 20:30 5.00
20/03/2016 21:00 7.47
20/03/2016 21:30 5.09
20/03/2016 22:00 0.33
20/03/2016 22:30 5.29
20/03/2016 23:00 15.33
20/03/2016 23:30 5.39
21/03/2016 00:00 6.74
Thank you in advance.
The expected sum output value for 20/03/2016 is: 662.98
The output table will look like:
SumValue Day Month Year Meter Id
659.18 20 3 2016 6
251.37 21 3 2016 6
279.03 22 3 2016 6
280.03 23 3 2016 6
284.22 24 3 2016 6
310.12 25 3 2016 6
320.84 26 3 2016 6
269.29 27 3 2016 6
276.11 28 3 2016 6
279.11 29 3 2016 6
The value column is the sum of the values for that day, made up of lots of individual times.
Use the below query for summing up the midnight value with previous day.
SELECT
SUM(fldValue) AS 'kWh',
CASE WHEN CONVERT(VARCHAR(8), fldDateTime, 108)='00:00:00' THEN DAY(fldDateTime)-1 ELSE DAY(fldDateTime) END AS 'Day',
MONTH(fldDateTime) AS 'Month',
YEAR(fldDateTime) AS 'Year'
FROM
Data.[tblData]
GROUP BY
YEAR(fldDateTime), MONTH(fldDateTime),CASE WHEN CONVERT(VARCHAR(8), fldDateTime, 108)='00:00:00' THEN DAY(fldDateTime)-1 ELSE DAY(fldDateTime) END
ORDER BY
YEAR(fldDateTime), MONTH(fldDateTime), CASE WHEN CONVERT(VARCHAR(8), fldDateTime, 108)='00:00:00' THEN DAY(fldDateTime)-1 ELSE DAY(fldDateTime) END
Sample output :
First, I have no idea what the WHERE clause is doing, so I'm going to remove it.
Second, don't use single quotes for column names.
Third, your GROUP BY clause is too complicated. You only need to include the unaggregated columns in the SELECT.
Finally, the key idea is to subtract one hour from the values everywhere they are used. Here is a simple method:
SELECT SUM(fldValue) AS kWh,
DAY(newdt) AS [Day],
MONTH(newdt) AS [Month],
YEAR(newdt) AS [Year]
FROM (SELECT d.*, DATEADD(hour, -1, fldDateTime) as newdt
FROM Data.tblData d
) d
GROUP BY YEAR(newdt), MONTH(newdt), DAY(newdt)
ORDER BY YEAR(newdt), MONTH(newdt), DAY(newdt)
Same answer as #Gordon but you can subtract one minute instead of one hour.
SELECT SUM(fldValue) AS kWh,
DAY(newdt) AS [Day],
MONTH(newdt) AS [Month],
YEAR(newdt) AS [Year]
FROM (SELECT d.*, DATEADD(minute, -1, fldDateTime) as newdt
FROM Data.tblData d
) d
GROUP BY YEAR(newdt), MONTH(newdt), DAY(newdt)
ORDER BY YEAR(newdt), MONTH(newdt), DAY(newdt)
declare #tempTable table ([DateTime] datetime, Value Float)
insert into #tempTable ([DateTime], [Value])
select convert(datetime,'20/03/2016 00:30',103), 69.00 union all
select convert(datetime,'20/03/2016 01:00',103), 69.00 union all
select convert(datetime,'21/03/2016 00:00',103), 6.74
select * from #tempTable
select [sum] = SUM(value), [year] = year(DT), [month] = month(DT), [day] = day(DT)
from (select Value, DT = dateadd(second, -1, [DateTime]) from #tempTable) x
group by year(DT), month(DT), day(DT)
I have a table has following data
CREATE TABLE #TempStudentSchedulingRecord(
seq_id int identity(1,1),
Student_ID int ,
PeriodNumber int ,
CPStartTime datetime ,
CPEndTime datetime ,
DateItem datetime ,
FirstSegmentEndTime datetime,
SecondSegmentEndTime datetime
)
Now
Insert Into #TempStudentSchedulingRecord
values(2730,1,'1900-01-01 07:25:00.000','1900-01-01 08:20:00.000','2010-10-05 00:00:00.000','2015-05-27 09:45:00.000','2015-05-27 16:00:00.000')
Insert Into #TempStudentSchedulingRecord values(2730,1,'1900-01-01 08:25:00.000','1900-01-01 10:00:00.000','2010-10-05 00:00:00.000','2015-05-27 09:45:00.000','2015-05-27 16:00:00.000')
Insert Into #TempStudentSchedulingRecord values(2730,1,'1900-01-01 10:05:00.000','1900-01-01 11:35:00.000','2010-10-05 00:00:00.000','2015-05-27 09:45:00.000','2015-05-27 16:00:00.000')
Now Here The firstSegmentTime is same in all rows. I want To find The Total minutes scheduled before First segment End and classes included in first segment.
Similarly find the The Total minutes scheduled between First segment End time and second segment end time and classes included in first segment.
Here the Period 2 resides both segments.. How can I calculate total minutes scheduled before first segment and second segment.
Desired Output is
Student Period CPStartTime CPEndTime DateItem FSET SSET
2730 1 01/01/00 08:25 AM 01/01/00 10:00 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM
2730 2 01/01/00 08:25 AM 05/27/15 09:45 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM
2730 2 05/27/15 09:45 AM 01/01/00 10:00 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM
2730 3 01/01/00 10:05 AM 01/01/00 11:35 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM