How to get average of earliest datetime per day? - sql

I need to get average time based on their earliest check in for each day.
For example, these are my check in datetime.
Person | Checkin
-----------------
Jack 2022-01-06 16:42:34.000
Jack 2022-01-06 17:30:34.000
Jack 2022-01-07 10:22:34.000
Jack 2022-01-07 12:12:54.000
Jack 2022-01-08 11:08:53.000
When I want to calculate my average check in time based on earliest check in, I should only consider these datetime.
2022-01-06 16:42:34.000
2022-01-07 10:22:34.000
2022-01-08 11:08:53.000
This is my current sql to get the average check in time. But this consider all the datetime above and gets the average time.
Select Person,(CAST(DATEADD(SS, AVG(CAST(DATEDIFF(SS, '00:00:00', CAST(Checkin AS TIME)) AS BIGINT)), '00:00:00' ) AS TIME)) AS 'AvgCheckInTime' from #Tab_CheckIn
group by Person
How can I only consider the earliest datetime for each day and get the average time?

This is a little messy.
Firstly you need to group the data to get the earliest checkin my day. That's quite simple, using CONVERT to date and MIN.
Then you need to get the "average" of those times. You can't average a time in SQL Server, however, as time represents a point in time during the day not an interval, so it doesn't make sense to average them like it would a timespan. As a result you need to "convert" the values to a numerical value.
In this case I use DATEDIFF to get the number of seconds since midnight to the checkin converted to a time. Then I can average those values, and finally add those second to midnight:
WITH Earliest AS(
SELECT Person,
MIN(Checkin) AS EarliestCheckin
FROM dbo.YourTable
GROUP BY Person,
CONVERT(date,Checkin))
SELECT Person,
DATEADD(SECOND,AVG(DATEDIFF(SECOND,'00:00',CONVERT(time,EarliestCheckin))),CONVERT(time,'00:00')) AS AverageCheckin
FROM Earliest
GROUP BY Person;

Assuming you get desired result(except filtering the undesired dates)
Select t.Person,(CAST(DATEADD(SS, AVG(CAST(DATEDIFF(SS, '00:00:00', CAST(t.Checkin AS TIME)) AS BIGINT)), '00:00:00' ) AS TIME)) AS 'AvgCheckInTime'
from (SELECT Person, min(Checkin) as Checkin FROM #Tab_CheckIn
GROUP BY Person, cast(Checkin As Date)) t
group by t.Person

SELECT Person,(CAST(DATEADD(SS, AVG(CAST(DATEDIFF(SS, '00:00:00', CAST(Checkin AS TIME)) AS BIGINT)), '00:00:00' ) AS TIME)) AS 'AvgCheckInTime'
from (
SELECT person, checkin, row_number() over(PARTITION by person, CAST(checkin as DATE) order by checkin asc) as row
FROM #Tab_CheckIn) as p
where p.row =1
group by p.person

Related

Count Number of hours between a range SQL

Im trying to count the number of working hours from some users for the month, the only way to do it is to see the date and hour for the productions entries they made. so I got:
Select a.EmployeeID, cast(a.fDate as Date) fDate, datepart(HOUR, a.fDate) fHour
From Table
Group by a.EmployeeID, cast(a.fDate as Date), datepart(HOUR, a.fDate)
This gives me the detail by date of the hours production was done, however I would like to know the total of hours in that time frame. For example:
I know employee xxx on 09/01/2018 registered production at 10:00AM, 11:00AM 12:00PM and 1:00PM, so the result will be 4 hours. Every employee has different working days so thats the only way I think I can calculated this...
Help?
Can you use the DATEDIFF of the min and max of fDate, group by EmployeeId and Date of a.fDate?
For example:
Select a.EmployeeID, cast(a.fDate as Date) as fDate, min(a.fDate) as TimeIn, max(a.fDate) as TimeOut, (DATEDIFF(mi, min(a.fDate), max(a.fDate)) / 60) as Hours
From MyTable a
Group by a.EmployeeID, cast(a.fDate as Date)

SQL Count of date values that dont match hour and day in select statement

I have a problem unique to a business process. My user needs to know how many dates, counted, are before a specific end time that do not match on the hour or the day.
Here is an example.
AAA, 2016-03-15 16:00:28.967, 2016-03-15 16:02:58.487, 2016-03-17 14:01:24.243
In the example above id AAA has 3 entries. I need to count only the ones that don't have a matching hour and day. So the actual count should come out to be 2.
I have to do this all in SQL and can't use a CTE. It needs to be either a sub select or some type of join.
Something like this.
SELECT id, date, (
SELECT COUNT(*)
FROM x
WHERE day!=day
AND hour!=hour AND date < z
) AS DateCount
Results would be AAA, 2
I am thinking some type of recursive comparison but I am not sure how to accomplish this without a CTE.
In SQL Server you can try something like this:
SELECT id, CONVERT(VARCHAR(13), [date], 120) AS [Date], COUNT(*) AS DateCount
FROM YourTable
WHERE [date] < #ENDDATE
GROUP BY id, CONVERT(VARCHAR(13), [date], 120)
SELECT a AS current_a, COUNT(*) AS b,day AS day, hour as hour,
(SELECT COUNT(*)
FROM t
WHERE day != day
AND hour != hour
AND date < z ) as datecount
FROM t GROUP BY a ORDER by b DESC

Count distinct sql and break by day with timestamp over midnight

I have a time series of data that has a trip_id and time stamp. I'm trying to write a SQL query to give me the number of unique trip_id's that occur on one day.
The problem is that the trip's extend across midnight, as the next day comes the trip is treated as a new distinct value and counted twice using this code select date(Timestamp), COUNT(DISTINCT trip_id) . Any help or the appropriate point in the correct direction would be very much appreciated.
Data:
trip_id Timestamp
47585 "2015-11-05 09:22:23"
16935 "2015-11-05 12:34:28"
16935 "2015-11-05 20:40:28"
16935 "2015-11-05 23:09:24"
16935 "2015-11-05 23:21:58"
16935 "2015-11-06 00:22:05"
15434 "2015-11-06 21:23:28"
Desired Outcome
date count
2015-11-05 2
2015-11-06 1
Use the minimum of the timestamp for each trip:
select dte, count(*)
from (select trip_id, min(date_trunc('day', timestamp)) as dte
from t
group by trip_id
) t
group by dte
order by dte;
That is, count the day when the trip begins.

SQL Query to find difference in hours between first and last records of each day for a month, and sum each difference to find the total

This isn't the easiest query to describe in one sentence which is why the title might not be the best.
Basically I have a log of sign-ins. This log looks like:
ContactId, LocationId, TimeStamp
These represent a Contact (registered person) being seen at a location at a given time.
What I want to do it pick a datetime window, and for each day in that window I want to take the first sign-in, and the last sign-in and work out the difference in hours. This difference in hours should then contribute to an overall total, giving an estimate of the total time the Contact spent at the location during the month.
Days when the Contact was not seen should obviously be ignored, and days when the Contact was seen only once should not be used either as no difference can be calculated.
I know how to find the difference between two datetimes in hours:
select DATEDIFF(HOUR, datetime1, datetime2) as hoursestimate
But I'm not sure how to:
Make datetime1 and datetime2 the first and last record of a day.
Loop through the data increasing the day count to find a cumulative total of hours (TotalHours) over the month.
Once I have the cumulative hours total over the time period based on the first and last seen difference I will perform a join with my contact table to obtain their first and last name and order by this TotalHours column, so hopefully the final table I want to be returned from the query will be something like:
Id FirstName LastName TotalHours
35 Bob Bobberson 65
40 Jim Jimmerson 63
2 Harry Harrison 54
It's steps 1 and 2 that I'm a bit lost on however. Any thoughts?
I think you want two aggregations:
select contactid, sum(hoursestimate) as total
from (select contactid, cast(TimeStamp as date) as dte,
DATEDIFF(HOUR, min(TimeStamp), max(TimeStamp)) as hoursestimate
from t
where TimeStamp >= #start and TimeStamp < #end
group by contactid, cast(TimeStamp as date)
) t
group by contactid;
There are couple of different techniques that can help you here.
CAST will let you strip the date and time sections of the date time stamp from each other. This is really handy for grouping multiple records from the same day, but different times, together.
The HAVING can be used to filter out contacts with only record in a day. This works by counting the number of contributing records, and removing those below your threshold.
This example combines those techniques:
Exmaple
WITH SampleDate AS
(
/* Lets make some records to experiment with.
*/
SELECT
r.*
FROM
(
VALUES
(1, 1, '2015-01-01 09:00:00.000'),
(1, 1, '2015-01-01 12:00:00.000'),
(1, 1, '2015-01-01 17:00:00.000'),
(2, 1, '2015-01-01 09:00:00.000')
) AS r(ContactId, LocationId, [TimeStamp])
)
SELECT
ContactId,
LocationId,
CAST([TimeStamp] AS DATE) AS [Day],
MIN(CAST([TimeStamp] AS TIME)) AS FirstSeenTime,
MAX(CAST([TimeStamp] AS TIME)) AS LastSeenTime,
DATEDIFF(
HOUR,
MIN(CAST([TimeStamp] AS TIME)),
MAX(CAST([TimeStamp] AS TIME))
) AS HoursEstimate
FROM
SampleDate
GROUP BY
ContactId,
LocationId,
CAST([TimeStamp] AS DATE) -- Removing the time allows us to create 1 record per day.
HAVING
COUNT(*) > 1 -- Make sure we've seen the contact at least twice.
;

Average difference between two dates, grouped by a third field?

So say we have 3 fields, username, start_date, end_date
Users start and stop multiple records, eg below bob has started and stopped two records.
bob 1/2/13 11:00 1/2/13 13:00
jack 1/2/13 15:00 1/2/13 18:00
bob 2/2/13 14:00 1/2/13 19:00
I need to know the average time taken (ie diff between start and end), in hours, for each user (ie group by user, not just for each row).
I can't quite get my head around how to do the diff, average AND group by? Any help?
You don't specify the granularity you want for the diff. This does it in days:
select username, avg(end_date - start_date) as avg_days
from mytable
group by username
If you want the difference in seconds, use datediff():
select username, avg(datediff(ss, start_date, end_date)) as avg_seconds
...
datediff can measure the diff in any time unit up to years by varying the first parameter, which can be ss, mi, hh, dd, wk, mm or yy.
SELECT [username], AVG(TIMESTAMPDIFF(HOUR, start_date, end_date))
FROM [table]
GROUP BY [username]