I have 2 columns:
Duration | ID
0h 7m 55sec. | 1
0h 25m 33sec.| 2
10h 5m 5sec. | 3
4h 11m 31sec.| 4
Duration(nvarchar(255))
I want to calculate the Duration in TOTAL NUMBER OF SECONDS for each ID.
I tried using SUBSTRING and then CAST but it's not giving me the desired output. Any help on this would be much appreciated.
The query below is using str_to_date to cast the string, the time_to_sec function is converting the time portion to seconds.
This approach will break if duration exceeds 23h 59m 59sec. #Gordon Linoff's approach will handle that scenario.
select id,
duration,
time_to_sec(str_to_date(duration,'%Hh %im %ssec.')) as seconds_elapsed;
This answer is for MySQL, as the question was originally tagged.
Yuck. But you can do:
select (substring_index(col, 'h ', 1) * 60 * 60 +
substring_index(substring_index(col, 'm ', 2), ' ', -1) * 60 +
substring_index(substring_index(col, 'sec.',1),' ', -1)
) as duration_secs
from t;
This extracts each component and then uses implicit conversion for the calculation.
Related
I am working with a table that has a variety of column types in rather specific and strange formats. Specifically I have a column, 'Total_Time' that measures a duration in the format:
days:hours:minutes (d:hh:mm)
e.g 200:10:03 represents 200 days, 10 hours and 3 minutes.
I want to be able to run queries against this duration in order to filter upon time durations such as
SELECT * FROM [TestDB].[dbo].[myData] WHERE Total_Time < 0:1:20
Ideally this would provide me with a list of entries whose total time duration is less than 1 hour and 20 minutes. I'm not aware of how this is possible in an nvarchar format so I would appreciate any advice on how to approach this problem. Thanks in advance...
I would suggest converting that value to minutes, and then passing the parametrised value as minutes as well.
If we can assume that there will always be a days, hours, and minutes section (so N'0:0:10' would be used to represent 10 minutes) you could do something like this:
SELECT *
FROM (VALUES(N'200:10:03'))V(Duration)
CROSS APPLY (VALUES(CHARINDEX(':',V.Duration)))H(CI)
CROSS APPLY (VALUES(CHARINDEX(':',V.Duration,H.CI+1)))M(CI)
CROSS APPLY (VALUES(TRY_CONVERT(int,LEFT(V.Duration,H.CI-1)),TRY_CONVERT(int,SUBSTRING(V.Duration,H.CI+1, M.CI - H.CI-1)),TRY_CONVERT(int, STUFF(V.Duration,1,M.CI,''))))DHM(Days,Hours,Minutes)
CROSS APPLY (VALUES((DHM.Days*60*24) + (DHM.Hours * 60) + DHM.Minutes))D(Minutes)
WHERE D.[Minutes] < 80; --1 hour 20 minutes = 80 minutes
If you can, then ideally you should be fixing your design and just storing the value as a consumable value (like an int representing the number of minutes), or at least adding a computed column (likely PERSISTED and indexed appropriately) so that you can just reference that.
If you're on SQL Server 2022+, you could do something like this, which is less "awful" to look at:
SELECT *
FROM (VALUES(N'200:10:03'))V(Duration)
CROSS APPLY(SELECT SUM(CASE SS.ordinal WHEN 1 THEN TRY_CONVERT(int,SS.[value]) * 60 * 24
WHEN 2 THEN TRY_CONVERT(int,SS.[value]) * 60
WHEN 3 THEN TRY_CONVERT(int,SS.[value])
END) AS Minutes
FROM STRING_SPLIT(V.Duration,':',1) SS)D
WHERE D.[Minutes] < 80; --1 hour 20 minutes = 80 minutes;
I have a column which is a sum of total minutes users spend on a task. This column was got using:
(sum(cast(LTRIM(DATEDIFF(SECOND, 0, TotalTimeOtherTasks))as int)) over (partition by headLogs.operatorID)/60) as TotalTimeOtherTasks
This returns e.g 315.
TotalTimeOtherTasks is a column of times for that task e.g
00:30:23
01:05:55
I want to make this show in HH:mm format so, 315 = 05:15.
I've tried doing other answers for similar questions such as; using separate formulas and concatenating them but i get errors such as " '05:15' cannot be converted to an int " once it gets the answer or "':' is not recognized as part of the formula". If i convert it I then can't use sum(). So i think this might be its own question.
One method is to compute the minutes and seconds separately, and then concatenante them
concat(
sum(datediff(second, 0, TotalTimeOtherTasks))
over (partition by headLogs.operatorID) / 60,
':',
sum(datediff(second, 0, TotalTimeOtherTasks))
over (partition by headLogs.operatorID) % 60
) as TotalTimeOtherTasks
Note that I removed the casting, that seems unnecessary here: in most databases, datediff() returns a integer already.
Though the answer is already accepted, I will post my solutions which is working in MySQL.
Reference from here: Convert number of minutes to hh:mm
Assuming the following table structure
create table total_minutes(
id bigint(20) NOT NULL AUTO_INCREMENT,
total_time int,
primary key(id)
);
SELECT total_time, floor(total_time/60) as hours, lpad(floor(total_time%60), 2, '0') as minutes,
concat(floor(total_time/60), ":", lpad(floor(total_time%60), 2, '0')) as hh_mm FROM classifiedads.total_minutes;
Gives
t h m hh:mm
35 0 35 0:35
95 1 35 1:35
69 1 9 1:09
I am still a rookie in SQL Server so I can't quite figure this one out.
I have a column that is filled with nvarchar values that I need to sum as durationOfWork, so it needs to do the sum function for time values.
The columns are like this:
DurationOfWork FirstName
--------------------------
1h:30min Peter
2h:0min Sandra
0h:10min Peter
5h:32min Peter
2h:0min Dave
1h:43min Dave
0h:25min Sandra
I need to return for each Person the sum of their durations of work.
SUM(DurationOfWork) FirstName
------------------------------
7h:12min Peter
2h:25min Sandra
3h:43min Dave
Any help would be great.
What a pain. I would recommend calculating the duration as minutes or decimal hours, instead of converting back to a string. The idea is to extract what you want from the string and put it in a better format:
select firstname,
sum( convert(int, left(durationofwork, 1)) * 60 +
convert(int, substring(durationofwork, 4, 2))
) as duration_minutes
from t
group by firstname;
If your values are always less than 24 hours -- which they seem to be based on the format -- then I would suggest storing them as time values rather than strings. That said, sum()s might exceed 24 hours, so you can't use times for aggregated results.
EDIT:
To handle the variable minutes:
select firstname,
sum( convert(int, left(durationofwork, 1)) * 60 +
convert(int, replace(substring(durationofwork, 4, 2), 'm', ''))
) as duration_minutes
from t
group by firstname;
I have a result using SQL inside a function
select a[2] as hour, a[3] minutes from ( select regexp_split_to_array('for 7h 18m', ' ') ) as dt(a);
and i got result as
hour minutes
7h 18m
I want to get
minutes
438
The documentation has an example using extract and epoch.
SELECT EXTRACT(EPOCH FROM '2h 18m'::INTERVAL)/60;
One option here is to remove the h from the hours string, multiply by 60 to get minutes, then add this quantity to the minutes field, with the m removed. Try this query:
select regexp_replace(a[2], '[h\s]', '')::integer * 60 +
regexp_replace(a[3], '[m\s]', '')::integer as minutes
from
(
select regexp_split_to_array('for 7h 18m', ' ')
) as dt(a);
I have a query with the fields date hour and value.
It looks something like this
date hour value
xx/xx/xx 15 100
xx/xx/xx 30 122
xx/xx/xx 45 50
... 100 100
... 115 23
... ... ...
... ... ...
... 2400 400
... 15 23
Basically, date is the date, hour is the hour, and value is the value for that particular 15 minute interval. What I have been trying to figure out is a way to take each hour (so 15, 30, 45, and 100) or (1015, 1030, 1045, 1100) [As you can see hours are military-esque 1:00pm is 1300 and midnight 2400], and sum their values together. So i am looking to return something like this:
xx/xx/xx 100 372
xx/xx/xx 200 23 + (130 data) + (145 data) + (200 data)
And so on...
The table has on average around 100 days and they all start from 15 to 2400 incrementing by 15 with varying numbers for the value column.
I have thought about using a partition, group by, etc. with no real ideas how to tackle it. Essentially I have to take 4 rows (an hour), sum their values, spit out the date, hour, and summed value then repeat for every day. I am not asking for code, just some help with what i should be using since this seems like a simple problem minus the key to solving it.
Any help is greatly appreciated, Thank you!
Grouping by Hour/100 will almost get you there - subtract 1 from the hour will make 1 AM fall to 99, and get included in the grouping. This will give a query that looks like this:
SELECT Table1.Dte, Int(([tme]-1)/100) AS Hr, Sum(Table1.Val) AS TotVal
FROM Table1
GROUP BY Table1.Dte, Int(([tme]-1)/100);
I may have misremembered how you cast to int in Access, but this might work:
Select
[date],
100 * (1 + Cint(([Hour] - 1) / 100)),
Sum(Value)
From
Query
Group By
[date],
100 * (1 + Cint(([Hour] - 1) / 100))
Order By
1, 2
SELECT
DateCol,
Int(HourCol \ -100) * -100 AS Hr,
Sum(Value) AS Value
FROM
YourTable
GROUP BY
DateCol,
Int(HourCol \ -100) * -100
Or you can use ((Hr + 99) \ 100) * 100.