Converting a mixed fraction to a float number in Netezza - sql

I have a field with numbers stored as text in 3 formats:
xx. (example: 31.)
xx.x (example: 31.2)
xx x/x (example: 31 2/7)
For the final result, I need all numbers to be in decimal format (that is, xx.x).
Converting the first two formats into decimals is fairly simple, but I haven't quite figured out how to convert the last case, as a simple CAST function doesn't work. I've used the INSTR function to isolate all the fractional cases of these numbers, but I don't know where to go from there. I've looked at other examples but some of the functions referenced (like SUBSTRING_INDEX) don't exist in Netezza.

I think #Niederee has the solution from brute force, but I'd use the sql extensions toolkit.
create temporary table fractions (
val nvarchar(64)
) distribute on random;
insert into fractions values ('2.');
insert into fractions values ('2.3');
insert into fractions values ('31 2/7');
insert into fractions values('2 0/8');
insert into fractions values('516 56/537');
select
val
,case
when regexp_like(val,'^[\d\.]+$') then val::numeric(20,10) --Cast it if we can.
when regexp_like(val,'^[\d\.\s\/]+$')
then regexp_extract(val,'\d+',1,1)::numeric(20,10) --Whole.
+ (
regexp_extract(val,'\d+',1,2)::numeric(20,10) --Numerator.
/ regexp_extract(val,'\d+',1,3)::numeric(20,10) --Denominator.
)
else null
end
from
fractions;

Try the following:
create temp table so_test (
txt_val varchar(100)
);
insert into so_test values ('31.');
insert into so_test values ('31.2');
insert into so_test values ('31 2/7');
select txt_val
, cast(decode(substr(txt_val,1,instr(txt_val,' ')),'',txt_val,substr(txt_val,1,instr(txt_val,' '))) as numeric(18,2)) as root
,cast(substr(txt_val,instr(txt_val,' ')+1,length(txt_val)-instr(txt_val,'/')) as numeric(18,2))
/cast(substr(txt_val,instr(txt_val,'/')+1,length(txt_val)) as numeric(18,2)) as fraction
,cast(root + case when fraction = 1 then 0 else fraction end as numeric(3,1)) as num_val
from so_test

Thanks for the help everyone. I forgot to close this out, I actually figured out a way to do it:
select
case when instr(num,'/') > 0 then
cast(substr(num,1,2) as float)
+ (cast(substr(num,4,1) as float)/cast(substr(num,6,1) as float))
when instr(num,'.') > 0 then cast(substr(num,1,4) as float)
else cast(num as float)
end as float_num

Related

Removing trailing zeros in case statement

I've been trying to remove the trailing zeros from a column of a table. It works well when I try to remove the zeros from the column. However, when I use it with a case statement (to remove the zeros when a flag is turned on, and to keep them when a flag is turned off) it doesn't work properly. It doesn't recognize the flag. For example, I've hard coded the column as a constant value; while 1=0 (false), it is retrieving the value removing the zeros. It should be true in the else statement.
SELECT CASE WHEN 1=0 THEN cast(CAST(123.45000 AS decimal(6,2)) as float)
ELSE
'123.456700'
END
SELECT CASE WHEN 1=0 THEN CONVERT(DOUBLE PRECISION, 123.456700)
ELSE
'123.456700'
END
Why is this happening? Can anyone help me with this?
The above is well explained by #Tim below.
However, it doesn't remove the zeros at all in a table. It doesn't recognize the flag at all. Here is an example:
CREATE TABLE #tablea
(item CHAR(2), name VARCHAR(10), amount DECIMAL(9,2))
INSERT INTO #tablea
VALUES ('AB', 'D1', 1.10),
('AB', 'D2', 1.00),
('AB', 'D3', 0.90),
('AB', 'D4', 0.09)
DECLARE #flag INT = 1
SELECT CASE WHEN #flag = 1
THEN CAST(CAST(amount AS DECIMAL(6,2)) AS VARCHAR(max))
ELSE amount END
FROM #tablea
As #JNevill commented, what is happening here is that an implicit conversion is happening in the ELSE branch of your CASE expression, converting the string literal into a float, thereby removing the trailing zeroes when it gets printed. One option would be to cast the IF portion to VARCHAR:
SELECT
CASE WHEN 1=0
THEN CAST(CAST(123.45000 AS decimal(6,2)) AS varchar(max)) -- a string
ELSE '123.456700' END -- also a string
Demo
Note that in certain versions of SQL (other than yours) your CASE expression would not even run without error. It just so happens that a silent conversion is taking place here.
You can't remove trailing zeroes from a decimal data type. The decimal/numeric data types are fixed point data type:
Numeric data types that have fixed precision and scale. Decimal and numeric are synonyms and can be used interchangeably.
This means that the decimal point is in a fixed position within the stored number, unlike float and read which are floating point data types - so for a decimal(9,2) there will always be two digits to the right of the decimal point - and for numeric(5,3) where will always be three digits to the left of the decimal point.
If precision is not very important, you can convert to float - but you should be aware that unlike decimal, float is an approximate data type.
Please note that you would still have to convert both branches of the case statement to a varhcar otherwise SQL Server will implicitly convert both branches to float and it will look like the flag is being ignored.
DECLARE #flag INT = 1
SELECT
CASE WHEN #flag = 1
THEN CAST(CAST(amount AS float) as varchar(30))
ELSE CAST(amount as varchar(30))
END As [Remove trailing zeros],
-- This is to show the opposite branch
CASE WHEN #flag = 0
THEN CAST(CAST(amount AS float) as varchar(30))
ELSE CAST(amount as varchar(30))
END As [Include trailing zeros]
FROM #tablea
Results:
Remove trailing zeros Include trailing zeros
1.1 1.10
1 1.00
0.9 0.90
0.09 0.09
#Tim, thanks. It works in the demo you showed. But it doesn't remove the zeros at all in a table. It doesn't recognize the flag at all. Here is an example:
CREATE TABLE #tablea
(item CHAR(2), name VARCHAR(10), amount DECIMAL(9,2))
INSERT INTO #tablea
VALUES ('AB', 'D1', 1.10),
('AB', 'D2', 1.00),
('AB', 'D3', 0.90),
('AB', 'D4', 0.09)
DECLARE #flag INT = 1
SELECT CASE WHEN #flag = 1
THEN CAST(CAST(amount AS DECIMAL(6,2)) AS VARCHAR(max))
ELSE amount END
FROM #tablea

Variable precision in a column in SQL

I have a column which consists of three different types of numbers:
Type 1 has no digits after decimal point like 5, 17, etc.
Type 2 has one digit after decimal point like 27.5, 11.8, etc.
Type 3 has 2 digits after decimal points like 227.64, 35.77, etc.
I want the Type 1 numbers to have a 0 after decimal point so that they become 22.0, 11.0 and so on while the Type 2 and Type 3 numbers remain unaffected.
Can be done by pushing value into a string.
DECLARE #table AS TABLE (myValue FLOAT)
INSERT INTO #table
(myValue)
VALUES (5),
(17),
(27.5),
(11.8),
(227.64),
(35.77)
SELECT CASE WHEN CAST(myValue AS VARCHAR(20)) LIKE '%.%' THEN CAST(myValue AS VARCHAR(20))
ELSE CAST(myValue AS VARCHAR(20)) + '.0'
END
FROM #table
This is a poor solution at best. Your better maintaining your data in its original format and then handling your formatting in the presentation layer as already stated by Ankit. I know its not always possible, but the data place is not really the place to do this.
What is the data type of the column?
Try:
SELECT
CASE
WHEN LEN(RIGHT([MyColumn], CHARINDEX('.', REVERSE([MyColumn])))) >= 3
THEN [MyColumn]
ELSE CAST(CAST([MyColumn] AS NUMERIC(8,1)) AS NVARCHAR(10))
END AS [MyColumn]
FROM [MyTable]

SQL How to convert number to text with minimum decimal places (dynamic number of decimal places) in SQL

In an SQL query, I want to convert numeric value to text with minimum no. of decimal places, example if the number is 2.50, then I want output as 2.5; if number is 3, then I want output as 3; if number is 18.75, I want output as 18.75, etc.
How can I achieve this?
EDIT 1:
To give more background, I am dividing 2 numeric values, and want the result in text with minimum required decimal places.
Thanks.
In SQL 2012 and above you can write
SELECT FORMAT(15.0/4.0 , '#.########' )
It uses FORMAT function which uses .NET String.Format functionality.
If want to get 2 decimals for division values, use this
Select case when right(cast ( x/y as decimal(18,2)),1) = 0
then left (cast ( x/y as decimal(18,2)),3)
else cast ( x/y as decimal(18,2)) end ReqOutput
This should do the trick...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
SomeNumber DECIMAL(9,7) NOT NULL
);
INSERT #TestData (SomeNumber) VALUES
(1.2345670), (1), (99.00100), (5.55);
SELECT
td.SomeNumber,
REVERSE(STUFF(rcv.RevCastVarchar, 1, PATINDEX('%[^0.]%', rcv.RevCastVarchar) - 1, ''))
FROM
#TestData td
CROSS APPLY ( VALUES (REVERSE(CAST(td.SomeNumber AS VARCHAR(10)))) ) rcv (RevCastVarchar);
HTH,
Jason

SQL Real number convert to Ft & In

enter code hereI asked a question back in May about how to convert a number from a table that inches, such as 300.9 to a Ft' In" display. I got two very good answers...
CONVERT(VARCHAR(20),finlength /12) + '''' + CONVERT(VARCHAR(20),finlength %12)+'"' as FinishLen
replace(replace('<feet>'' <inches>', '<feet>', FinLength / 12), '<inches>', FinLength % 12) as FinishLen
Both worked well until I ran into a table that the inches are declared as "REAL" numbers. Now I ran into this error...
"The data types real and int are incompatible in the modulo operator."
How can I display that? I can't change the table declarations. Other users need that data as well.
Thanks and Kuddos for the great site.
Guess the full query might help, sorry.
SELECT TOP 1000 ProdWkYr
,Product
,Grade
,CONVERT(VARCHAR(20),finlength /12) + '''' + CONVERT(VARCHAR(20),finlength %12)+'"' as FinishLen
,BlmWeight
,BlmsNeeded
,BlmFootWgt
FROM NYS2MiscOrderInfo
where ProdWkYr = 3215
order by product, Grade
Just include a floor() in your expression like
-- -------------------------------------------------------------------
-- set-up some test data using a CTE:
WITH tst as ( SELECT 13.7 finlength UNION ALL SELECT 123 )
-- alternatively: generate a table [tst] with a single column [finlength]
-- -------------------------------------------------------------------
SELECT CONVERT(VARCHAR(20),FLOOR(finlength / 12)) + ''''
+ CONVERT(VARCHAR(20),finlength % 12)+'"' as FinishLen
FROM tst
-- results:
FinishLen
1'1.70"
10'3."
This will turn the first (ft) value into an integer while the second one (in) will still show all the digits after the decimal point.
UPDATE
When I ran the select from a #tmp table I got the same error as OP. I then modified and ended up with this:
It is as ugly as hell now, but at least it works now, see here SQL Demo:
create table #tst (finlength float);
INSERT INTO #tst VALUES (13.7),(123.),(300.9);
SELECT CONVERT(VARCHAR(20),FLOOR(finlength / 12)) + '''' -- ft
+CONVERT(VARCHAR(20),finlength-FLOOR(finlength) -- in: fractional part
+CAST(FLOOR(finlength) as int) %12)+'"' -- in: integer part
as FinishLen
FROM #tst
Please note: The formula will return reasonable results for positive values. For "negative distances" further changes are necessary. If similar output is required in different places then a UDF makes sense here. Something like:
CREATE FUNCTION ftinstr(#v float) RETURNS varchar(32) BEGIN
DECLARE #l int;
SELECT #l=FLOOR(ABS(#v));
RETURN CAST(SIGN(#v)*(#l/12) AS varchar(6))+''''
+CAST( ABS(#v)-#l+#l%12 AS varchar(20))+'"'
END
would do the trick, To be called like dbo.ftinstr( floatval ).
Maybe I can beautify it a little still ...

Remove only zero after decimal sql server 2012

Consider the following numbers.
7870.2
8220.0
I need to remove decimal points if the value ends with .0. If it ends with .2 then it should keep the value as it is.
I have used ceiling but it removes all the values after decimal.
How can I write a select query in which I can add some condition for this?
Generally speaking you should not do this in your dB. This is an app or reporting side operation. The dB is made to store and query information. It is not made to format/string manipulate information.
use right within a case statement and:
DECLARE #val decimal(5,1)
SET #val = 7870.0
Select
Case
When right(#val,1)<> '0' then
cast(#val as varchar)
else
cast(cast(#val as int) as varchar)
End
output: 7870
EDIT: I could write :
Case
When right(#val,1)<> '0' then
#val
else
cast(#val as int) -- or floor(#val)
End
but because return type of case statement is the highest precedence type from the set of given types, so the output for second version is: 7870.0 not 7870, that's why I convert it to i.e varchar in when clauses, and it can be converted outside of case statement, I mean cast ((case when...then...else... end) as datatype)
Cast the number as a float, using float(24) to increase precision:
DECLARE #t table(number decimal(10,1))
INSERT #t values(7870.2),(8220.0)
SELECT cast(number as float(24))
FROM #t
Result:
7870,2
8220
Here below goes a sample:
declare #1 decimal(4,3)
select #1 = 2.9
select case when SUBSTRING (PARSENAME(#1,1), 1, 1) = 0 then FLOOR(#1) else #1 end
Change the #1 in the select statement with your database field name.
sqlfiddle
The solution seems to be simple:
SELECT CONVERT (FLOAT, PAYLOAD)