I don't understand fully how can I use the to_char function to convert a number to a string with the appropriate format model.
The actual number has this type of format:
Uses comma as decimal separator
Always 5 decimal numbers
The integer numbers can up to 6 (potentially can be infinite, but for now they were never more than 6)
The number can be positive or negative
The number can begin with a 0
I've tried to use the to_char but I am not able to achieve a result that works with all the conditions
Some examples of how the output should be are
0,00235 or 156,45623 or -0,0235 or -156,45623
Keep in mind that you are transforming a number into a string. The number does not have any sense of "," or "." or anything--it is a number.
The trick is to get the TO_CHAR function to convert the internal number to the string representation that you want.
There are a few problems to worry about: getting the radix point (decimal) correct and dealing with padding.
Here is a working example:
SELECT to_char(0.00235,'FM99999999999999990D99999', 'NLS_NUMERIC_CHARACTERS = '',.''') FROM DUAL;
0,00235
SELECT to_char(156.45823,'FM99999999999999990D99999', 'NLS_NUMERIC_CHARACTERS = '',.''') FROM DUAL;
156,45823
SELECT to_char(-0.0235,'FM99999999999999990D99999', 'NLS_NUMERIC_CHARACTERS = '',.''') FROM DUAL;
-0,0235
SELECT to_char(-156.45623,'FM99999999999999990D99999', 'NLS_NUMERIC_CHARACTERS = '',.''') FROM DUAL;
-156,45623
SELECT to_char(123456789.45623,'FM99999999999999990D99999', 'NLS_NUMERIC_CHARACTERS = '',.''') FROM DUAL;
123456789,45623
The relevant parts of the mask:
FMis used to trim leading and trailing blanks that Oracle normally uses to pad out numbers.
D is the radix point, depending on your NLS settings.
NLS_NUMERIC_CHARACTERS ... is an override of your local NLS settings--this might not be necessary if your locale uses a comma for the decimal, but it is a way you can force this behavior in a database with, say, North American settings.
Shamelessly stolen from this post from #Vadzim.
You should be able to get the format you're looking for by using this pattern:
rtrim(to_char(num, 'FM999999999999990.99'), '.')
https://rextester.com/QRSD48676
SELECT rtrim(to_char('0,00235', 'FM999999999999990.99999'), '.') FROM DUAL\\
SELECT rtrim(to_char('156,45623', 'FM999999999999990.99999'), '.') FROM DUAL\\
SELECT rtrim(to_char('-0,0235', 'FM999999999999990.99999'), '.') FROM DUAL\\
SELECT rtrim(to_char('-156,45623', 'FM999999999999990.99999'), '.') FROM DUAL\\
Results:
0.00235
156.45623
-0.0235
-156.45623
Related
I'm using Oracle Database version 12.1.0.2.0. I'm running a query that returns integers that is actually a dollar amount:
SELECT value AS "Valuation" FROM estimates;
Result:
Instead, I would like to show:
$115,508
$38,150
$92,832
$116,222
How can I convert the integers into dollar $ format?
Use the TO_CHAR function:
TO_CHAR(SOME_NUMBER, '$999,999,999,999,999')
db<>fiddle here
Use to_char with extended parameters format and nlsparam: TO_CHAR (number)
and Number Format Models:
You can specify currency with NLS_CURRENCY and "Group symbol" (NLS_NUMERIC_CHARACTERS('dg'))
SELECT
to_char(
value
,'L999g999'
,q'[
NLS_NUMERIC_CHARACTERS = '.,'
NLS_CURRENCY = '$'
]') AS "Valuation"
FROM estimates;
DBFiddle
Results:
Valuation
$11,234
$104
$321,349
$2,837
NB: It's not necessary to specify extra NLS parameters if they correctly set on session level! So it will be much more agile and users will be able to use own session settings.
Can get rid of the left spaces if you really want that:
SQL> SELECT ltrim(to_char(value,'$999,999')) AS "Valuation" FROM estimates;
Valuation
---------
$115,508
$38,150
$92,832
$116,222
Bobby
select to_number(replace(nvl('-100,000',0),'',','),'999,999,999.99')from dual;
... produces the output: 100000
Now I use the same expression in my procedure with table column:
select to_number(replace(nvl(TABLEA.VOLUME,0),'',','),'999,999,999.99')from TABLEA;
... and get the output: INVALID NUMBER
Column VOLUME in TABLEA is of type VARCHAR2.
Most certainly the contents of column VOLUME are stored as strings without the grouping character ( , ). Thus the strings violate the format in the conversion with to_number.
In addition, the argument order in REPLACE makes no sense.
Finally, you want to swap the calls to NVL and REPLACE.
So - assuming that you want to parse numbers with 2 fractional digits given as strings - use the following:
select to_number ( nvl ( replace (TABLEA.VOLUME, ',', ''), 0), '999999999.99') from TABLEA;
Seems you want to convert the string values to money format.
First, consider replace as you did by switching '' and ',' parameters in the argument order to remove the commas, and making suitable for numeric conversion as :
to_number(replace(nvl(str,0),',','')),
and then apply the money format as :
with tableA as
(
select '-100,000' as volume
from dual
)
select to_char(
to_number(replace(nvl(volume,0),',',''))
,'fm999G999G990D00','NLS_NUMERIC_CHARACTERS = ''.,''')
as Money
from tableA;
MONEY
-----------
-100,000.00
Depending on the currency displaying style the order of dot and comma can be switched as
'NLS_NUMERIC_CHARACTERS = '',.''' to display the money as -100.000,00.
P.S. first of all, you need to make sure all the data for volume column can be casted to number to be able to use to_number() conversion.
Demo
I need to replace comma with point and then i need my value to be a number.
So i wrote this:
select replace('12345,6789', ',' , '.') from dual --it works fine
but then I want to convert to_number that value and I get the error:
"invalid number"
The to_number() function uses the session's NLS_NUMERIC_CHARACTERS setting to decide how to interpret commas and periods. If you know your string will always have a comma as decimal separator you can override that as part of the call, using the optional third argument; although that does mean you have to specify the format model:
select to_number('12345,6789', '9999999999D9999', 'NLS_NUMERIC_CHARACTERS='',.''')
from dual;
TO_NUMBER('12345,6789','9999999999D9999
---------------------------------------
12345.6789
You don't need a separate replace() step.
You can also change the session's setting with ALTER SESSION SET NLS_NUMERIC_CHARACTERS=',.';, but you may not be able to control the setting in every client that has to run your code.
The decimal separator is defined in your locale. Here it looks like it is ,. So you need not to do the replacement before converting your string:
select to_number('12345.6789') from dual --should work already
Or change your locale:
alter session set NLS_NUMERIC_CHARACTERS= '.,';
select to_number('123'||'.'||'456') from dual;
select to_number(replace('12345,6789', ',' , '.')) from dual
I have a number for example 39.46
and i want it to convert in ,format i.e it should look like 39,46 in SQL
is there any function to convert decimal amount in , separated format ?
There is a NLS setting NLS_NUMERIC_CHARACTERS, where you can set "," as decimal separator and "." to separate thousands. They are typically automatically set when you set your locale. You obviously use an English locale.
See here.
This assumes you have actual numbers in your DB and not strings which look like numbers. For strings you may want to use sting conversion operations as described by Thomas G.
Below I demonstrate how to use the number format and the nls_numeric_characters parameter, both for a numeric input and a string input. Notice the d (or D) in the format model, it says "use whatever the appropriate decimal separator is."
SQL> select to_char(93.23, '999d99', 'nls_numeric_characters='',.''') from dual;
TO_CHAR
-------
93,23
1 row selected.
Elapsed: 00:00:00.14
SQL> select to_char(to_number('93.23'), '999d99', 'nls_numeric_characters='',.''')
from dual;
TO_CHAR
-------
93,23
1 row selected.
I use the TO_CHAR function to format number from 0001 to 9999, and to fit the column size (VARCHAR2(4)) where the value is inserted (even if value is > 9999).
I use the function like this:
TO_CHAR(n, 'FM0000')
Examples that work:
SELECT TO_CHAR(1, 'FM0000') FROM DUAL;
Result: 0001
SELECT TO_CHAR(1234, 'FM0000') FROM DUAL;
Result: 1234
But when I test with a value greater than 9999, I get an extra character:
SELECT TO_CHAR(12345, 'FM0000') FROM DUAL;
Result: #####
SELECT TO_CHAR(123456, 'FM0000') FROM DUAL;
Result: #####
For information, the result I expected was #### (on 4 chars).
To sum up:
When the value to convert corresponds to the expected size (4), the converted value has the same length (4)
When the value to convert is longer than the expected size (5 or more), the converted value has one more character than the expected length (5).
How to explain this ?
I didn't found explanation in the Oracle documentation here https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i170559
I tried on several Oracle version (9, 10, 11) and the result is the same.
The workaround I found is to truncate the result with RPAD() function RPAD(TO_CHAR(n,'FM0000'), 4) but I need to understand why the TO_CHAR function is not enough.
Your format model still has to allow for the sign of the value. There is no way to indicate to TO_CHAR() that it can never be negative (if that is in fact the case for your values). Even with a 4-digit number the formatting allows allows for five characters, as you can see from the column heading:
SQL> SELECT TO_CHAR(1234, 'FM0000') FROM DUAL;
TO_CH
-----
1234
Notice the column heading is TO_CH, which is five characters, not four. If you have a negative number (as Florin suggested) you need that extra space:
SQL> SELECT TO_CHAR(-1234, 'FM0000') FROM DUAL;
TO_CH
-----
-1234
Without the FM modifier you get a leading space in the returned string for positive values, so LENGTH(TO_CHAR(1234, '0000')) is 5 but LENGTH(TO_CHAR(1234, 'FM0000')) is 4, because the leading space (which normally makes the values in the column right-justified) is suppressed. With a negative value the length of the returned string is 5 either way. The format model determines that the returned data type is varchar2(5) to allow for the sign, even if you know there will never be negative values - there isn't any way for the format model to reflect that.
You can see it with positive values too if you force the sign to be shown:
SQL> SELECT TO_CHAR(1234, 'FMS0000') FROM DUAL;
TO_CH
-----
+1234
There isn't anything you can do about that in the TO_CHAR call. As an alternative to your RPAD workaround, you could use SUBSTR to only get the last four characters of the formatted string:
SQL> SELECT SUBSTR(TO_CHAR(12345, 'FM0000'), -4) FROM DUAL
SUBSTR(TO_CHAR(1
----------------
####
But if you do have negative values you'd lose the sign:
SQL> SELECT SUBSTR(TO_CHAR(-1234, 'FM0000'), -4) FROM DUAL
SUBSTR(TO_CHAR(-
----------------
1234
With your RPAD you keep the sign but lose the fourth significant digit:
SQL> SELECT RPAD(TO_CHAR(-1234, 'FM0000'), 4) FROM DUAL
RPAD(TO_CHAR(-12
----------------
-123
which also isn't good. You may not have to deal with negative numbers; but if you're dealing with number larger than you expect (i.e. you get a number >= 10000 when you're expecting only <= 9999) then I'm not sure you can be certain you won't see an (invalid?) negative number at some point too. This seems to be a data problem rather than a formatting problem, on some level anyway.
Based on your comment to Ollie, another approach which might be more explicit and obvious to future maintainers of the code is to spell it out in a CASE:
SELECT CASE WHEN n BETWEEN 0 AND 9999 THEN TO_CHAR(n, 'FM0000') ELSE '####' END FROM DUAL
Which would also allow you to leave the string column null or use some other magic value rather than ####, if you wanted to.
And another way to trim the value, which may also be clearer, is with CAST:
SQL> SELECT CAST(TO_CHAR(12345, 'FM0000') AS VARCHAR2(4)) FROM DUAL;
CAST
----
####