So my data looks like this:
DATE TEMPERATURE
2012-01-13 23:15:00 UTC 0
2012-01-14 01:35:00 UTC 5
2012-01-14 02:15:00 UTC 6
2012-01-14 03:15:00 UTC 8
2012-01-14 04:15:00 UTC 0
2012-01-14 04:55:00 UTC 0
2012-01-14 05:15:00 UTC -2
2012-01-14 05:35:00 UTC 0
I am trying to calculate the amount of time a zip code temperature will drop to 0 or below on any given day. On the 13th, it only happens for a very short amount of time so we don't really care. I want to know how to calculate the number of minutes this happens on the 14th, since it looks like a significantly (and consistently) cold day.
I want the query to add two more columns.
The first column added would be the time difference between the rows on a given date. So row 3- row 2=40 mins and row 4-row3=60 mins.
The second column would total the amount of minutes for a whole day the minutes the temperature has dropped to 0 or below. Here row 2-4 would be ignored. From row 5-8, total time that the temperature was 0 or below would be about 90 mins
It should end up looking like this:
DATE TEMPERATURE MINUTES_DIFFERENCE TOTAL_MINUTES
2012-01-13 23:15:00 UTC 0 0 0
2012-01-14 01:35:00 UTC 5 140 0
2012-01-14 02:15:00 UTC 6 40 0
2012-01-14 03:15:00 UTC 8 60 0
2012-01-14 04:15:00 UTC 0 60 60
2012-01-14 04:55:00 UTC 0 30 90
2012-01-14 05:15:00 UTC-2 20 110
2012-01-14 05:35:00 UTC 0 20 130
Use below
select *,
sum(minutes_difference) over(order by date) total_minutes
from (
select *,
ifnull(timestamp_diff(timestamp(date), lag(timestamp(date)) over(order by date), minute), 0) as minutes_difference
from your_table
)
if applied to sample data in your question - output is
Update to answer updated question
select * except(new_grp, grp),
sum(if(temperature > 0, 0, minutes_difference)) over(partition by grp order by date) total_minutes
from (
select *, countif(new_grp) over(order by date) as grp
from (
select *,
ifnull(timestamp_diff(timestamp(date), lag(timestamp(date)) over(order by date), minute), 0) as minutes_difference,
ifnull(((temperature <= 0) and (lag(temperature) over(order by date) > 0)) or
((temperature > 0) and (lag(temperature) over(order by date) <= 0)), true) as new_grp
from your_table
)
)
with output
I have a table which contains Students Attendance, the schema is
StudentId ClassId EventType EventTime
1 1 I 2018-10-31 07:00:00 AM
2 1 I 2018-10-31 07:02:00 AM
1 1 O 2018-10-31 07:31:00 AM
3 1 I 2018-10-31 07:45:00 AM
OutPut
ClassId StudentCount StartTime EndTime
1 2 2018-10-31 07:00:00 AM 2018-10-31 07:10:00 AM
1 2 2018-10-31 07:10:01 AM 2018-10-31 07:20:00 AM
1 2 2018-10-31 07:20:01 AM 2018-10-31 07:30:00 AM
1 1 2018-10-31 07:30:01 AM 2018-10-31 07:40:00 AM
1 2 2018-10-31 07:40:01 AM 2018-10-31 07:50:00 AM
You need to generate the times. One way uses a recursive CTE. Then there are various ways to get the count.
with times as (
select cast('2018-10-31 07:00:00' as datetime) dt
union all
select dateadd(minute, 10, dt)
from times
where dateadd(minute, 10, dt) < '2018-10-31 08:00:00'
)
select t.dt,
(select sum(case when eventtype = 'I' then 1 else -1 end)
from attendance a
where a.EventTime <= t.dt
) as attendance
from times;
I need to compare 2 dates and return the number of days in between. Here is a table as example:
+----+--------+-------------------------+-------------------------+
| id | userid | datestarted | datefinished |
+----+--------+-------------------------+-------------------------+
| | | | |
| 1 | 23 | 2014-03-25 09:05:00.000 | 2014-03-25 12:15:00.000 |
| 2 | 43 | 2014-03-25 09:05:00.000 | 2014-03-25 12:15:00.000 |
| 3 | 23 | 2014-03-31 09:05:00.000 | 2014-03-31 12:15:00.000 |
| 4 | 12 | 2014-03-25 09:05:00.000 | 2014-03-26 12:15:00.000 |
+----+--------+-------------------------+-------------------------+
In the first 3 cases, we have the same day, only the hours don't match.
Datestarted = 2014-03-25 09:05:00.000
Datefinished = 2014-03-25 12:15:00.000
We only input hours and minutes.
Until now, wee needed only to show the difference as whole number, without decimal points, and did it like this:
DATEDIFF(carsharing.datestarted, carsharing.datefinished)
But now, we have to show the difference between the dates as 0,5 day, if it is less than 4,5 hours. If the difference is greater it should stay as 1 day.
In the more complecated last case from the table, we should also compare and show difference between two different days
Datestarted = 2014-03-25 09:05:00.000
Datefinished = 2014-03-26 12:15:00.000
Here the result should be 1,5 days
I believe this is what you're looking for - this will round the difference to 0.5 for anything under 4.5 hours in the day, and everything else over that will go to a full day:
Declare #StartDate DateTime = '2014-03-25 09:05:00.000',
#EndDate DateTime = '2014-03-26 12:15:00.000'
;With TotalHours As
(
Select DateDiff(Minute, #StartDate, #EndDate) / 60.0 As TotalHours
)
Select Case
When TotalHours % 24 = 0
Then Floor(TotalHours / 24)
When TotalHours % 24 < 4.5
Then Floor(TotalHours / 24) + 0.5
Else Floor(TotalHours / 24) + 1.0
End As Days
From TotalHours
You can try this query. It gets the difference in minutes and multiply it by 2 in order to get a 0.5 day range. It then devide it by 24 hours and by 60 minutes before calculating the Ceiling value. Once you have it, it can be devide by 2 again.
When the value is over 4.5*24*60 (4.5 days in minutes), it only has to be devided by 24 and 60.
Query:
Select id, userid, datestarted, datefinished
, Days = Case When DATEDIFF(minute, datestarted, datefinished) > 4.5*60*24
then DATEDIFF(minute, datestarted, datefinished) / 24 / 60
else CEILING(((2.0*DATEDIFF(minute, datestarted, datefinished)) / 24 / 60)) / 2
end
From #dates
Output:
id userid datestarted datefinished Days
1 23 2014-03-25 09:05:00.000 2014-03-25 12:15:00.000 0.500000
2 43 2014-03-25 09:05:00.000 2014-03-25 12:15:00.000 0.500000
3 23 2014-03-31 09:05:00.000 2014-03-31 12:15:00.000 0.500000
4 12 2014-03-25 09:05:00.000 2014-03-26 12:15:00.000 1.500000
5 12 2014-03-25 09:05:00.000 2014-03-29 12:15:00.000 4.500000
6 12 2014-03-25 09:05:00.000 2014-03-29 22:15:00.000 4.000000
Sample Data
declare #dates table(id int, userid int, datestarted datetime, datefinished datetime);
insert into #dates(id, userid, datestarted, datefinished) values
(1, 23, '2014-03-25 09:05:00.000', '2014-03-25 12:15:00.000')
, (2, 43, '2014-03-25 09:05:00.000', '2014-03-25 12:15:00.000')
, (3, 23, '2014-03-31 09:05:00.000', '2014-03-31 12:15:00.000')
, (4, 12, '2014-03-25 09:05:00.000', '2014-03-26 12:15:00.000')
, (5, 12, '2014-03-25 09:05:00.000', '2014-03-29 12:15:00.000')
, (6, 12, '2014-03-25 09:05:00.000', '2014-03-29 22:15:00.000')
DECLARE
#StartDate datetime = '2014-03-25 09:05:00.000'
,#EndDate datetime = '2014-03-26 09:05:00.000'
;WITH d AS (SELECT DATEDIFF(d,#StartDate,#EndDate) Dys)
,h AS (SELECT DATEDIFF(hh,#StartDate,#EndDate) Hrs)
SELECT d.Dys + CASE WHEN (h.Hrs - d.Dys*24) = 0 THEN 0 ELSE CASE WHEN (h.Hrs - d.Dys*24) < 4.5 THEN 0.5 ELSE 1 END END
FROM d,h
How to find the date difference in hours between two records with nearest datetime value and it must be compared in same group?
Sample Data as follows:
Select * from tblGroup
Group FinishedDatetime
1 03-01-2009 00:00
1 13-01-2009 22:00
1 08-01-2009 03:00
2 01-01-2009 10:00
2 13-01-2009 20:00
2 10:01-2009 10:00
3 27-10-2008 00:00
3 29-10-2008 00:00
Expected Output :
Group FinishedDatetime Hours
1 03-01-2009 00:00 123
1 13-01-2009 22:00 139
1 08-01-2009 03:00 117
2 01-01-2009 10:00 216
2 13-01-2009 20:00 82
2 10:01-2009 10:00 82
3 27-10-2008 00:00 48
3 29-10-2008 00:00 48
Try this:
Select t1.[Group], DATEDIFF(HOUR, z.FinishedDatetime, t1.FinishedDatetime)
FROM tblGroup t1
OUTER APPLY(SELECT TOP 1 *
FROM tblGroup t2
WHERE t2.[Group] = t1.[Group] AND t2.FinishedDatetime<t1.FinishedDatetime
ORDER BY FinishedDatetime DESC)z
Out of hour calculation
An out of hour calendar defined as below,Here WeekNumber starts from 1 = Monday to 5 = Friday
CalendarId WeekNumber StartTime EndTime
600 1 1900-01-01 00:00 1900-01-01 08:00
600 1 1900-01-01 18:00 1900-01-01 23:59
600 2 1900-01-01 00:00 1900-01-01 08:00
600 2 1900-01-01 18:00 1900-01-01 23:59
600 3 1900-01-01 00:00 1900-01-01 08:00
600 3 1900-01-01 18:00 1900-01-01 23:59
600 4 1900-01-01 00:00 1900-01-01 08:00
600 4 1900-01-01 18:00 1900-01-01 23:59
600 5 1900-01-01 00:00 1900-01-01 08:00
600 5 1900-01-01 18:00 1900-01-01 23:59
I would like to apply this calendar to another table called events to find records falls in these day and times ?
Edit
The Structure of event table as follows
EventID StartDateTime TotalTimeInSec WeekNumber
1 2009-07-05 07:44 100 1
2 2009-07-05 08:40 200 1
3 2009-07-05 09:35 150 1
4 2009-07-05 10:37 200 1
5 2009-07-05 19:37 200 1
6 2009-07-05 20:37 200 1
The required output will be after appyling the calendar
EventID StartDateTime TotalTimeInSec WeekNumber
1 2009-07-05 07:44 100 1
5 2009-07-05 19:37 200 1
6 2009-07-05 20:37 200 1
Select a.WeekNumber,a.startDateTime,b.starttime,b.EndTime
from tblEvents a,(Select WeekNumber,Starttime,EndTime from tblMain) b
where a.startDateTime between b.starttime and b.EndTime
and a.WeekNumber = b.WeekNumber
Select E.*
From tblEvent E
Full outer Join tblMain M on E.WeekNumber = M.WeekNumber
Where E.StartDateTime Between M.StartTime and M.EndTime
I don't believe a full outer join is what you're asking for. And the other answer didn't seem to handle your method of storing time ranges as datetime values. The only tricky part seems to be handling that date math. You can find different ways to do that check, but I think this is one solution.
SELECT e.*
FROM
Events as e INNER JOIN Calendar as c
ON c.WeekNumber = e.WeekNumber
WHERE
/* CAST(CAST(e.StartDateTime AS TIME) AS DATETIME) -- later versions */
e.StartDateTime - DATEADD(dd, DATEDIFF(dd, 0, e.StartDateTime), 0)
BETWEEN c.StartTime and e.EndTime