3

I have a column in table TotalHours which is of type float.

The value are as

  • 3.4
  • 1.3
  • 4.2

the format the hour column is following is like hours.min

I want to get the total sum

the query which i am using is as

select sum(TotalHours) as hours from workdone where userid = 3

so it is returning 8.9 which is wrong, first i need to convert it to hours and then take the sum but i am stucked.

How do I get convert the values to hours and get sum?

Edited:The sum value will be in float format again. For eg, the sum result should be 9.3

Hassaan
  • 3,931
  • 11
  • 34
  • 67

4 Answers4

1

This is not a good way to store duration. Storing decimal seconds, minutes, hours is fine, but it should be to base 10, i.e. 1 hour 30 minutes, should be 1.5 hours, or 90 minutes, not 1.3 - What if someone inserts 1.7 into your table? It is also much simpler to add/subtract data stored in seconds/minutes, and to reformat as required.

Anyway, you can do the conversion using some fairly simple logic. The hours portion will just be the portion before the decimal, i.e. the integer part of the number, this can be obtained by rounding your number down - e.g. FLOOR(1.3) = 1 hour. Then to get the number of minutes you need to extract the decimal part of the number and multiply by 100 - e.g. extract 0.3 from 1.3 and multiply this by 100 to get 30 minutes.

SELECT  [Hours] = FLOOR(n),
        [Minutes] = (n - FLOOR(n)) * 100,
        TotalMinutes = (FLOOR(n) * 60) + (n - FLOOR(n)) * 100,
        SummedMinutes = SUM((FLOOR(n) * 60) + (n - FLOOR(n)) * 100) OVER(),
        SummedHours = SUM((FLOOR(n) * 60) + (n - FLOOR(n)) * 100) OVER() / 60.0
FROM    (VALUES (3.4), (1.3), (4.2)) t (N);

Then if you need to convert 9.5 hours back to 9.3 (again, this is a terrible way of representing 9 hours 30 minutes) you would need to reverse the logic above, i.e. Total hours + (minutes / 100)

SELECT  [Hours] = CAST(FLOOR(SummedMinutes / 60) AS FLOAT),
        [Minutes] = SummedMinutes % 60,
        OddFormat = CAST(FLOOR(SummedMinutes / 60) AS FLOAT) + (SummedMinutes % 60 / 100)
FROM    (   SELECT  SummedMinutes = SUM((FLOOR(n) * 60) + (n - FLOOR(n)) * 100)
            FROM    (VALUES (3.4), (1.3), (4.2)) t (N)
        ) AS t;

Example on SQL Fiddle

GarethD
  • 68,045
  • 10
  • 83
  • 123
  • I am curious as to why an answer that both correctly answers the question asked, and suggests an alternative method that would be better is *not useful* - Always happy to be proved wrong if the down voter cares to comment? – GarethD Nov 12 '14 at 10:04
0

Try this query to sum up hour and minutes:

 DECLARE @Result AS INT

 SELECT @Result = SUM(SubString(CAST(CAST(TOTALHOUR AS DECIMAL(10,2)) 
     AS VARCHAR(10)), 0, Charindex('.', CAST(CAST(TOTALHOUR AS DECIMAL(10,2)) 
     AS VARCHAR(10)))) * 60 + SubString(CAST(CAST(TOTALHOUR AS DECIMAL(10,2)) 
     AS VARCHAR(10)), Charindex('.', CAST(CAST(TOTALHOUR AS DECIMAL(10,2)) 
     AS VARCHAR(10))) + 1, len(CAST(CAST(TOTALHOUR AS DECIMAL(10,2)) 
     AS VARCHAR(10)))))
    FROM WORKDONE 
    WHERE userid = 3

SELECT @Result, CAST(@Result / 60 
       AS VARCHAR(10)) + ':' + CAST(@Result % 60 
       AS VARCHAR(10)) 
       AS ExpectedResult 

ExpectedResult = 9:30

Veera
  • 3,412
  • 2
  • 14
  • 27
0

This should work :

SELECT  sum(CAST(TotalHours as int))
        + sum(cast(Parsename(cast((TotalHours) as decimal(10,2)),1) as int))/60 
        + (sum(cast(Parsename(cast((TotalHours) as decimal(10,2)),1) as int))%60) *0.01
FROM   workdone
WHERE  userid = 3

sql fiddle

Deep
  • 3,162
  • 1
  • 12
  • 21
-2

You can use this kind of regexp to seperate digits and their deciamls and you can achieve the result. Below is the sample and you need to apply this for all rows and sum it up

 select (regexp_substr('4.2','[[:digit:]]',1)*60 + 
         replace(regexp_substr('4.2','\.[[:digit:]]'),'.')*10)/60 
  from dual;
Saravana Kumar
  • 3,669
  • 5
  • 15
  • 35
arunb2w
  • 1,196
  • 9
  • 28