My table:
timestamp | value
------------------------+---------
2013-08-31 22:00:01.000 | 19.1
2013-08-31 22:00:03.000 | 21.5
...
Due to missing seconds in my data series i want to calculate an average value per minute. So instead of having a data series in seconds I want to have it in minutes instead, like so:
timestamp | value
-----------------+---------
2013-08-31 22:00 | 19.5
2013-08-31 22:01 | 21.1
...
How could I write an SQL query that give me this result? I am using SQL Server 2012.
Casting from datetime to smalldatetime avoids tedious (and computationally slow) mucking about with date-to-character-back-to-date conversions. The following will calculate the average per minute.
SELECT
cast(Timestamp as smalldatetime) Timestamp
,avg(value) Value
from PageLogs
group by cast(Timestamp as smalldatetime)
order by cast(Timestamp as smalldatetime)
The downsides is rounding; this would convert values between 21:00:30.000 and 22:01:29.997 to 22:00. If you need to average by "calendar" minutes (22:00:00.000 to 22:00:59.997), you'd have to adjust the times (at the millisecond level) to get the right breakpoints, like so:
SELECT
cast(dateadd(ms, -30000, Timestamp) as smalldatetime) Timestamp
,avg(value) Value
from PageLogs
group by cast(dateadd(ms, -30000, Timestamp) as smalldatetime)
order by cast(dateadd(ms, -30000, Timestamp) as smalldatetime)
You can remove seconds using CONVERT() with format 100:
SELECT CONVERT(VARCHAR,GETDATE(),100) AS Dt
,AVG(value)
FROM YourTable
GROUP BY CONVERT(VARCHAR,GETDATE(),100)
You could re-cast as DATETIME() if needed:
CAST(CONVERT(VARCHAR,GETDATE(),100)AS DATETIME)
That has seconds/miliseconds but they are all zeroes.
Goat CO's answer will work, but if you need the exact date format in your example you need to construct it manually:
select
convert(varchar, datepart(year, ts)) + '-' +
convert(varchar, datepart(month, ts)) + '-' +
convert(varchar, datepart(day, ts)) + ' ' +
convert(varchar, datepart(hour, ts)) + ':' +
convert(varchar, datepart(minute, ts)) as timestamp,
avg(value) as value
from
tbl
group by
datepart(year, ts),
datepart(month, ts),
datepart(day, ts),
datepart(hour, ts),
datepart(minute, ts)
Related
How to get the time by minutes and seconds of each record and then sum the totals
Look at the images of how it is currently and how I would like it to appear.
Thanks
DECLARE #TimeInSeconds INT
SET #TimeInSeconds = (SELECT Datediff(second, Min(lra.time), Max(lra.time))
segundos
FROM log_rpa lra
WHERE 1 = 1
AND date = Cast(Getdate() AS DATE)
-- Ejecución hoy
GROUP BY lra.log_id)
SELECT lr.log_id,
lr.project,
Datediff(minute, Min(lr.time), Max(lr.time)) Tiempo_ejecucion_minutos,
Datediff(second, Min(lr.time), Max(lr.time)) segundos,
(SELECT RIGHT('0' + Cast(#TimeInSeconds / 3600 AS VARCHAR), 2)
+ ':'
+ RIGHT('0' + Cast((#TimeInSeconds / 60) % 60 AS VARCHAR), 2)
+ ':'
+ RIGHT('0' + Cast(#TimeInSeconds % 60 AS VARCHAR), 2))
Tiempo_Ejecucion_exacta
FROM log_rpa lr
WHERE 1 = 1
GROUP BY lr.log_id,
lr.project,
lr.date
ORDER BY lr.date DESC
Is so
I need it
If I need the DurationTime values to be totalled as a sum as it does?
Looks like you are stuck on the duration formatting. The #TimeInSeconds variable is a constant (its value does not change after the initial SET) and therefore produces constant results (00:05:10).
The solution below takes the time difference in seconds (datediff(SS, ...)) and adds those seconds to an empty datetime (equal to 1900-01-01 00:00:00.000, abbreviated like 00:00:00 in the code). Converting this back to the type time drops the date part.
Sample data
create table MyLog
(
ProjId int,
LogId int,
LogDate date,
LogTime time
);
insert into MyLog (ProjId, LogId, LogDate, LogTime) values
(100, 101, '2020-09-16', '01:00:00'),
(100, 101, '2020-09-16', '01:01:05'), -- project 100, task 101 takes 00:01:05
(100, 102, '2020-09-16', '02:00:00'),
(100, 102, '2020-09-16', '02:05:00'),
(100, 102, '2020-09-16', '02:08:00'); -- project 100, task 102 takes 00:08:00
Solution
select ml.ProjId,
ml.LogId,
ml.LogDate,
min(ml.LogTime) as LogTimeFrom,
max(ml.LogTime) as LogTimeTo,
datediff(SS, min(ml.LogTime), max(ml.LogTime)) as DurationSec,
convert(time, dateadd(SS, datediff(SS, min(ml.LogTime), max(ml.LogTime)), '00:00:00')) as DurationTime
from MyLog ml
group by ml.ProjId,
ml.LogId,
ml.LogDate
order by ml.ProjId,
ml.LogId;
Result
ProjId LogId LogDate LogTimeFrom LogTimeTo DurationSec DurationTime
------- ------ ----------- ------------ ---------- ------------ -------------
100 101 2020-09-16 01:00:00 01:01:05 65 00:01:05
100 102 2020-09-16 02:00:00 02:08:00 480 00:08:00
See it in action: fiddle.
I was writing an answer and Sander answered before me! Very similar answers but he was much more succinct.
Only minor issue with Sander's solution (which also exists in the original problem) is the GROUP BY ml.LogDate. If a log starts just before midnight and finishes after midnight, you may get two rows - which may have 0 time against them (some other solutions may have negative times e.g., 23:55:00 to 00:05:00 on next day results in -1430)
Instead, I suggest calculating the full datetime e.g., CAST([ml.LogDate] AS datetime) + CAST([ml.LogTime] AS datetime) the
use that for the DATEDIFFs
use the max (or min) date rather than group by
Here's a version of Sander's code that has been tweaked for the group by date issue
select ml.ProjId,
ml.LogId,
max(ml.LogDate) AS LogDate,
min(ml.LogDatetime) as LogTimeFrom,
max(ml.LogDatetime) as LogTimeTo,
datediff(SS, min(ml.LogDateTime), max(ml.LogDateTime)) as DurationSec,
convert(time, dateadd(SS, datediff(SS, min(ml.LogDateTime), max(ml.LogDateTime)), '00:00:00')) as DurationTime
from (select *, CAST(LogDate AS datetime) + CAST(logTime AS datetime) AS LogDatetime FROM MyLog) ml
group by ml.ProjId,
ml.LogId
order by ml.ProjId,
ml.LogId;
And here's the tweak on Sander's fiddle, with an additional log crossing midnight: fiddle
I have below View Query. While calculating time interval it only display time interval if check Out is for same date. For example if i check in on 11/12/2017 then it i have to check out with same date 11/12/201 n order to calculate time Interval.
But i want to modify it like if i checkout on next day (after 12:00 AM midnight) it should also calculate the time interval.can some help me to modify query to get the desired results?
Query:
ALTER VIEW [dbo].[TimeAttendanceQuery]
AS
SELECT TOP (100) PERCENT
dbo.AxPerson.Name,
dbo.AxPerson.IdNumber AS EmployeeID,
dbo.TimeAttendance.Badge,
dbo.AxPerson.Id,
MIN(dbo.TimeAttendance.EventTime) AS EntryTime,
MAX(dbo.TimeAttendance.EventTime) AS ExitTime,
CAST(DATEDIFF(second, MIN(dbo.TimeAttendance.EventTime), MAX(dbo.TimeAttendance.EventTime)) / 60 / 60 / 24 AS NVARCHAR(50)) +
':' + CAST(DATEDIFF(second, MIN(dbo.TimeAttendance.EventTime), MAX(dbo.TimeAttendance.EventTime)) / 60 / 60 % 24 AS NVARCHAR(50)) + ':' + CAST(DATEDIFF(second, MIN(dbo.TimeAttendance.EventTime), MAX(dbo.TimeAttendance.EventTime)) / 60 % 60 AS NVARCHAR(50))
AS TimeInterval,
dbo.TimeAttendance.Event,
dbo.AxPerson.Type AS ShitType,
dbo.AxPerson.ShiftDesc,
CONVERT(Varchar,dbo.TimeAttendance.EventTime, 101) AS EventTIME
FROM
dbo.AxPerson
INNER JOIN dbo.TimeAttendance ON dbo.AxPerson.Name = dbo.TimeAttendance.Name
GROUP BY dbo.AxPerson.Name, dbo.AxPerson.IdNumber, dbo.TimeAttendance.Badge, CONVERT(Varchar, dbo.TimeAttendance.EventTime, 101), dbo. AxPerson.ShiftDesc, dbo.AxPerson.Id, dbo.TimeAttendance.Event,dbo.AxPerson.Type
ORDER BY dbo.AxPerson.Name, EventTime DESC
GO
I'm not sure about the algorithm you posted, but if you want to get the time difference from two datetimes you can cast the subtraction as time. This works for less than 24 hours. If you also want the number of days (I think this is only good for less than a year), then you can do the datepart-day of the difference.
For example:
DECLARE #starttime datetime = '2017-11-12 010:20:00'
DECLARE #endtime datetime = '2017-11-13 08:00:00'
SELECT DATEPART(DAY, #endtime - #starttime) - 1 [Days Passed]
,CAST(#endtime - #starttime as time(0)) [Time Passed]
--WHERE the (0) in time(0) is for the milliseconds to return.
Gives output:
Days Passed Time Passed
0 21:40:00
If you don't care about the days, then your code could be modified like this:
ALTER VIEW [dbo].[TimeAttendanceQuery]
AS
SELECT Name, EmployeeID, Badge, Id, EntryTime,
CAST(ExitTime - EntryTime as time(0)) [TimeInterval],
Event, ShiftType, ShiftDesc
,CONVERT(Varchar, EventTime, 101) AS EventTIME
FROM (
SELECT
dbo.AxPerson.Name,
dbo.AxPerson.IdNumber AS EmployeeID,
dbo.TimeAttendance.Badge,
dbo.AxPerson.Id,
MIN(dbo.TimeAttendance.EventTime) AS EntryTime,
MAX(dbo.TimeAttendance.EventTime) AS ExitTime,
dbo.TimeAttendance.Event,
dbo.AxPerson.Type AS ShiftType,
dbo.AxPerson.ShiftDesc,
dbo.TimeAttendance.EventTime
FROM dbo.AxPerson INNER JOIN dbo.TimeAttendance
ON dbo.AxPerson.Name = dbo.TimeAttendance.Name
GROUP BY
dbo.AxPerson.Name,
dbo.AxPerson.IdNumber,
dbo.TimeAttendance.Badge,
dbo.AxPerson.Id,
dbo.TimeAttendance.Event,
dbo.AxPerson.Type
dbo.AxPerson.ShiftDesc,
dbo.TimeAttendance.EventTime,
) AS dT
I'm importing my data to excel and so I need to see the date as a varchar to use for a graph in excel but I also need the data for the individual hours in the day as well. My manager wants to see data for the past hour whenever he checks my chart. This is my code so far. Dayshift has been fine but I can't get the hours to go past 24 for nightshift so I can't group them in my graph in excel.
convert(VARCHAR, TimeStamp, 101) as date
,StationID as lane
,DATEPART(hh,TimeStamp)
,.185 as posSD1
,-.185 as negSD1
,.370 as posSD2
,-.370 as negSD2
,.556 as posSD3
,-.556 as negSD3
, COUNT (TrickleActual) as Count
, convert(decimal (18,3) ,AVG (TrickleActual - TrickleTarget)) as Average
FROM CherryBoxInfo
WHERE TimeStamp >= '2015-05-01' -- '2015-05-01 18:30:00'
and TimeStamp between convert(DATETIME, convert(VARCHAR, TimeStamp, 101) + ' ' + '19:00:00') and convert(DATETIME, convert(VARCHAR, DATEADD(day, 1, TimeStamp), 101) + ' ' + '04:30:00')
and (TrickleActual-TrickleTarget) BETWEEN -1 and 1
GROUP BY
convert(VARCHAR, TimeStamp, 101)
,StationID
,DATEPART(hh,TimeStamp)
ORDER BY convert(VARCHAR, TimeStamp, 101)
,StationID
,DATEPART(hh,TimeStamp)
Instead of grouping on datepart, group on date truncated to hour.
Here is how to truncate a date:
select dateadd(hh, datediff(hh, 0, #dt), 0)
I need to calculate the total length in terms of Hours, Minutes, Seconds, and the average length, given some data with start time and end time.
For example the result must be something like 45:15:10 which means 45 hours 15 min 10 sec, or 30:07 for 30 min 07 sec.
We're using SQL Server 2008 R2 and the conversion failed when time is more than 24:59:59. Any idea of how I could do this?
For information, the columns in the table are Id, StartDateTime, EndDateTime, etc. I need to make a monthly report which contains the recordings count of the month, the total length of these records, and the average length. I'd like to know if there is an easy way to perform all of this.
You shouldn't be converting to time - it is meant to store a point in time on a single 24h clock, not a duration or interval (even one that is constrained on its own to < 24 hours, which clearly your data is not). Instead you can take the datediff in the smallest interval required (in your case, seconds), and then perform some math and string manipulation to present it in the output format you need (it might also be preferable to return the seconds to the application or report tool and have it do this work).
DECLARE #d TABLE
(
id INT IDENTITY(1,1),
StartDateTime DATETIME,
EndDateTime DATETIME
);
INSERT #d(StartDateTime, EndDateTime) VALUES
(DATEADD(DAY, -2, GETDATE()), DATEADD(MINUTE, 15, GETDATE())),
(GETDATE() , DATEADD(MINUTE, 22, GETDATE())),
(DATEADD(DAY, -1, GETDATE()), DATEADD(MINUTE, 5, GETDATE())),
(DATEADD(DAY, -4, GETDATE()), DATEADD(SECOND, 14, GETDATE()));
;WITH x AS (SELECT id, StartDateTime, EndDateTime,
d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
FROM #d
)
SELECT id, StartDateTime, EndDateTime,
[delta_HH:MM:SS] = CONVERT(VARCHAR(5), d/60/60)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
[avg_HH:MM:SS] = CONVERT(VARCHAR(5), a/60/60)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;
Results:
id StartDateTime EndDateTime delta_HH:MM:SS avg_HH:MM:SS
-- ------------------- ------------------- -------------- ------------
1 2013-01-19 14:24:46 2013-01-21 14:39:46 48:15:00 42:10:33
2 2013-01-21 14:24:46 2013-01-21 14:46:46 0:22:00 42:10:33
3 2013-01-20 14:24:46 2013-01-21 14:29:46 24:05:00 42:10:33
4 2013-01-17 14:24:46 2013-01-21 14:25:00 96:00:14 42:10:33
This isn't precisely what you asked for, as it won't show just MM:SS for deltas < 1 hour. You can adjust that with a simple CASE expression:
;WITH x AS (SELECT id, StartDateTime, EndDateTime,
d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
FROM #d
)
SELECT id, StartDateTime, EndDateTime,
[delta_HH:MM:SS] = CASE WHEN d >= 3600 THEN
CONVERT(VARCHAR(5), d/60/60) + ':' ELSE '' END
+ RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
[avg_HH:MM:SS] = CASE WHEN a >= 3600 THEN
CONVERT(VARCHAR(5), a/60/60) + ':' ELSE '' END
+ RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;
This query changes the delta column in the 2nd row in the above result from 0:22:00 to 22:00.
I slightly modified Avinash's answer as it may end with error if difference is too big. If you need only HH:mm:ss it is sufficient to distinguish at seconds level ony like this:
SELECT CONVERT(time,
DATEADD(s,
DATEDIFF(s,
'2018-01-07 09:53:00',
'2018-01-07 11:53:01'),
CAST('1900-01-01 00:00:00.0000000' as datetime2)
)
)
SELECT CONVERT(time,
DATEADD(mcs,
DATEDIFF(mcs,
'2007-05-07 09:53:00.0273335',
'2007-05-07 09:53:01.0376635'),
CAST('1900-01-01 00:00:00.0000000' as datetime2)
)
)
If you want to do averages, then the best approach is to convert to seconds or fractions of a day. Day fractions are convenient in SQL Server, because you can do things like:
select avg(cast(endtime - starttime) as float)
from t
You can convert it back to a datetime using the reverse cast:
select cast(avg(cast(endtime - starttime as float) as datetime)
from t
The arithmetic to get the times in the format you want . . . that is a pain. You might consider including days in the final format, and using:
select right(convert(varchar(255), <val>, 120), 10)
To get the hours exceeding 24, here is another approach:
select cast(floor(cast(<val> as float)*24) as varchar(255))+right(convert(varchar(255), <val>, 120), 6)
It uses convert for minutes and seconds, which should be padded with 0s on the left. It then appends the hours as a separate value.
Starting in SQL SERVER 2012, you don't need to use DATEDIFF function. You can use FORMAT function to achieve what you want:
SELECT
FORMAT(CONVERT(TIME, [appoitment].[Start] - [appointment].[End]), N'hh\:mm') AS 'Duration'
FROM
[tblAppointment] (NOLOCK)
A way that avoids overflows and can include days and go all the way to milliseconds in the output:
DECLARE #startDate AS DATETIME = '2018-06-01 14:20:02.100'
DECLARE #endDate AS DATETIME = '2018-06-02 15:23:09.000'
SELECT CAST(DATEDIFF(day,'1900-01-01', #endDate - #startDate) AS VARCHAR) + 'd ' + CONVERT(varchar(22), #endDate - #startDate, 114)
The above will return
1d 01:03:06:900
And, off course, you can use the formatting of your choice
SQL Supports datetime substraction which outputs a new datetime relative to the MIN date (for instance 1900-01-01, you can probably get this value from some system variable) This works better than DATEDIFF, because DATEDIFF will count ONE for each "datepart boundaries crossed", even if the elapsed time is less than a whole datapart. Another nice thing about this method is that it allows you to use the date formatting conversions.
If days is the (positive) number of days, like 0.5 for 12 hours, use this expression to format it as a proper duration:
CONVERT(varchar(9), FLOOR(days * 24)) + RIGHT(CONVERT(char(19), CAST(days AS datetime), 120), 6)
Excel will understands values up to 9999:59:59 when pasted. There apply a custom format: [h]:mm:ss in the English version ([u]:mm:ss for Dutch).
I have this query
select CONVERT(varchar(5), tdate ,108) AS [Time] from table
which gives me the time in 24 hour format( military)
I wanted to convert it into a 12 hour format so i tried the query below
select SUBSTRING(CONVERT(VARCHAR, tdate, 100),13,2) + ':'
+ SUBSTRING(CONVERT(VARCHAR, tdate, 100),16,2) + ''
+ SUBSTRING(CONVERT(VARCHAR, tdate, 100),18,2) AS T
from table
and i get the 12 hour format but I am just curious if there is a shorter or better way of doing it. any help?
If you want to convert the current datetime for example:
SELECT CONVERT(VARCHAR, getdate(), 100) AS DateTime_In_12h_Format
Instead of getdate() you can put your desired column in a query (such as tdate in your example). If you want JUST the time in 12h and not the date and time use substring/right to separate them. It seems that you already know how to =).
This page lists every datetime conversion. It's really handy if you need other types of conversions.
This will return just the time, not the date.
SELECT RIGHT(CONVERT(VARCHAR, getdate(), 100), 7) AS time
For your table data:
select RIGHT(CONVERT(varchar, tdate ,100), 7) AS [Time] from table
Below code will return only time like 10:30 PM
SELECT FORMAT(CAST(getdate() AS DATETIME),'hh:mm tt') AS [Time]
Get date of server
SELECT LTRIM(RIGHT(CONVERT(VARCHAR(20), GETDATE(), 100), 7))
or
If it is stored in the table
SELECT LTRIM(RIGHT(CONVERT(VARCHAR(20), datename, 100), 7))
Result:
11:41AM
ifnull(date_format(at.date_time,'%d/%m/%Y'),"") AS date_time,
ifnull(time_format(at.date_time ,'%h:%i:%s'),"") AS date_time
This is how a SQL procedure looks...(for separating date and time)..there is no need of a special column for time/date....
Note:if H instead of h it will show the "hour in 24 hour" format