I have a requirement in SQL where I have data of a server start stop time on daily basis for one month. I need the result where it should calculate the first start time of the day, last stop time of the day, total time server was started in a day on daily basis and for servers.
Table is like below and expected output is also given.
Table:
Date & Time Reader ServerID
3/14/2016 6:36:20 AM ON 123
3/14/2016 6:58:45 AM OFF 123
3/14/2016 8:06:19 AM ON 123
3/14/2016 9:32:48 AM OFF 123
3/15/16 6:00:00 AM ON 123
3/15/16 6:01:00 AM OFF 123
3/14/2016 9:46 AM ON 124
3/14/2016 10:01 AM OFF 124
3/14/16 11:01 AM ON 124
3/14/16 12:01 PM OFF 124
Expected output
UserID FirstIN Last Out TotalInTime (min) Date
123 6:00 09:32 86 3/14
123 06:00 06:01 1 3/15
124 9:46 12:01 75 3/14
So, for each day & server, you want the minimum and maximum time and the sum of minutes "ON".
First you need rows of ON/OFF pairs (pairs on a row, not pairs of rows) whose minutes you can calculate. Then you sum the minutes and take the minimum and maximum times.
SQL Server has datepart. You can use that to compute days. To make On/Off pairs, join the table to itself along these lines:
select A.ServerID, datepart(day, A.time) as day,
A.time as ON, min(B.time) as OFF
from T as A join T as B on datepart(day, A.time) = datepart(day, B.time)
and A.Reader = 'ON' and B.Reader = 'OFF'
and A.time < B.time
group by A.ServerID, datepart(day, A.time), A.time
You can make a view like that, or a CTE, or insert the results in a temporary table. Let's call the result V.
select ServerID, day, min(ON), max(OFF)
, sum(datediff(minute, OFF, ON)) as minutes
from V
group by ServerID, day
(You can also nest the first query inside the second one.)
The trick is knowing how to find the "next" time for any pair (a question I've answered often), and how to use the server's date functions.
Related
Let's say I have an employees list and I log inside "log" table the beginning and the end of the employee working day. Example:
ID
NAME
BEGINTIME
ENDTIME
1
Mary
05/04/2021 07:10
05/04/2021 10:10
2
John
05/04/2021 09:10
05/04/2021 14:10
And I want to search: how many employees where working at the same time (interval) and the number of them (if more than 1) and sort them from max to min.
Example: Mary and John were working at the same time May 4th from 09:10 to 10:10, before 09:10 Mary was alone, then John came at 10:10 and they were two employee working at the office (the max in that example) then Mary left the office at 10:10 and John was alone.
The point is due to COVID19, I want to know for on a specific date (May 4th in that example) when we had the more employees working in the office at the same time, to split them to lower that max.
Exepected result (the first row is to define the aim) :
MAXEMPLOYEES
FROMBEGINTIME
TOENDTIME
LISTAGG
120
dd/MM/YYYY HH:mm
dd/MM/YYYY HH:mm
...
2
05/04/2021 09:10
05/04/2021 10:10
Mary, John
I really don't know where to start, maybe I thought, find all the log for the May 4th (let's say 1000 row) and loop, first row then loop again to the other logs and if MYSELECTEDROWBEGINTIME >= NthBEGINTIME AND MYSELECTEDROWENDTIME <= NthENDTIME and loop to my list and then go the 2nd row etc.
For 12-12:30 interval, you can start working on this query:
select count(*) employees_count
from log
where begintime<to_date('05/04/2021 12:30','MM/DD/YYYY HH24:MI')
and endtime>to_date('05/04/2021 12:00','MM/DD/YYYY HH24:MI');
I'm assuming that the begintime and endtime are of date type. In general, your condition should be begintime<interval_endtime and endtime>interval_begintime.
For your example output in your original post, you may need a table for the time interval to be joined to log, which would look like this:
int_id
int_from
int_to
1
09:10
10:10
2
12:00
12:30
and your query for May 4, 2021 can be something like this:
select count(*) maxemployee,
int_from frombegintime,
int_to toendtime
from (
select log.id, log.begintime, log.endtime,
tint.int_from, tint.int_to
from log
join time_interval tint
on log.begintime<to_date('05/04/2021 '||tint.int_to,'MM/DD/YYYY HH24:MI')
and log.endtime>to_date('05/04/2021 '||tint.int_from,'MM/DD/YYYY HH24:MI')
) t
group by int_from, int_to
I have a list of julian dates that I need to keep in order ex. 362, 363, 364, 365, 001, 002, 003. My query starts with getting the last julian date processed and each date after that. Right now it will max my lowest date out at 365 and I can't get the records that follow it. The same set of data also has a date field with the year attached but it doesn't seem to be helpful since those records won't be gathered until the rollover is corrected. Here is my simplified query:
select JulianDate, RecordDate
from table
where JulianField > #LowestJulianDate
and RecordDate between GetDate() and DateAdd(day, 6, GetDate())
Sample date:
JulianDate
RecordDate
362
2020-12-28
363
2020-12-29
364
2020-12-30
365
2020-12-31
001
2021-01-01
002
2021-01-02
003
2021-01-03
Desired output:
JulianDate
362
363
364
365
001
002
003
So if you'll imagine we start on day 362, our #LowestJulianDate is 362, and our record date range is today and the next 6 days, completing that list of julian dates.
How can I get the dates to go in order and resolve in a rollover?
You cannot by just using the "JulianDate" which is actually the DayOfYear value. You would need to also store the year that it refers to either separately or as part of the "JulianDate" value. For example, instead of "362" you need "2021362".
well why not sorting by year column and Julian date column ?
select JulianDate, RecordDate
from table
order by yearcolumn,JulianDate
What we are doing in the case of not having a year and wanting to sort a list on the year rollover for a 7 day rolling window is looking at the left 1 of the Julian day. If it's less than 3 roll it's rolled over. We sort into 2 baskets (old year and new year), order them, then recombine them with the new year's data being the "greatest" in the list.
We look at the left 1 because in our application, the last day of data we get may be 357 and the rollover may be 003 for example.
I have an Oracle table filled with call information. I have the call datetime field (calldate). Each record represents one call. How do I find the average number of calls per hour by year?
Sample data:
Calldate Account Name
1/20/2016 10:16:09 AM 12345 Blee
1/20/2016 11:17:02 AM 45678 Foo
Something like:
1:00 AM 23
2:00 AM 22
3:00 AM 19
Thank you!
Something like:
select to_char(calldate, 'YYYY-HH24') as yyyyhh,
count(*) / count(distinct trunc(calldate)) as avg_per_hour
from t
group by to_char(calldate, 'YYYY-HH24')
order by yyyyhh;
Note: This treats days with no calls as NULL, rather than zero.
I'm using Microsoft SQL Server 2008, and have a data set that has entries for every few minutes, over a long period of time. I am using a program to graph the data, so i need to return about 20 values per hour. Some days the data is every minute, sometimes every five minutes, and sometimes every 8 or 9 minutes, so selecting every nth row won't give an even spread over time
eg for a sample in 2012, it looks like this :
DateTime
2012-01-01 08:00:10.000
2012-01-01 08:08:35.000
2012-01-01 08:17:01.000
2012-01-01 08:25:26.000
and for a sample the next year it looks like this:
DateTime
2013-07-20 08:00:00.000
2013-07-20 08:01:00.000
2013-07-20 08:02:00.000
2013-07-20 08:03:00.000
2013-07-20 08:04:00.000
at the moment I am using a statement like this:
SELECT * FROM [Master]
WHERE (((CAST(DATEPART(hour, DateTime)as varchar(2)))*60)
+CAST(DATEPART(minute, DateTime)as varchar(2))) % '5' = '0'
ORDER BY DateTime
This works fine for july 2013, but I miss most points in 2012, as it returns this
DateTime
2012-01-01 08:00:10.000
2012-01-01 08:25:26.000
2012-01-01 08:50:43.000
2012-01-01 09:15:59.000
2012-01-01 10:40:14.000
2012-01-01 11:05:30.000
What better way is there to do this?
EDIT: The table has a DateTime column, and a pressure column, and I need to output both and graph pressure against date and time.
Since they can be random for the hours, this should work for what you need:
Declare #NumberPerHour Int = 20
;With Cte As
(
Select DateTime, Row_Number() Over (Partition By DateDiff(Hour, 0, DateTime) Order By NewId()) RN
From Master
)
Select DateTime
From Cte
Where RN <= #NumberPerHour
Order By DateTime Asc
This will group the rows by the hour, and assign a random Row_Number ID to them, and only pull those with a Row_Number less than the number you're looking for per hour.
I need to perform a time sheet calculations Employee will punch in and punch out. I store those records in one table. That table has time and a field for in punch or out punch. Employee may go out for lunch or other reasons and punches for out and in. I need to deduct those times and get the working hours. My table will look like below :
PunchTime EmpCode IsInpunch
10:01 AM (A) T
12:03 PM (A) F (this isoutpunch)
01:05 PM (A) T
07:14 PM (A) F
10:32 AM (B) T
For (A)'s time 7.14 - 10.01 is the total hours, but he was not there between 12.03 to 01.05 so I need to deduct the lunch time and get the total hours. How to do this in Query
This is pretty straightforward. Assuming your T and F IsInPunch is balanced, which is to say for any day, you will have T-F or T-F-T-F etc (always paired), just total up the F and subtract the total of T's.
select empcode, DateValue(PunchTime),
sum(IIF(IsInPunch='F',PunchTime,0)) -
sum(IIF(IsInPunch='T',PunchTime,0))
from TimeSheet
group by empcode, DateValue(PunchTime)
(haven't got Access open but do check the syntax)