Values are not displaying with leading zero in oracle - sql

I have a table where i have data with leading zeros for a column(number datatype). When i try to query the column in apex - SQL Workshop, it is not displaying the leading zero. So i need to manually convert to display value with leading zeros. But there is a problem while converting.
If i format explicitly using to_char then it is affecting the normal value.
For example
select to_char(colA,'0.99') from tab1
will give me 0.87 when value is .87 but we do have values without decimal also. in that case it will give me ###. Basically i want to display value as it is(but add 0 if value is starting with decimal). It should not add trailing zero also.Is there any way to achieve this? For example, below will give 661.00. But it should not give. If it whole number, it should display the same value.
select to_char(661,'999G999G999G999G990D00MI') from dual

You can get close with a mask like 'FM999999990D9999', with an appropriate number of 9s each side of the decimal to cover all values you might have.
with tab1 (cola) as (
select 0.87 from dual
union select 661 from dual
union select 661.87 res from dual
union select 1.5 res from dual
)
select cola, to_char(cola, 'FM999999990D9999')
from tab1;
COLA TO_CHAR(COLA,'F
---------- ---------------
.87 0.87
1.5 1.5
661 661.
661.87 661.87
The FM removes trailing zeros and leading spaces (including a nominal space for a +/- sign).
To get rid of the trailing decimal marker too you need to trim it off:
with tab1 (cola) as (
select 0.87 from dual
union select 661 from dual
union select 661.87 res from dual
union select 1.5 res from dual
)
select cola, rtrim(to_char(cola, 'FM999999990D9999'), to_char(0, 'FMD'))
from tab1;
I've stuck with D in both parts of that; you could use a fixed . in both so you don't need the second to_char() call to convert that, but you may want it to be controlled by the session - either way it needs to be consistent.
If you don't know how many 9s you need to include, you could generate a bespoke format mask for every number, based on how many digits there are before and after the decimal separator:
with tab1 (cola) as (
select 0.87 from dual
union all select 661 from dual
union all select 661.87 res from dual
union all select 1.5 res from dual
union all select 0.00045354543 from dual
)
select cola,
'FM' || lpad('0', length(trunc(cola)), '9')
|| case when trunc(cola) != cola
then 'D' || rpad('9', length(cola - trunc(cola)) - 1, '9')
end as format_mask,
to_char(cola,
'FM' || lpad('0', length(trunc(cola)), '9')
|| case when trunc(cola) != cola
then 'D' || rpad('9', length(cola - trunc(cola)) - 1, '9')
end) as result
from tab1;
COLA FORMAT_MASK RESULT
--------------- -------------------- --------------------
.87 FM0D99 0.87
661 FM990 661
661.87 FM990D99 661.87
1.5 FM0D9 1.5
.00045354543 FM0D99999999999 0.00045354543
This relies on implicit conversion but seems to work for positive, negative and zero. It doesn't need to trim the result because the decimal separator D is only included at all for non-integers.

Think also your format mask is wrong D99 should help:
SQL> with a as
2 ( select 1/100 nb, '0.01' res from dual
3 union select 20 nb, '20' res from dual
4 union select 444/100 nb, '4.44' res from dual
5 union select 120/100 nb, '1.2' res from dual)
6 select nb, to_char(nb,'999G990D99') t_c, res from a
NB T_C RES
,01 0,01 0.01
1,2 1,20 1.2
4,44 4,44 4.44
20 20,00 20

How about using a case statement in your query for the column in question?
Something like this:
select case
when INSTR(to_char(:test_no),'.') = 1
then replace(to_char(:test_no),'.','0.')
else to_char(:test_no)
end as 'test_no'
from dual

Related

TRIM Trailing Zeros

I know this is a relatively simple question, but I couldn't find anything with my keywords using Google.
I am referencing with a SQL (Oracle) to a column that has numbers like that:
100
12500
300
Now I need to remove the last 2 zeros.
This approach is not working:
Trim(TRAILING '00' FROM F0035.Nr) "Sequence",
Does anyone have any idea?
The result should be a column with numbers - not a text
See these two options:
SQL> with test (col) as
2 (select '100' from dual union all
3 select '12500' from dual union all
4 select '300' from dual
5 )
6 select col,
7 to_number(substr(col, 1, length(col) - 2)) result_1,
8 to_number(col) / 100 result_2
9 from test;
COL RESULT_1 RESULT_2
----- ---------- ----------
100 1 1
12500 125 125
300 3 3
SQL>
the first one removes the last two characters (from your sample data, it seems that they are always 00)
the second one divides that "number" by 100
You could do this:
SELECT regexp_replace(F0035.Nr, '^(.*)00$', '\1')
FROM F0035
You can easily tweak the regular expression if your requirements change subtly, such as removing more than 2 trailing zeros (e.g. ^(.*)00+), or other characters
with test (col) as (
select 10 from dual union all
select 100 from dual union all
select 1000 from dual union all
select 12500 from dual union all
select 125002 from dual union all
select 3000 from dual
)
select col,
case when substr(col, -2) = '00' then col/100 else col end newnum
from test;
If the column contains numbers, why are you using string operations?
If all values have two 00s as the end, then:
F0035.Nr / 100
If some do not, then use a case:
(case when mod(F0035.Nr, 100) = 0 then F0035.Nr / 100 else F0035.Nr end)
I don't recommend converting to a string to do numeric operations under most circumstances.
The following expression will strip off any number of zeroes from a number:
SELECT NR / POWER(10, LENGTH(REGEXP_SUBSTR(TO_CHAR(NR), '0*$')))
FROM F0035
db<>fiddle here

How to apply padding on the Decimal Values in Oracle?

I need help on applying padding on the Decimal values in Oracle.
E.g.:
-36693.76 should be displayed as -000036693.76
367.2 should be displayed as +000000367.20
Padding should be (9,2) and sign also should be displayed.
You can use to_char() with the appropriate format mask:
TO_CHAR(the_column,'S000000000.00')
The S indicates the position of the sign. The 0 indicates to display a 0 if no value is available for that digit (a 9 would display a blank)
The following:
with sample_data(the_column) as (
select 367.2 from dual
union all
select -36693.76 from dual
union all
select 1.234 from dual
union all
select 1.236 from dual
)
select TO_CHAR(the_column,'S000000000.00') as the_column
from sample_data;
returns:
THE_COLUMN
-------------
+000000367.20
-000036693.76
+000000001.23
+000000001.24
Note how 1.234 got rounded to 1.23 and 1.236 to 1.24
Here's your query.
with cte(num) AS(
select 367.2 from dual
union all
select -36693.76 from dual
)
select case when num < 0 then concat('-', TO_CHAR(num*-1,'000000000.00')) else concat('+', TO_CHAR(num,'000000000.00')) end
from cte
result:

Oracle SQL TO_CHAR variable length

I'd like to ask you with help with a TO_CHAR method in Oracle SQL.
TO_CHAR(Number_parameter,'9999D99','NLS_NUMERIC_CHARACTERS = ''. ''') vc_num,
Number_Parameter is coming in as a decimal number with usual values between 10.10 to 1999.99 (but not limited to them) I need to create a VARCHAR with the smallest representation of the value with at most 2 decimal points. My problem is that I have not found a mask that would satisfy my needs.
I need 200.99 as '200.99' but 10.1 as '10.1' while now I am getting ' 10.1 ' (with the white spaces, which I do not want) also 150 should translate to '150' and not '150.00'
Can you help me please?
As #a_horse_with_no_name suggested, using the FM format modifier will get rid of the leading space, and will also remove trailing zeros. But it's not quite there:
with t(number_parameter) as (
select 200.99 from dual
union all select 10.10 from dual
union all select 150.00 from dual
)
select to_char(number_parameter,'FM9999D99','NLS_NUMERIC_CHARACTERS = ''. ''') vc_num
from t;
VC_NUM
--------
200.99
10.1
150.
To get rid fo the trailing period you'll need to trim that:
with t(number_parameter) as (
select 200.99 from dual
union all select 10.10 from dual
union all select 150.00 from dual
)
select rtrim(
to_char(number_parameter,'FM9999D99','NLS_NUMERIC_CHARACTERS = ''. '''),
'.') vc_num
from t;
VC_NUM
--------
200.99
10.1
150
Or as you discovered yourself, the TM text minimum format model also works for your data:
with t(number_parameter) as (
select 200.99 from dual
union all select 10.10 from dual
union all select 150.00 from dual
)
select to_char(number_parameter,'TM') vc_num
from t;
VC_NUM
----------------------------------------------------------------
200.99
10.1
150

How to return an expected value with decimal places using dual table on Oracle SQL?

I'm currently trying to force a number to have a two decimal character on the output no need to round,
if there is a decimal value exist I just need to have 2 decimal places
Example:
26 will return 26.00
26.1 will return 26.10
26.20 will return 26.20
26.09090909 will return 26.09
26.23090909 will return 26.23
0.14000 will return 0.14
0.04000 will return 0.04
0 will return 0.00
but the in-house language that I'm currently using has a very limited function to do it (possible but it will take a lot of lines).
but I am able to do a query on Oracle SQL. Now I would like to ask if it is possible to query using the dual table on SQL.
My plan is to pass the value to variable and this variable will be use on my SQL command and SQL will return my expected value.
Thanks in advance.
You simply need format mask:
select to_char(yourVariable, 'fm9999999990.00') from dual
According to Boneist's suggestion, 'fm' in format mask prevents the creation of blanks, while '0' digits are useful to always write the digit:
with test(num) as
(
select 26 from dual union all
select 26.1 from dual union all
select 26.20 from dual union all
select 26.09090909 from dual union all
select 26.23090909 from dual union all
select 0.14000 from dual union all
select 0.04000 from dual union all
select 0 from dual
)
select num, to_char(num, 'fm9999999990.00')
from test
You can try like this:
SELECT TO_CHAR(26, '99.99') AS X FROM DUAL
For numbers less than 1 in which you need to have 0 explicitly you have to provide it like
SELECT TO_CHAR(0.14000,'0.99') FROM DUAL;
So you can use it like
CASE WHEN myNum > 0 and myNum < 1
then TO_CHAR(myNum,'0.99') else
TO_CHAR(myNum, '99.99')
or more simplified(as suggested in comments):
select to_char(num, 'fm9999999990.00') from dual

Filter the rows with number only data in a column SQL

I am trying to SELECT rows in a table, by applying a filter condition of identifying number only columns. It is a report only query, so we least bother the performance, as we dont have the privilege to compile a PL/SQL am unable to check by TO_NUMBER() and return if it is numeric or not.
I have to achieve it in SQL. Also the column is having the values like this, which have to be treated as Numbers.
-1.0
-0.1
-.1
+1,2034.89
+00000
1023
After ground breaking research, I wrote this.(Hard time)
WITH dummy_data AS
( SELECT '-1.0' AS txt FROM dual
UNION ALL
SELECT '+0.1' FROM dual
UNION ALL
SELECT '-.1' FROM dual
UNION ALL
SELECT '+1,2034.89.00' FROM dual
UNION ALL
SELECT '+1,2034.89' FROM dual
UNION ALL
SELECT 'Deva +21' FROM dual
UNION ALL
SELECT '1+1' FROM dual
UNION ALL
SELECT '1023' FROM dual
)
SELECT dummy_data.*,
REGEXP_COUNT(txt,'.')
FROM dummy_data
WHERE REGEXP_LIKE (TRANSLATE(TRIM(txt),'+,-.','0000'),'^[-+]*[[:digit:]]');
I got this.
TXT REGEXP_COUNT(TXT,'.')
------------- ---------------------
-1.0 4
+0.1 4
-.1 3
+1,2034.89.00 13 /* Should not be returned */
+1,2034.89 10
1+1 3 /* Should not be returned */
1023 4
7 rows selected.
Now terribly confused with 2 Questions.
1) I get +1,2034.89.00 too in result, I should eliminate it. (means, two decimal points) Not just decimal point, double in every other special character (-+,) should be eliminated)
2) To make it uglier, planned to do a REGEXP_COUNT('.') <= 1. But it is not returning my expectation, while selecting it, I see strange values returned.
Can someone help me to frame the REGEXP for the avoiding the double occurences of ('.','+','-')
The following expression works for everything, except the commas:
'^[-+]*[0-9,]*[.]*[0-9]+$'
You can check for bad comma placement with additional checks like:
not regexp_like(txt, '[-+]*,$') and not regexp_like(txt, [',,'])
First you remove plus and minus with translate and then you wonder why their position is not considered? :-)
This should work:
WITH dummy_data AS
( SELECT '-1.0' AS txt FROM dual
UNION ALL
SELECT '+0.1' FROM dual
UNION ALL
SELECT '-.1' FROM dual
UNION ALL
SELECT '+12034.89.00' FROM dual -- invalid: duplicate decimal separator
UNION ALL
SELECT '+1,2034.89' FROM dual -- invalid: thousand separator placement
UNION ALL
SELECT 'Deva +21' FROM dual -- invalid: letters
UNION ALL
SELECT '1+1' FROM dual -- invalid: plus sign placement
UNION ALL
SELECT '1023' FROM dual
UNION ALL
SELECT '1.023,88' FROM dual -- invalid: decimal/thousand separators mixed up
UNION ALL
SELECT '1,234' FROM dual
UNION ALL
SELECT '+1,234.56' FROM dual
UNION ALL
SELECT '-123' FROM dual
UNION ALL
SELECT '+123,0000' FROM dual -- invalid: thousand separator placement
UNION ALL
SELECT '+234.' FROM dual -- invalid: decimal separator not followed by digits
UNION ALL
SELECT '12345,678' FROM dual -- invalid: missing thousand separator
UNION ALL
SELECT '+' FROM dual -- invalid: digits missing
UNION ALL
SELECT '.' FROM dual -- invalid: digits missing
)
select * from dummy_data
where regexp_like(txt, '[[:digit:]]') and
(
regexp_like(txt, '^[-+]{0,1}([[:digit:]]){0,3}(\,([[:digit:]]){0,3})*(\.[[:digit:]]+){0,1}$')
or
regexp_like(txt, '^[-+]{0,1}[[:digit:]]*(\.[[:digit:]]+){0,1}$')
);
You see, you need three regular expressions; one to guarantee that there is at least one digit in the string, one for numbers with thousand separators, and one for numbers without.
With thousand separators: txt may start with one plus or minus sign, then there may be up to three digits. These may be followed by a thousand separator plus three digits several times. Then there may be a decimal separator with at least one following number.
Without thousand separators: txt may start with one plus or minus sign, then there may be digits. Then there may be a decimal separator with at least one following number.
I hope I haven't overlooked anything.
I just tried to correct the mistakes of you and made the SQL simple as possible. But not neat!
WITH dummy_data AS
( SELECT '-1.0' AS txt FROM dual
UNION ALL
SELECT '+.0' FROM dual
UNION ALL
SELECT '-.1' FROM dual
UNION ALL
SELECT '+1,2034.89.0' FROM dual
UNION ALL
SELECT '+1,2034.89' FROM dual
UNION ALL
SELECT 'Deva +21' FROM dual
UNION ALL
SELECT 'DeVA 234 Deva' FROM dual
UNION ALL
SELECT '1023' FROM dual
)
SELECT to_number(REPLACE(txt,',')),
REGEXP_COUNT(txt,'.')
FROM dummy_data
WHERE REGEXP_LIKE (txt,'^[-+]*')
AND NOT REGEXP_LIKE (TRANSLATE(txt,'+,-.','0000'),'[^[:digit:]]')
AND REGEXP_COUNT(txt,',') <= 1
AND REGEXP_COUNT(txt,'\+') <= 1
AND REGEXP_COUNT(txt,'\-') <= 1
AND REGEXP_COUNT(txt,'\.') <= 1;