Select Sum HH:MM for period between two dates - sql

I would like to get the sum of hours (Duration) worked between say 16/11/2016 09:00 > 15/12/2016 17:30. To achieve this I need to calculate the Duration for each day worked between the two dates and then to add those up to get monthly hours worked.
The EventTime table will contain data for every time a user clock in when they start work, clocks out at lunch time, clocks back in after lunch, and then clocks out at the end of the day.
I have managed to get this to work for a single day:
EMPLOYEE CLOCK IN CLOCK OUT DURATION
Tatjana 05/01/2017 08:33 05/01/2017 13:12 04:39
Harj 05/01/2017 10:59 05/01/2017 14:20 03:20
Tomasz 05/01/2017 09:55
John 05/01/2017 09:57
Sam 05/01/2017 08:11 05/01/2017 14:11 05:59
Paul 05/01/2017 09:39 05/01/2017 14:05 04:26
Adrian 05/01/2017 13:59
Sophie 05/01/2017 08:42
Meg 05/01/2017 07:56 05/01/2017 13:10 05:14
Anna 05/01/2017 07:59 05/01/2017 12:30 04:31
Adriana 05/01/2017 07:46 05/01/2017 12:44 04:58
Jacky 05/01/2017 09:01
Anna 05/01/2017 07:57 05/01/2017 12:29 04:32
Kelly 05/01/2017 07:56 05/01/2017 12:45 04:48
Ana 05/01/2017 07:41 05/01/2017 14:13 06:32
The above is achieved using the following query:
SELECT
u.Field14_50 AS EmployeeID,
u.Firstname,
u.Surname,
MIN(e.EventTime) AS [Clocked In],
CASE
WHEN MAX(e.EventTime) = MIN(e.EventTime) THEN NULL
WHEN MAX(e.EventTime) > MIN(e.EventTime) THEN MAX(e.EventTime)
END AS [Clocked Out],
CASE
WHEN MAX(e.EventTime) = MIN(e.EventTime) THEN NULL
WHEN MAX(e.EventTime) > MIN(e.EventTime) THEN FORMAT((DATEDIFF(SECOND, MIN(e.EventTime), MAX(e.EventTime)) / 3600) % 24, '00') + ':' + FORMAT((DATEDIFF(SECOND, MIN(e.EventTime), MAX(e.EventTime)) / 60) % 60, '00')
END AS [Duration]
FROM
UsersEx AS u
INNER JOIN
EventsEx AS e
ON
u.UserID = e.UserID
WHERE
u.Field14_50 <> ''
AND
u.DepartmentName IN (
'Production',
'Finance and Administration',
'Purchase',
'Sales',
'Warehouse'
)
AND
DAY(e.EventTime) = DAY(GETDATE()) AND MONTH(e.EventTime) = MONTH(GETDATE()) AND YEAR(e.EventTime) = YEAR(GETDATE())
AND
e.PeripheralName IN ('TIME AND ATTENDANCE OFFICE (In)', 'TIME AND ATTENDANCE OFFICE (Out)')
GROUP BY
u.Field14_50,
u.UserID,
u.FirstName,
u.Surname
ORDER BY
u.Surname ASC
I hope that is clear.
Thanks in advance.
Update: 06/01/2017
I am able to use the following query:
SELECT
u.FirstName,
e.EventTime
FROM
UsersEx AS u
INNER JOIN
EventsEx AS e
ON
u.UserID = e.UserID
WHERE
u.Field14_50 <> ''
AND
e.EventTime > '2016/11/16' AND e.EventTime < '2016/12/16'
AND
e.PeripheralName IN ('TIME AND ATTENDANCE OFFICE (In)', 'TIME AND ATTENDANCE OFFICE (Out)')
AND
u.DepartmentName IN ('Finance and Administration')
ORDER BY
u.Field14_50,
e.EventTime
ASC
to get this result:
Ram 16/11/2016 09:12
Ram 16/11/2016 12:59
Ram 16/11/2016 13:39
Ram 16/11/2016 17:47
Ram 17/11/2016 09:35
Ram 17/11/2016 12:45
Ram 17/11/2016 13:11
Ram 17/11/2016 17:43
Ram 21/11/2016 09:14
Ram 21/11/2016 12:24
Ram 21/11/2016 12:53
Ram 21/11/2016 17:36
Ram 22/11/2016 09:18
Ram 22/11/2016 13:32
Ram 22/11/2016 17:45
Ram 23/11/2016 09:10
Ram 23/11/2016 13:13
Ram 23/11/2016 13:51
Ram 24/11/2016 09:10
Ram 24/11/2016 13:15
Ram 24/11/2016 13:50
Ram 24/11/2016 17:41
Ram 25/11/2016 09:12
Ram 25/11/2016 17:36
Ram 28/11/2016 09:05
Ram 28/11/2016 12:32
Ram 28/11/2016 13:12
Ram 28/11/2016 17:40
Ram 29/11/2016 09:17
Ram 29/11/2016 12:45
Ram 29/11/2016 13:16
Ram 29/11/2016 17:50
Ram 30/11/2016 09:15
Ram 30/11/2016 12:51
Ram 30/11/2016 13:55
Ram 30/11/2016 17:31
Ram 01/12/2016 09:10
Ram 01/12/2016 12:44
Ram 01/12/2016 13:12
Ram 01/12/2016 17:36
Ram 02/12/2016 09:00
Ram 02/12/2016 12:19
Ram 02/12/2016 12:51
Ram 02/12/2016 17:38
Ram 05/12/2016 09:14
Ram 05/12/2016 12:45
Ram 05/12/2016 13:28
Ram 05/12/2016 17:45
Ram 06/12/2016 09:32
Ram 06/12/2016 12:15
Ram 06/12/2016 12:49
Ram 06/12/2016 17:51
Ram 07/12/2016 09:09
Ram 07/12/2016 12:43
Ram 07/12/2016 13:22
Ram 07/12/2016 17:51
Ram 08/12/2016 09:18
Ram 08/12/2016 12:54
Ram 08/12/2016 13:16
Ram 08/12/2016 17:39
Ram 09/12/2016 09:09
Ram 09/12/2016 18:02
Ram 12/12/2016 09:20
Ram 12/12/2016 12:55
Ram 12/12/2016 13:20
Ram 12/12/2016 17:47
Ram 13/12/2016 09:13
Ram 13/12/2016 13:10
Ram 13/12/2016 13:37
Ram 13/12/2016 18:01
Ram 15/12/2016 09:07
Ram 15/12/2016 12:37
Ram 15/12/2016 13:12
Ram 15/12/2016 17:53
Yuka 16/11/2016 08:52
Yuka 16/11/2016 19:05
Yuka 17/11/2016 09:02
Yuka 17/11/2016 18:25
Yuka 18/11/2016 08:23
Yuka 18/11/2016 18:26
Yuka 21/11/2016 08:12
Yuka 21/11/2016 17:59
Yuka 22/11/2016 08:51
Yuka 22/11/2016 17:44
Yuka 23/11/2016 08:43
Yuka 23/11/2016 18:07
Yuka 24/11/2016 08:42
Yuka 24/11/2016 18:24
Yuka 25/11/2016 08:37
Yuka 25/11/2016 17:34
Yuka 28/11/2016 08:44
Yuka 28/11/2016 18:03
Yuka 29/11/2016 08:11
Yuka 29/11/2016 16:58
Yuka 12/12/2016 08:51
Yuka 12/12/2016 17:57
Yuka 13/12/2016 07:51
Yuka 13/12/2016 18:30
Yuka 14/12/2016 08:32
Yuka 14/12/2016 18:04
Yuka 15/12/2016 08:40
Yuka 15/12/2016 18:09
Duncan 16/11/2016 07:25
Duncan 16/11/2016 18:28
Duncan 17/11/2016 07:25
Duncan 17/11/2016 17:48
Duncan 18/11/2016 07:29
Duncan 21/11/2016 07:33
Duncan 21/11/2016 17:48
Duncan 22/11/2016 07:31
Duncan 22/11/2016 18:14
Duncan 23/11/2016 07:43
Duncan 24/11/2016 07:21
Duncan 25/11/2016 07:32
Duncan 28/11/2016 07:35
Duncan 28/11/2016 18:11
Duncan 29/11/2016 07:34
Duncan 30/11/2016 07:35
Duncan 30/11/2016 18:21
Duncan 01/12/2016 07:27
Duncan 01/12/2016 17:57
Duncan 02/12/2016 07:38
Duncan 05/12/2016 07:29
Duncan 05/12/2016 18:12
Duncan 06/12/2016 07:28
Duncan 06/12/2016 17:37
Duncan 07/12/2016 07:13
Duncan 07/12/2016 07:19
Duncan 07/12/2016 18:01
Duncan 08/12/2016 07:22
Duncan 08/12/2016 17:56
Duncan 09/12/2016 07:24
Duncan 09/12/2016 17:30
Now how can I get the MIN and MAX for each user for each day from that result set (as below)?
Employee Clocked In Clocked Out Duration
Ram 16/11/2016 09:12 16/11/2016 17:47 08:35
Ram 17/11/2016 09:35 17/11/2016 17:43 08:08
...
Ram 13/12/2016 09:13 13/12/2016 18:01 08:48
Ram 15/12/2016 09:07 15/12/2016 17:53 08:46
and so on for each employee...

Convert each Duration field to seconds and then add it to the format HH:MM
This is an example:
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
CREATE TABLE #tmp (
Id INT IDENTITY
, duration VARCHAR(MAX)
)
INSERT INTO #tmp (duration)
VALUES ('04:39')
, ('03:20')
, ('05:59')
SELECT
Sum(Left(duration, 2) * 3600 + substring(duration, 4, 2) * 60) AS seconds
, CONVERT(VARCHAR, DATEADD(ms, (Sum(Left(duration, 2) * 3600 + substring(duration, 4, 2) * 60)) * 1000, 0), 114) AS 'seconds to HH:MM'
--http://stackoverflow.com/questions/1262497/how-to-convert-seconds-to-hhmmss-using-t-sql
FROM #tmp
DROP TABLE #tmp
RESULT
seconds seconds to HH:MM
----------- ------------------------------
50280 13:58:00:000
(1 row(s) affected)
One option to implement in your query this solution would be to use a CTE. In this case with a CTE would look something like this:
;WITH Base
AS (
SELECT u.Field14_50 AS EmployeeID
, u.Firstname
, u.Surname
, MIN(e.EventTime) AS [Clocked In]
, CASE
WHEN MAX(e.EventTime) = MIN(e.EventTime)
THEN NULL
WHEN MAX(e.EventTime) > MIN(e.EventTime)
THEN MAX(e.EventTime)
END AS [Clocked Out]
, CASE
WHEN MAX(e.EventTime) = MIN(e.EventTime)
THEN NULL
WHEN MAX(e.EventTime) > MIN(e.EventTime)
THEN FORMAT((DATEDIFF(SECOND, MIN(e.EventTime), MAX(e.EventTime)) / 3600) % 24, '00') + ':' + FORMAT((DATEDIFF(SECOND, MIN(e.EventTime), MAX(e.EventTime)) / 60) % 60, '00')
END AS [Duration]
FROM UsersEx AS u
INNER JOIN EventsEx AS e
ON u.UserID = e.UserID
WHERE u.Field14_50 <> ''
AND u.DepartmentName IN (
'Production'
, 'Finance and Administration'
, 'Purchase'
, 'Sales'
, 'Warehouse'
)
AND DAY(e.EventTime) = DAY(GETDATE())
AND MONTH(e.EventTime) = MONTH(GETDATE())
AND YEAR(e.EventTime) = YEAR(GETDATE())
AND e.PeripheralName IN (
'TIME AND ATTENDANCE OFFICE (In)'
, 'TIME AND ATTENDANCE OFFICE (Out)'
)
GROUP BY u.Field14_50
, u.UserID
, u.FirstName
, u.Surname
--ORDER BY u.Surname ASC --Don't include ORDER BY here.
)
SELECT CONVERT(VARCHAR, DATEADD(ms, (Sum(Left(duration, 2) * 3600 + substring(duration, 4, 2) * 60)) * 1000, 0), 114) AS 'sum of hours (Duration)'
FROM Base
ORDER BY u.Surname
UPDATED
According to your update, you would need to query using the MIN and MAX aggregate functions, but performing a GROUP BY for dates converted to DATE. With this you can get the highest and lowest value for each day.
CODE:
SELECT u.FirstName
, MIN(e.EventTime) AS 'Clocked In'
, CASE
WHEN MIN(e.EventTime) = MAX(e.EventTime)
THEN NULL
ELSE MAX(e.EventTime)
END AS 'Clocked Out'
, DATEDIFF(SECOND, min(e.EventTime), MAX(e.EventTime)) AS 'Duration in seconds'
, CONVERT(VARCHAR, DATEADD(ms, DATEDIFF(SECOND, min(e.EventTime), MAX(e.EventTime)) * 1000, 0), 114) AS 'Duration'
FROM UsersEx AS u
INNER JOIN EventsEx AS e
ON u.UserID = e.UserID
WHERE u.Field14_50 <> ''
AND e.EventTime > '2016/11/16'
AND e.EventTime < '2016/12/16'
AND e.PeripheralName IN (
'TIME AND ATTENDANCE OFFICE (In)'
, 'TIME AND ATTENDANCE OFFICE (Out)'
)
AND u.DepartmentName IN ('Finance and Administration')
GROUP BY u.FirstName
, cast(e.EventTime AS DATE)
ORDER BY u.FirstName
Then, you only need to sum the seconds and convert them to the HH:MM format that I showed you, using the CTE or a Subquery.

Related

SQL Server : update query doesn't change anything, shows no error

I am trying to update the table with the values from the same table.
What I want is to change the connection setup in the rows where the worker and client are same and that the changed row Connection setup started in 5mins after the other connection (with the same worker and client) ended.
I first created a SELECT query that returned me all the rows that needed to be changed
SELECT t.*
FROM Table1 t
WHERE EXISTS (SELECT 1 FROM Table1
WHERE worker = t.worker
AND client = t.client
AND t.SessionNo != SessionNo
AND t.[Connection setup] <= DATEADD(mi, 5, [Connection end])
AND t.[Connection setup] >= [Connection end])
Then I tried to import this query inside of an UPDATE query, but it didn't change anything :/ and it doesn't show me any errors.
UPDATE t
SET t.Start = t2.Start
FROM Table1 t
INNER JOIN Table1 t2 ON (t.SessionNo = t2.SessionNo)
WHERE t.worker = t2.worker
AND t.client = t2.client
AND t2.SessionNo <> t.SessionNo
AND t.[Connection setup] <= DATEADD(mi, 5, t2.[Connection end])
AND t.[Connection setup] >= t2.[Connection end]
Example:
The first table are the rows that should be changed. As you can see there is a column "right time" that shows what value should they have after the update.
SessionNo worker Tag Start Ende Dauer Connection setup Connection end client right_time
1 424568 mh 09.01.2020 00:00:00 13:45 13:49 00:04 09.01.2020 13:45:00 09.01.2020 13:49:00 OBENAT1D0209 13:44
2 269650 mg 09.03.2020 00:00:00 10:25 10:47 00:21 09.03.2020 10:25:00 09.03.2020 10:47:00 OBENAT1D0117 10:24
3 280892 mg 09.03.2020 00:00:00 12:19 12:22 00:03 09.03.2020 12:19:00 09.03.2020 12:22:00 OBENAT1D0117 12:19
4 175250 mg 09.03.2020 00:00:00 13:12 13:13 00:01 09.03.2020 13:12:00 09.03.2020 13:13:00 ORTNERAT1D0001 13:04
5 332684 dg 09.05.2020 00:00:00 16:05 16:33 00:28 09.05.2020 16:05:00 09.05.2020 16:33:00 KILLYAT3D0102 15:57
but as you can see here Start column is still the same.
SessionNo worker Tag Start Ende Dauer Connection setup Connection end client right_time
1 317045 mh 09.01.2020 00:00:00 09:29 09:38 00:09 09.01.2020 09:29:00 09.01.2020 09:38:00 AUMAAT1D0124 09:29
2 144035 sb 09.01.2020 00:00:00 11:09 11:27 00:18 09.01.2020 11:09:00 09.01.2020 11:27:00 OBENAT1D0231 11:09
3 437704 mh 09.01.2020 00:00:00 13:44 13:44 00:00 09.01.2020 13:44:00 09.01.2020 13:44:00 OBENAT1D0209 13:44
4 424568 mh 09.01.2020 00:00:00 13:45 13:49 00:04 09.01.2020 13:45:00 09.01.2020 13:49:00 OBENAT1D0209 13:44
5 219640 mh 09.01.2020 00:00:00 15:16 15:26 00:10 09.01.2020 15:16:00 09.01.2020 15:26:00 OBENAT1D0209 15:16
6 201023 mh 09.01.2020 00:00:00 16:29 16:35 00:06 09.01.2020 16:29:00 09.01.2020 16:35:00 OBENAT1D0209 16:29
7 236114 mg 09.03.2020 00:00:00 08:55 09:08 00:12 09.03.2020 08:55:00 09.03.2020 09:08:00 NULL NULL
8 271379 mg 09.03.2020 00:00:00 10:24 10:25 00:00 09.03.2020 10:24:00 09.03.2020 10:25:00 OBENAT1D0117 10:24
9 269650 mg 09.03.2020 00:00:00 10:25 10:47 00:21 09.03.2020 10:25:00 09.03.2020 10:47:00 OBENAT1D0117 10:24
10 290765 mg 09.03.2020 00:00:00 12:19 12:19 00:00 09.03.2020 12:19:00 09.03.2020 12:19:00 OBENAT1D0117 12:19
11 280892 mg 09.03.2020 00:00:00 12:19 12:22 00:03 09.03.2020 12:19:00 09.03.2020 12:22:00 OBENAT1D0117 12:19
12 538583 mg 09.03.2020 00:00:00 12:30 12:58 00:28 09.03.2020 12:30:00 09.03.2020 12:58:00 RATTAYAT1D0107 NULL
13 697202 mg 09.03.2020 00:00:00 13:04 13:08 00:04 09.03.2020 13:04:00 09.03.2020 13:08:00 ORTNERAT1D0001 13:04
14 175250 mg 09.03.2020 00:00:00 13:12 13:13 00:01 09.03.2020 13:12:00 09.03.2020 13:13:00 ORTNERAT1D0001 13:04
15 330580 dg 09.05.2020 00:00:00 15:57 16:05 00:08 09.05.2020 15:57:00 09.05.2020 16:05:00 KILLYAT3D0102 15:57
16 332684 dg 09.05.2020 00:00:00 16:05 16:33 00:28 09.05.2020 16:05:00 09.05.2020 16:33:00 KILLYAT3D0102 15:57
NOTE : In this case, in order to test the values I am changing the Start column instead of the connection startup.
You are updating zero rows, because of:
ON (t.SessionNo = t2.SessionNo)
...
AND t2.SessionNo <> t.SessionNo
You want to find rows with another session number, but you have t.SessionNo = t2.SessionNo, so this is exactly what you don't want.
You seem to think that a join needs a comparision with = on a single column, but this is not true. A join condition can be any boolean expression.
This may work for you:
UPDATE t
SET t.Start = t2.Start
FROM Table1 t
INNER JOIN Table1 t2 ON t.worker = t2.worker
AND t.client = t2.client
AND t.SessionNo <> t2.SessionNo
AND t.[Connection setup] <= DATEADD(mi, 5, t2.[Connection end])
AND t.[Connection setup] >= t2.[Connection end];

SQL Server SUM(Values)

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)

Find Monthly Average of remaining time

I am using SQL Server 2008R2, I have a Table named Timings which has Column names StartTime and EndTime.
What I need is to find the difference between StartTime and EndTime in time only(HH:MM),not the date, and the result which I get after the difference, I need monthly Average of that difference.
My Columns are in DateTime datatype which are as follows,
---------------------------------------
STARTTIME ENDTIME
---------------------------------------
02/08/2016 14:29 02/08/2016 14:30
07/07/2016 15:37 07/07/2016 15:37
07/07/2016 15:38 07/07/2016 15:39
07/07/2016 15:39 07/07/2016 15:39
07/07/2016 15:40 07/07/2016 15:40
07/07/2016 15:44 07/07/2016 15:45
07/07/2016 15:45 07/07/2016 15:45
07/07/2016 15:46 07/07/2016 15:46
07/07/2016 15:46 07/07/2016 15:53
07/07/2016 15:53 07/07/2016 15:54
07/07/2016 15:54 07/07/2016 15:54
02/12/2016 9:28 02/12/2016 9:28
02/12/2016 9:29 02/12/2016 9:29
02/12/2016 9:30 02/12/2016 9:30
02/12/2016 9:33 02/12/2016 9:34
02/12/2016 9:34 02/12/2016 9:35
So far I have tried this,
;With CTTT
AS (
Select STARTTIME
,ENDTIME
,(ENDTIME-STARTTIME) AS R
From Timings
)
Select AVG(Convert(Varchar(10),R,108))
From CTTT
I am getting this Error message,
Msg 8117, Level 16, State 1, Line 6
Operand data type varchar is invalid for avg operator.
I am not good at SQL,A help would be much appreciable.
Here's a working script that converts average datetime difference to hh:mm format.
--DROP TABLE #Test
--DROP TABLE #TestTemp
CREATE TABLE #Test
(
[START] DATETIME NOT NULL,
[END] DATETIME NOT NULL,
);
INSERT INTO #Test
SELECT
'02/08/2016 14:29', '02/08/2016 14:34'
UNION
SELECT
'02/08/2016 14:39', '02/08/2016 14:47'
SELECT * FROM #Test
SELECT
MONTH([START]) AS 'MONTH',
YEAR([START]) AS 'YEAR',
SUBSTRING(CONVERT(VARCHAR, CAST(AVG(CONVERT(FLOAT, [END] - [START])) AS DATETIME),108),1,5) AS 'DIFFERENCE'
FROM #Test
GROUP BY
MONTH([START]),
YEAR([START])
OUTPUT:
START END
2016-02-08 14:29:00.000 2016-02-08 14:34:00.000
2016-02-08 14:39:00.000 2016-02-08 14:47:00.000
MONTH YEAR DIFFERENCE
2 2016 00:06
For your convenience:
SELECT
MONTH(STARTTIME) AS 'MONTH',
YEAR(STARTTIME) AS 'YEAR',
SUBSTRING(CONVERT(VARCHAR, CAST(AVG(CONVERT(FLOAT, ENDTIME-STARTTIME)) AS DATETIME),108),1,5) AS 'DIFFERENCE'
FROM
Timings
GROUP BY
MONTH(STARTTIME),
YEAR(STARTTIME)
Try This,
select DATEPART(month,starttime) as Mon,
DATEPART(YEAR,starttime) as Years ,
avg(Convert(int,Hours)) as Hours,
AVG(Convert(int,minute)) as minutes from (select starttime,endtime,
convert(varchar(5),DateDiff(s, starttime, endtime)/3600) as Hours,convert(varchar(5),
DateDiff(s, starttime, endtime)%3600/60) as minute
from timings) as tbl
group by DATEPART(month,starttime),DATEPART(YEAR,starttime)
You shuold try this. This will resolve you error.
Select Convert(Varchar(10),AVG(R),108)
From CTTT

join status history

I have a table listing patient days for encounters. Below a sample for one encounter. Every day the patient is in the hospital one record is created at midnight untill discharge.
Enc_iD Day_Id ServiceDtTm AdmitDate
2616350 34707672 2/21/2013 23:59 21/FEB/13 12:19:00
2616350 34733898 2/22/2013 23:59 21/FEB/13 12:19:00
2616350 34748155 2/23/2013 23:59 21/FEB/13 12:19:00
2616350 34760403 2/24/2013 23:59 21/FEB/13 12:19:00
2616350 34784357 2/25/2013 23:59 21/FEB/13 12:19:00
2616350 34808228 2/26/2013 23:59 21/FEB/13 12:19:00
2616350 34814512 2/27/2013 10:10 21/FEB/13 12:19:00
In a separate table a status for every encounter is maintained irregulary by a user.
Enc_iD TransDtTm Status
2616350 2/21/2013 12:20
2616350 2/21/2013 13:29 1
2616350 2/22/2013 7:28 3
2616350 2/25/2013 13:44 2
2616350 2/27/2013 10:10 2
I want to create a resultset with SQL as below. So for every day in the top table the status that was the most recent at that ServiceDtTm.
Enc_iD Day_Id DtTime AdmitDate Status
2616350 34707672 2/21/2013 23:59 21/FEB/13 12:19:00 1
2616350 34733898 2/22/2013 23:59 21/FEB/13 12:19:00 3
2616350 34748155 2/23/2013 23:59 21/FEB/13 12:19:00 3
2616350 34760403 2/24/2013 23:59 21/FEB/13 12:19:00 3
2616350 34784357 2/25/2013 23:59 21/FEB/13 12:19:00 2
2616350 34808228 2/26/2013 23:59 21/FEB/13 12:19:00 2
2616350 34814512 2/27/2013 10:10 21/FEB/13 12:19:00 2
Any help is appreciated. Can't figure this out SQL. Only in excel by using vlookup with approximate match.
Robbert
I think the simplest solution is a correlated subquery. Here is the syntax in SQL Server:
select pd.*,
(select top 1 status
from status s
where s.enc_id = pd.enc_id and s.transdttm <= pd.servicedttm
order by s.transdttm
) as MostRecentStatus
from patientdays pd
For most other databases, it would look like:
select pd.*,
(select status
from status s
where s.enc_id = pd.enc_id and s.transdttm <= pd.servicedttm
order by s.transdttm
limit 1
) as MostRecentStatus
from patientdays pd

Average time difference between sql and excel?

I have these values of time (varchar): [hh:mm]
2:41
2:31
1:46
21:41
18:19
17:56
18:4
17:17
17:2
16:39
0:40
0:38
0:38
0:29
1:19
2:52
0:15
16:55
17:25
17:15
3:31
2:7
2:21
1:35
1:38
0:17
0:28
18:40
2:54
18:14
2:31
18:9
18:10
0:39
0:38
3:5
3:20
3:6
2:58
2:31
2:4
1:54
2:2
1:44
1:39
1:22
1:6
1:15
0:53
1:13
20:32
1:11
0:36
0:35
0:26
1:3
4:20
3:42
3:7
3:16
2:44
2:30
0:40
2:5
4:21
2:6
3:54
3:45
3:31
18:59
18:59
18:47
18:43
19:40
19:29
2:19
1:9
4:10
3:50
2:20
1:16
4:33
21:23
20:57
16:31
1:51
5:15
1:48
3:15
1:32
4:19
4:17
1:59
3:38
1:55
2:11
1:26
Now, when I do the average in excel the result is: 6:14
And if I do this in sql: (using: This)
select
Month(OperationDate) [Month], count(distinct IdOrder) OrderQty,
avg(DATEPART(hh,TimeSpent)*60 + DATEPART(mi,TimeSpent)) % 24 as AvgHour,
avg(DATEPART(hh,TimeSpent)*60 + DATEPART(mi,TimeSpent)) / 24 as AvgMinute
from #tmp1 tmp1
inner join tblCheckList tcl on tmp1.IdCheckList = tcl.IdCheckList
where TimeSpent<>'0:0'
group by Month(OperationDate)
It returns as average: 10:15
Why the difference?
Why % 24 and / 24?
Wouldn't you divide the average minutes by 60 to get the average hour?
avg(DATEPART(hh,TimeSpent)*60 + DATEPART(mi,TimeSpent)) / 60.0 as AvgHour,
avg(DATEPART(hh,TimeSpent)*60 + DATEPART(mi,TimeSpent)) as AvgMinute
This would take care of you as well.
Select Convert(Varchar(5),Convert(Time,DateAdd(mi,Avg(DateDiff(mi,0,Convert(DateTime,TimeColumn))),0)))
From TableName
The solution is to work with minutes and then, convert those minutes in Hours and Minutes:
avg(DATEPART(hh,TimeSpent)*60 + DATEPART(mi,TimeSpent)) / 60 as AvgHour,
avg(DATEPART(hh,TimeSpent)*60 + DATEPART(mi,TimeSpent)) % 60 as AvgMinute