Using SQL Server 2005
Table1
ID Intime Outtime
001 00.21.00 00.48.00
002 08.23.00 13.45.00
003 00.34.00 00.18.00
I need to display the time time like 30 minutes or 1 Hours, it should display a roundoff time
Expected Output
ID Intime Outtime
001 00.30.00 01.00.00
002 08.30.00 14.00.00
003 01.00.00 00.30.00
How to make a query for the roundoff time.
You can round the current date to 30 minutes like:
select dateadd(mi, datediff(mi,0,getdate())/30*30, 0)
Explanation: this takes the number of minutes since the 0-date:
datediff(mi,0,getdate())
Then it rounds that to a multiple of 30 by dividing and multiplying by 30:
datediff(mi,0,getdate())/30*30
The result is added back to the 0-date to find the last 30 minute block
dateadd(mi, datediff(mi,0,getdate())/30*30, 0)
This can be adjusted easily for 60 minutes. :)
By checking the range
select ID,
DateAdd(mi, DateDiff(mi, 0, Intime +
case when InMi >= 15 then 30 - InMi else - InMi end), 0) as Intime,
DateAdd(mi, DateDiff(mi, 0, Outtime +
case when OutMi >= 15 then 30 - OutMi else - OutMi end), 0) as Outtime
FROM
(
select ID, Intime, Outtime,
datepart(mi, InTime) % 30 InMi,
datepart(mi, Outtime) % 30 OutMi
from tbl
) X
or by using the classical trick equivalent to Int(x+0.5)..
select ID,
dateadd(mi, ((datediff(mi, 0, Intime)+15)/30)*30, 0) Intime,
dateadd(mi, ((datediff(mi, 0, Outtime)+15)/30)*30, 0) Outtime
from tbl
IF you want to ROUNDUP instead
(you have a value going from 00.34.00 to 01.00.00) Then you need this
select ID,
dateadd(mi, ((datediff(mi, 0, Intime)+29)/30)*30, 0) Intime,
dateadd(mi, ((datediff(mi, 0, Outtime)+29)/30)*30, 0) Outtime
from tbl
Take a look at the DATEDIFF, DATEADD and DATEPART. You should be able to do what you want with that.
http://msdn.microsoft.com/en-us/library/ms189794.aspx
http://msdn.microsoft.com/en-us/library/ms186819.aspx
http://msdn.microsoft.com/en-us/library/ms174420.aspx
Here is kind of a step-by-step routine. I'm sure you can do something shorter and even more efficient. It would also simplify a lot if you used a datetime data type instead of a string.
declare #T table (id char(3), intime char(8), outtime char(8))
insert into #T values ('001', '00.21.00', '00.48.00')
insert into #T values ('002', '08.23.00', '13.45.00')
insert into #T values ('003', '00.34.00', '00.18.00')
;with
cteTime(id, intime, outtime)
as
( -- Convert to datetime
select
id,
cast(replace(intime, '.', ':') as datetime),
cast(replace(outtime, '.', ':') as datetime)
from #T
),
cteMinute(id, intime, outtime)
as
( -- Get the minute part
select
id,
datepart(mi, intime),
datepart(mi, outtime)
from cteTime
),
cteMinuteDiff(id, intime, outtime)
as
( -- Calcualte the desired diff
select
id,
case when intime > 30 then (60 - intime) else (30 - intime) end,
case when outtime > 30 then (60 - outtime) else (30 - outtime) end
from cteMinute
),
cteRoundTime(id, intime, outtime)
as
( -- Get the rounded time
select
cteTime.id,
dateadd(mi, cteMinuteDiff.intime, cteTime.intime),
dateadd(mi, cteMinuteDiff.outtime, cteTime.outtime)
from cteMinuteDiff
inner join cteTime
on cteMinuteDiff.id = cteTime.id
),
cteRoundedTimeParts(id, inHour, inMinute, outHour, outMinute)
as
( -- Split the time into parts
select
id,
cast(datepart(hh, intime) as varchar(2)) as inHour,
cast(datepart(mi, intime) as varchar(2)) as inMinute,
cast(datepart(hh, outtime) as varchar(2)) as outHour,
cast(datepart(mi, outtime) as varchar(2)) as outMinute
from cteRoundTime
),
cteRoundedTime(id, intime, outtime)
as
( -- Build the time string representation
select
id,
right('00'+inHour, 2)+'.'+right('00'+inMinute, 2)+'.00',
right('00'+outHour, 2)+'.'+right('00'+outMinute, 2)+'.00'
from cteRoundedTimeParts
)
select *
from cteRoundedTime
Related
I have a table with timestamp that I want to round off at 15 min. interval. I can round off using the below Query but it rounds off both 11:58 and 12:02 to 12:00 which is not what I want. I would like to round off timestamp at 15 min. interval which gives me time_untill ie for anything between 11:45 to 11:59 should be rounded off to 12 and anything between 12:00 to 12:14 should be rounded off to 12:15. Please let me know how can I achieve that? Thanks
SELECT transaction_id,
CONVERT(smalldatetime, ROUND(CONVERT(float, CONVERT(datetime, entry_date_time)) * 96.0, 0, 1) /96.0) as transaction_datetime
FROM <table>
You can use datetimefromparts():
select dateadd(minute,
15,
datetimefromparts(year(entry_date_time), month(entry_date_time), day(entry_date_time),
datepart(hour, entry_date_time),
15 * (datepart(minute, entry_date_time) / 15), 0, 0
)
) as roundup15
You could use the DATEADD/DATEDIFF method to truncate date/time values that's been available for a long time.
SELECT transaction_id,
entry_date_time,
DATEADD( MI, DATEDIFF( MI, '2010', entry_date_time)/15*15, '2010') as transaction_datetime
--FROM Sample Data
FROM (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) transaction_id,
DATEADD( SS, CHECKSUM(NEWID())%10000, CAST( GETDATE() AS smalldatetime)) AS entry_date_time
FROM sys.columns)x;
Something like this...
DECLARE #time TIME(0) = GETDATE();
SELECT
DATEADD(MINUTE,
(((DATEDIFF(MINUTE, '00:00:00', #time) % 60) / 15) * 15),
DATEADD(HOUR, DATEDIFF(HOUR, '00:00:00', #time), '00:00:00')
);
I have split the below query in 15 minute interval on the basis of Start datetime but this query is not providing the exact result set
as i am expecting.
Below is the example of query i want to execute.
select Date_Stamp,
Case when substring(convert(char(8),starttime,114), 1, 8) between '12:00:01 AM'and '12:15:00 AM' then '0015'
when substring(convert(char(8),starttime,114), 1, 8) between '12:15:01 AM'and '12:30:00 AM' then '0030'
when substring(convert(char(8),starttime,114), 1, 8) between '12:30:01 AM'and '12:45:00 AM' then '0045'
when substring(convert(char(8),starttime,114), 1, 8) between '12:45:01 AM'and '01:00:00 AM' then '0100'
and i want the result as
Date Need result set
12:01 AM '0015'
'12:15:01 '0030'
'12:30:01 '0045'
'12:45:01 '0100'
'01:00:01 '0115'
'01:15:01 '0130'
'01:30:01 '0145'
'01:45:01 '0200'
'02:00:01 '0215'
'02:15:01 '0230'
'02:30:01 '0245'
3:00:00 ' '0015'
'12:30:00 '0030'
'12:45:00 '0045'
'01:00:00 '0100'
'01:15:00 '0115'
'01:30:00 '0130'
'01:45:00 '0145'
'02:00:00 '0200'
'02:15:00 '0215'
'02:30:00 '0230'
'02:45:00 '0245'
Just change #starttime with your column name
DECLARE #starttime datetime = getdate()
SELECT CONCAT(CASE WHEN DATEPART(HH, #starttime) <= 9
THEN '00'+ CAST(DATEPART(HH, #starttime) AS VARCHAR(2))
ELSE '0'+CAST(DATEPART(HH, #STARTTIME) AS VARCHAR(2))
END,
CASE WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 1 AND 15
THEN 15
WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 16 AND 30
THEN 30
WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 31 AND 45
THEN 45
WHEN DATEPART(MINUTE, #STARTTIME) BETWEEN 46 AND 59 OR DATEPART(MINUTE, #STARTTIME) = 0
THEN 00
END)
You can use this date generator:
DEMO
DECLARE #Break INT = 15
;WITH Numbers (n) as
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1
FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0)) a(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(n)
)
,Dates as
(
SELECT dt
FROM Numbers
CROSS APPLY
(
VALUES (DATEADD(MINUTE , n, CAST(CAST(GETDATE() AS DATE) AS DATETIME)))
) X(Dt)
WHERE N % #Break = 0
AND CAST(DT AS DATE) = CAST(GETDATE() AS DATE) --Only for today's date
)
SELECT CONVERT(VARCHAR(10),Dt,108) [Time] , REPLACE(CONVERT(VARCHAR(5),ISNULL(Lead(Dt) OVER (ORDER BY Dt) , DATEADD(MINUTE,#Break,Dt)),108), ':','') Grp
FROM Dates
It appears you're using datetime and have only taken the substring of the time. A string cannot be compared to a time, without being casted to the time datatype.
For example:
DECLARE #mytable TABLE (starttime datetime)
INSERT INTO #mytable VALUES ('2018-03-13 00:00:01'), ('2018-03-15 00:00:01')
SELECT * FROM #mytable
select CAST(starttime as time(0)) AS [thetime],
Case when CAST(starttime as time) between '12:00:01 AM'and '12:15:00 AM' then '0015'
when CAST(starttime as time) between '12:15:01 AM'and '12:30:00 AM' then '0030'
when CAST(starttime as time) between '12:30:01 AM'and '12:45:00 AM' then '0045'
when CAST(starttime as time) between '12:45:01 AM'and '01:00:00 AM' then '0100'
END AS [Interval]
FROM #mytable
Produces:
thetime Interval
00:00:01 0015
00:15:01 0030
following code returns
CREATE TABLE #emp1
(
empid VARCHAR(50),
empname VARCHAR(50),
intime SMALLDATETIME,
outtime SMALLDATETIME
)
INSERT INTO #emp1
VALUES (2500,
'Arun',
'2014-01-01 09:00:00',
'2014-01-01 10:30:0'),
(2500,
'Arun',
'2014-01-01 11:00:00:00',
'2014-01-01 11:00:0'),
(2500,
'Arun',
'2014-01-01 11:30:00:00',
'2014-01-01 19:00:00')
SELECT empid,
Cast(intime AS DATE)
AS workingday,
empname,
RIGHT('0' + CONVERT(VARCHAR, Floor(Sum( Datediff( mi, intime, outtime)/
60.0))),
2)
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR, Sum( Datediff( mi, intime, outtime))%60),
2) AS
[total work_hour(s)],
CONVERT(VARCHAR(5), Max(outtime) - Min(intime), 108)
AS Difference,
Cast(Dateadd(minute, Sum(Datediff(mi, intime, outtime)) - 45, 0) AS TIME)
AS
TotalTime,
Cast(Dateadd(minute, CASE
WHEN Sum(Datediff(mi, intime, outtime)) > 525 THEN
Sum(
Datediff(mi, intime, outtime)) - 525
ELSE 0
END, 0) AS TIME)
AS OverTime
FROM #emp1
GROUP BY empid,
empname,
Cast(intime AS DATE)
DROP TABLE #emp1
as
EmpId workingday EmpName total work_hour(s) Difference TotalTime OverTime
2500 2014-01-01 Arun 09:00 10:00 08:15:00.0000000 00:15:00.0000000
Here TotalTime is 08:15 and OverTime is 00:15. Everything is fine.
However, I need another field ActualTime
i.e. if TotalTime is greater than 8 hours then ActualTime is the difference of TotalTime and OverTime. In this example ActualTime should be 08:00.
If TotalTime is less than 8 hours then ActualTime is the same as TotalTime.
Finally, I also want to avoid excess zeros in TotalTime and OverTime
I imagine you want something like this: *EDIT nullcheck added
;with x as
(
SELECT empid,
Cast(intime AS DATE) workingday,
empname,
cast(dateadd(mi, sum(datediff(mi, 0, outtime - intime)), 0) as time) twh,
cast(dateadd(mi,datediff(mi,0,max(outtime)-min(intime)), 0) as time) Difference,
case when count(outtime)=count(*) then '' end nullcheck
FROM #emp1
GROUP BY empid, empname, Cast(intime AS DATE)
)
select empid, workingday, empname,
nullcheck+left(twh, 5) [total_hours],
nullcheck+left(Difference, 5) Difference,
nullcheck+left(cast(dateadd(mi, -45, twh)as time ),5) TotalTime,
nullcheck+left(case when twh > '08:45' then cast(dateadd(mi, -525, twh) as time) else '00:00' end, 5) OverTime,
nullcheck+left(case when twh > '08:00' then '08:00' else twh end, 5) actualtime
from x
Result:
empid workingday empname total_hours Difference TotalTime OverTime actualtime
2500 2014-01-01 Arun 09:00 10:00 08:15 00:15 08:00
First I'd wrap your entire current query in a Common Table Expression, so that the parts of it can be reused.
WITH CalculatedTime AS (SELECT empid,
Cast(intime AS DATE) AS workingday,
empname,
RIGHT('0' + CONVERT(VARCHAR, Floor(Sum( Datediff( mi, intime, outtime)/
60.0))),
2)
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR, Sum( Datediff( mi, intime, outtime))%60),
2) AS [total work_hour(s)],
CONVERT(VARCHAR(5), Max(outtime) - Min(intime), 108)
AS Difference,
Cast(Dateadd(minute, Sum(Datediff(mi, intime, outtime)) - 45, 0) AS TIME)
TotalTime,
Cast(Dateadd(minute, CASE
WHEN Sum(Datediff(mi, intime, outtime)) > 525 THEN
Sum(
Datediff(mi, intime, outtime)) - 525
ELSE 0
END, 0) AS TIME)
OverTime
FROM #emp1
GROUP BY empid,
empname,
Cast(intime AS DATE) )
Now we can refer to CalculatedTime as a table in itself, and we don't need to repeat any of that nasty logic used for calculating the TotalTime column.
So the final step is to use a case statement to perform the calculation you are after:
SELECT *,
CASE WHEN DATEDIFF(minute,TotalTime,'08:00') > 0 THEN TotalTime
ELSE DATEADD(minute, DATEDIFF(minute,OverTime, 0), TotalTime)
END AS ActualTime
FROM CalculatedTime
The formatting part of the problem (remove the extra zeros) is a separate question that has been answered many times before on StackOverflow.
In SQL Server, I have a start time column on a table such as:
2011-09-18 08:06:36.000
2011-09-19 05:42:16.000
2011-09-20 08:02:26.000
2011-09-21 08:37:24.000
2011-09-22 08:22:20.000
2011-09-23 11:58:27.000
2011-09-24 09:00:48.000
2011-09-25 06:51:34.000
2011-09-26 06:09:05.000
2011-09-27 08:25:26.000
...
My question is, how can I get the average hour and minute? I want to know that what is the average start time for this job. (for example 07:22)
I tried something like this but didn't work:
select CAST(AVG(CAST(DATEPART(HH, START_TIME)AS float)) AS datetime) FROM
Thanks.
declare #T table(StartTime datetime)
insert into #T values
('2011-09-18 08:06:36.000'),
('2011-09-19 05:42:16.000'),
('2011-09-20 08:02:26.000'),
('2011-09-21 08:37:24.000'),
('2011-09-22 08:22:20.000'),
('2011-09-23 11:58:27.000'),
('2011-09-24 09:00:48.000'),
('2011-09-25 06:51:34.000'),
('2011-09-26 06:09:05.000'),
('2011-09-27 08:25:26.000')
;with C(Sec) as
(
select dateadd(second, avg(datediff(second, dateadd(day, datediff(day, 0, StartTime), 0), StartTime)), 0)
from #T
)
select convert(char(5), dateadd(minute, case when datepart(second, C.Sec) >= 30 then 1 else 0 end, C.Sec), 108)
from C
-----
08:08
Try this :
select CAST((SUM(DATEPART(HH, START_TIME) * 60 + DATEPART(MI, START_TIME))/COUNT(*))/60 AS VARCHAR(10)) + ':' + CAST((SUM(DATEPART(HH, START_TIME) * 60 + DATEPART(MI, START_TIME))/COUNT(*))%60 AS VARCHAR(10))
FROM.....
Using SQL Server 2000:
SELECT PERSONID,
CARDEVENTDATE,
INTIME,
CASE
WHEN OUTTIME = INTIME THEN
'No PunchOut'
ELSE
OUTTIME
END AS OUTTIME,
CONVERT(char(8), CASE
WHEN DateAdd(Day, - DateDiff(Day, 0, OutTime), OutTime) > '18:00:00' THEN
Cast('18:00:00' AS datetime)
ELSE
DateAdd(Day, - DateDiff(Day, 0, OutTime), OutTime)
END - CASE
WHEN DateAdd(Day, - DateDiff(Day, 0, InTime), InTime) < '09:00:00' THEN
Cast('09:00:00' AS datetime)
ELSE
DateAdd(Day, - DateDiff(Day, 0, InTime), InTime)
END, 8) AS WorkTime
FROM (SELECT T_PERSON.PERSONID,
T_CARDEVENT.CARDEVENTDATE,
MIN(T_CARDEVENT.CARDEVENTTIME) AS INTIME,
MAX(T_CARDEVENT.CARDEVENTTIME) AS OUTTIME
FROM T_PERSON
INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID
GROUP BY T_PERSON.PERSONID, T_CARDEVENT.CARDEVENTDATE) DERIVEDTBL
T_cardevent.cardeventtime column datatype is Varchar.
In table Cardeventtime values are 080002, 091235.... so on...,
When I executing the above query it showing Arithmetic Express Overflow error for converting expression to datatype Datetime.
So this "080002" stands for? 8 hours, 0 minutes, 2 seconds?
This is definitely not a valid DATETIME format out of the box - and it doesn't comply with any of the valid SQL Server CONVERT styles, either.
So you'll have to do some conversions yourself, manually. Is there any chance you could wrap the table with this column into a view which could handle the conversion?
You'd have to do something along the lines of:
CONVERT(DATETIME, SUBSTRING(CardEventTime, 1, 2) + ':' +
SUBSTRING(CardEventTime, 3, 2) + ':' +
SUBSTRING(CardEventTime, 5, 2), 8)
and this should turn your "080002" into "08:00:02" which can then be converted to a DATETIME (no separate time datatype until SQL Server 2008) using the style no. 8 (hh:mm:ss).
Marc
I've made a series of assumptions here, and worked without being able to test it, but here's a possible solution:
SELECT PERSONID,
CARDEVENTDATE,
INTIME,
CASE
WHEN OUTTIME = INTIME THEN
'No PunchOut'
ELSE
OUTTIME
END AS OUTTIME,
Stuff(Stuff(Right('000000' +
CONVERT(varchar(5), CASE
WHEN Convert(int,OutTime) > 180000 THEN
180000
ELSE
Convert(int,OutTime)
END - CASE
WHEN Convert(int,InTime) < 90000 THEN
90000
ELSE
Convert(int,InTime)
END), 6),5,0,':'),3,0,':')
AS WorkTime
FROM (SELECT T_PERSON.PERSONID,
T_CARDEVENT.CARDEVENTDATE,
MIN(T_CARDEVENT.CARDEVENTTIME) AS INTIME,
MAX(T_CARDEVENT.CARDEVENTTIME) AS OUTTIME
FROM T_PERSON
INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID
GROUP BY T_PERSON.PERSONID, T_CARDEVENT.CARDEVENTDATE) DERIVEDTBL
I've not used Stuff very frequently, so the insertion points may be off.