How to extract fractional digits of double - sql

I need to extact fractional part of double in sql, but without "0." For example:
number: 5.67
int: 5
fact: 67

In most databases, you can use something like this:
select cast((x - floor(x)) * 100 as int)
In SQL Server, you have other options. For instance, to get the fractional part, you can use %:
select (x % 1)
To get two digits:
select floor(100 * (x % 1)) -- or perhaps round()
or:
select (x * 100) % 100

SELECT 5.67 AS Doubles, CAST(5.67 AS INT) AS Fractional_Only,
PARSENAME(5.67,1) AS DECIMAL_ONLY

this will work in oracle:
select substr(to_char(5.67),instr(to_char(5.67),'.')+1) from dual;
check http://sqlfiddle.com/#!4/e2ac5e/1074
for mssql :
select substring(CONVERT(varchar, 25.65),CHARINDEX('.', CONVERT(varchar, 25.65))+1,5);
http://sqlfiddle.com/#!18/9eecb/41866
check the last one :
select substring(CONVERT(varchar, (15+15)/2.0),
CHARINDEX('.', CONVERT(varchar, (15+15)/2.0))+1,1);
http://sqlfiddle.com/#!18/9eecb/41875

Related

What's the difference between these 2 SQL query involving round() and ceiling ()?

SELECT ROUND(CEILING(36.3) / 4,2)
SELECT ROUND(37 / 4,2)
The first query returns 9.25. The second query returns 9.
Ceiling(36.3) would have returned 37. Why would there be such differences then?
The difference is due to the return type from operations. When you call Ceiling on any number or expression, the return type is of same type as the expression.
Let's look at the first one:
Ceiling(36.3) -> returns a decimal
This means that the division operation is also done on decimals which means you get a decimal result and thus could be rounded.
In the second statement, you are dividing 2 integers which would also result in a integer result (just the quotient). Thus the value will only be 9.
SELECT ROUND(CEILING(36.3) / 4,2) -- select round(decimal/int,int) => select round(decimal, int)
SELECT ROUND(37 / 4,2) -- select round(int/int,int) => select round(int, int)
You would get similar result when you do this:
SELECT ROUND((CEILING(36.3) / 4),2)
SELECT ROUND((cast(37 as decimal(10,2)) / 4),2)

SELECT SUM for time

I have a Table in SQL server with a column "Time" having data type as time(7). Need to call the sum of this column, and when I use the following statement, it returns result as integer only.
Eg. If total time is 1:30:00,I expect result as 1.5. But the code I use doesn't get me this, it get me result as 1. Please check if you have a solution.
The code I used is
SELECT SUM(DATEPART(ss,Time) + DATEPART(mi,Time)*60 + DATEPART(hh,Time)*3600)/3600 AS TotalTime FROM dbo.Table
SELECT (
DATEPART(hh,Time) +
DATEPART(mi,Time) / 60.0 +
DATEPART(ss,Time) / 3600.0
) AS TotalTime
FROM dbo.Table
Try below - you don't need sum() function here and in your case, it is showing 1 because your result is 5400/3600 which is 1 but you need to add a float value as you are expecting float result
SELECT (DATEPART(ss,'1:30:00') + DATEPART(mi,'1:30:00')*60 +
DATEPART(hh,'1:30:00')*3600)/3600.00
AS TotalTime FROM dbo.Table
Try this, you can change the datepart argument based on your needs here is the full list
SELECT SUM(CAST(DATEDIFF(MINUTE, '00:00:00', [Time]) as float)/60) AS TotalHours FROM [dbo].[Table]
When you divide some value by int type, the result will be also int (the fraction is just dropped). Therefore, you need to convert a divider of 3600 from int to decimal:
SELECT SUM(DATEPART(ss,Time) + DATEPART(mi,Time)*60 + DATEPART(hh,Time)*3600)/CONVERT(DECIMAL(16,4), 3600) AS TotalTime FROM dbo.Table
If you want the difference in decimal hours, then do the following:
Convert the time values to seconds.
Sum the seconds.
Divide by 60 * 60
So:
select sum(datediff(second, 0, v.t)) / (60.0 * 60)
from (values (convert(time, '00:10:01')),
(convert(time, '01:00:03'))
) v(t)
There is no reason to break the value in to component parts. That just seems unnecessarily complicated.

Converting hours into minutes in SQL

i'm trying to write a regular expression that will convert the hours into minutes.
Currently I have a value which give me the number of hours before the dot and the number of minutes after the dot, for example 6.10 is 6 hours and 10 minute.
Can i use a regular expression to look for the value before the dot and multiply by 60 (to get minutes) and then add the value after the dot (which is already in minutes)?
So as per the example used before, it would do:
(6 * 60) + 10
Thank you!
There's a STRTOK function to tokenize a string and then it's just:
select '12.34' as x,
cast(strtok(x,'.',1) as int) * 60 + cast(strtok(x,'.',2) as int)
If your value "6.10" is stored as a string, convert it to a number first:
SET #Input = CAST(#InputString AS FLOAT)
Then, use Modulus and Floor.
Total Minutes = The fractional part * 100 + the whole number part * 60.
So if your value 6.10 is contained in a variable named #Input, then you can get the value you wish with
SET #Output = (#Input % 1) * 100 + FLOOR(#Input, 0) * 60
If it's in a table then something more like this would be appropriate:
SELECT (Input % 1) * 100 + FLOOR(Input, 0) * 60 Output
FROM Table
The above only works if minutes are zero padded, e.g. 6 hours five minutes = 6.05. If you instead represent minutes without padding (6 hours five minutes = 6.5) then use the method that under suggests.
Regular expressions is probably an overkill for such a simple string manipulation. All you need is INDEX function to get the location of the dot and SUBSTR function to get hours and minutes.
Dot position:
select INDEX([yourstring], '.')
Hours (before the dot):
select SUBSTR([yourstring], 1, INDEX([yourstring], '.') - 1)
Minutes (after the dot):
select SUBSTR([yourstring], INDEX([yourstring], '.') + 1)

Comparing dates as strings and integers in Teradata

My task is to compare dates in two different tables in a Teradata database. In table group_1 dates are BIGINT, for instance 20,141,106 and in table group_2 dates are VARCHAR(30), for instance, 11/12/2015.
What would be the best way to do a conversion and compare them, namely,
select * from ....
where date in group_1 = date in group_2?
Many thanks in advance.
Can you safely convert those columns to dates (no invalid dates)?
BIGINT -> DATE:
cast(col - 19000000 as date)
VARCHAR -> DATE:
to_date(col, 'dd/mm/yyyy') (or 'mm/dd/yyyy'?)
Otherwise:
BIGINT -> VARCHAR:
TRIM((col MOD 100) * 1000000 + (col/100 MOD 100) * 10000 + (col / 10000) (FORMAT '99/99/9999')) -- dmy
or
TRIM((col/100 MOD 100) * 1000000 + (col MOD 100) * 10000 + (col / 10000) (FORMAT '99/99/9999')) -- mdy
And next time, try to store data using the correct datatype or at least the same wrong type :-)
You should convert date types to date for comparisons and other operations.
For the integer:
select to_date(convert(bigintcol as varchar(255)), 'YYYYMMDD')
For the string:
select to_date(varcharcol, 'MM/DD/YYYY') -- or perhaps DD/MM/YYYY
You can then compare the dates directly.

Teradata SQL HHMM to HH:MM

On Teradata SQL I am trying to convert the duration 30 hours and 30 minutes given as '3030' to 1) 30:30 and 2) 30.5 . Or, in another example 3 hours and 15 minutes as 1) 3:10 and 3) 3.25
I can use mod and other arithmetic operations. However, is there a default way of doing this in Teradata SQL?
Every interval has a FORMAT
select format(interval '3:30' hour to minute)
returns
-h(1):mm
but I never found a way to change it :-(
Assuming that you input is a string:
cast(col as int) / 100 + to_number(col) mod 100 / 60 -- numeric result
trim(cast(col as int format 'Z(8)9:99')) -- string result
You can just insert the character:
select substr(val, 1, 2) || ':' substr(val, 3, 2)
Or, convert the values to integers:
select cast(substr(val, 1, 2) as decimal(10, 2)) + cast(substr(val, 3, 2) as decimal(10, 2))/60.0
EDIT:
If you want to convert them to a number, you can do:
select (cast(hhmm as int) / 100 + (cast(hhmm as int) mod 100) / 60.0
This will return a number.