Oracle cursor removes leading zero - oracle

I have a cursor which selects date from column with NUMBER type containg floating point numbers. Numbers like 4,3433 are returned properly while numbers smaller then 1 have removed leading zero.
For example number 0,4513 is returned as ,4513.
When I execute select used in the cursor on the database, numbers are formatted properly, with leading zeros.
This is how I loop over the recors returned by the cursor:
FOR c_data IN cursor_name(p_date) LOOP
...
END LOOP;
Any ideas why it works that way?
Thank you in advance.

You're confusing number format and number value.
The two strings 0.123 and .123, when read as a number, are mathematically equals. They represent the same number. In Oracle the true number representation is never displayed directly, we always convert a number to a character to display it, either implicitly or explicitly with a function.
You assume that a number between 0 and 1 should be represented with a leading 0, but this is not true by default, it depends on how you ask this number to be displayed. If you don't want unexpected outcome, you have to be explicit when displaying numbers/dates, for example:
to_char(your_number, '9990.99');

It's the default number formatting that Oracle provides.
If you want to specify something custom, you shall use TO_CHAR function (either in SQL query or PL/SQL code inside the loop).
Here is how it works:
SQL>
SQL> WITH aa AS (
2 select 1.3232 NUM from dual UNION ALL
3 select 1.3232 NUM from dual UNION ALL
4 select 332.323 NUM from dual UNION ALL
5 select 0.3232 NUM from dual
6 )
7 select NUM, to_char(NUM, 'FM999990D9999999') FORMATTED from aa
8 /
NUM FORMATTED
---------- ---------------
1.3232 1.3232
1.3232 1.3232
332.323 332.323
.3232 0.3232
SQL>
In this example, 'FM' - suppresses extra blanks, '0' indicates number digit including leading/trailing zeros, and '9' indicates digit suppressing leading/trailing zeros.
You can find many examples here:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34570

Related

Need specific number format in Oracle S9(15)V9(2)

I have a requirement to produce amount fields in zoned decimal format with this specific syntax below.
I don’t know if I need to create a function to handle this or if I can tweak the Oracle number format model. I’m thinking it might require some conditional formatting within a function due to the different requirement for number of digits between positive and negative. I will be performing this formatting on a couple of dozen data elements in the procedure so that might be another reason to use a function. Thoughts?
Requirement:
Amount should be represented by 17 characters (positive number) or 16 characters plus a “}” appended to the end (negative number).
Ex. 0.00 should show as 00000000000000000.
Ex. -935,560.00 should show as 00000000093556000}
Using Oracle 12c.
If I understood you correctly, the input is already formatted and its datatype is VARCHAR2. If that's so, then this might do the job:
SQL> with test (col) as
2 (select '0.00' from dual union all
3 select '25.34' from dual union all
4 select '-935,560.00' from dual
5 )
6 select col,
7 lpad(translate(col, 'x,.-', 'x'),
8 case when substr(col, 1, 1) = '-' then 16
9 else 17
10 end, '0') ||
11 case when substr(col, 1, 1) = '-' then '}'
12 else null
13 end result
14 from test;
COL RESULT
----------- --------------------
0.00 00000000000000000
25.34 00000000000002534
-935,560.00 0000000093556000}
SQL>
What does it do?
lines #1 - 5 - sample data
line #7 - translate removes minus sign, commas and dots
lines #7 - 10 - lpad pads the number (without characters from the previous step) with zeros up to the length of 16 (for negative values) or 17 (for positive values) characters
lines #11 - 13 - if it is a negative value, concatenate } to the end of the result string

FInd if the fifth position is a letter and not a number using ORACLE

How can I find if the fifth position is a letter and thus not a number using Oracle ?
My last try was using the following statement:
REGEXP_LIKE (table_column, '([abcdefghijklmnopqrstuvxyz])');
Perhaps you'd rather check whether 5th position contains a number (which means that it is not something else), i.e. do the opposite of what you're doing now.
Why? Because a "letter" isn't only ASCII; have a look at the 4th row in my example - it contains Croatian characters and these aren't between [a-z] (nor [A-Z]).
SQL> with test (col) as
2 (select 'abc_3def' from dual union all
3 select 'A435D887' from dual union all
4 select '!#$%&/()' from dual union all
5 select 'ASDĐŠŽĆČ' from dual
6 )
7 select col,
8 case when regexp_like(substr(col, 5, 1), '\d+') then 'number'
9 else 'not a number'
10 end result
11 from test;
COL RESULT
------------- ------------
abc_3def number
A435D887 not a number
!#$%&/() not a number
ASDĐŠŽĆČ not a number
SQL>
Anchor to the start of the string else you may get unexpected results. This works, but remove the caret (start of string anchor) and it returns 'TRUE'! Note it uses the case-insensitive flag of 'i'.
select 'TRUE'
from dual
where regexp_like('abcd4fg', '^.{4}[A-Z]', 'i');
Yet another way to do it:
regexp_like(table_column, '^....[[:alpha:]]')
Using the character class [[:alpha:]] will pick up all letters upper case, lower case, accented and etc. but will ignore numbers, punctuation and white space characters.
If what you care about is that the character is not a number, then use
not regexp_like(table_column, '^....[[:digit:]]')
or
not regexp_like(table_column, '^....\d')
Try:
REGEXP_LIKE (table_column, '^....[a-z]')
Or:
SUBSTR (table_column, 5, 1 ) BETWEEN 'a' AND 'z'

Oracle plsql how to check if number has decimal points

Just started working with oracle using toad ide. trying to format the numbers from a table in specific format. the numbers come in from a variable in the table and I want to display the whole numbers as whole numbers and display floats as floats. So far, I can use trim(TO_CHAR (width,'999.999')) to display all numbers with decimal points.
For example: 123.5 will be displayed as 123.500 and 100 will be displayed as 100.000.
What I want to do is display for eg: 100 as 100.
Hope this is clear and I get a solution soon.
I'm using MOD for determining decimals.
select test_value, (case when mod(test_value,1) != 0 then 'DECIMAL' else 'NODECIMAL' END) IS_DECIMAL
from (select 1.5 test_value from dual
union all
select 100 test_value from dual) test_table
If your problem is about the way Toad shows numbers, you can follow the hints in the comments.
If the problem is about the way Oracle shows numbers, converting them to strings, maybe this can help:
SQL> select to_char(1.5, 'TM9') as num from dual union all
2 select to_char(100, 'TM9') from dual;
NUM
----------------------------------------------------------------
1,5
100
You find much more in the documentation
If you need a way to check whether a number has a decimal part or not, you can simply try:
SQL> with numbers(num) as (
2 select 1.5 from dual union all
3 select 100 from dual
4 )
5 select case
6 when floor(num) = num
7 then to_char(num, 'FM999999') || ' has not a decimal part'
8 else
9 to_char(num, 'FM9999D000') || ' has a decimal part'
10 end as checkString
11 from numbers;
CHECKSTRING
------------------------------
1,500 has a decimal part
100 has not a decimal part

Decimal place require in Oracle

case 1: SELECT TO_CHAR(12345.6789, '99999D99') FROM dual;
Output: 12345.67
case 2: SELECT TO_CHAR(12345.6789, '999D99') FROM dual;
Output: ######
case 3: SELECT TO_CHAR(12345, '99999D99') FROM dual;
Output: 12345.00
case 4: SELECT TO_CHAR(12345.1, '99999D99') FROM dual;
Output: 12345.10
Here Problem is if we don't know how many digits before decimal then how to manage for correct answer.[only case 1,3,4 can resolved using by TO_CHAR but how to solve for case 2.]
In this case the simplest answer might be to not supply a format model at all, but truncate or round the value to two decimal places:
SELECT TO_CHAR(ROUND(12345.6789, 2)) as rounded,
TO_CHAR(TRUNC(12345.6789, 2)) as truncated
FROM dual;
ROUNDED TRUNCATED
-------- ---------
12345.68 12345.67
From the documentation:
If you omit fmt, then n is converted to a VARCHAR2 value exactly long enough to hold its significant digits.
Otherwise you'd need to supply a format model that allowed for the maximum size of your number; if it's unrestricted you'd need 36 nines, the decimal separator, and two more nines. The result would be padded with spaces so you might also want to trim it, depending on how you'll use the string value.
SELECT TO_CHAR(12345.6789, '999999999999999999999999999999999999D99') as val
FROM dual;
VAL
----------------------------------------
12345.68
You could also do that flexibly by using the length of the truncated value (i.e. once the decimal places have been removed):
SELECT TO_CHAR(12345.6789,
lpad('9', length(trunc(12345.6789)), '9') || 'D99') as val
FROM dual;
VAL
---------
12345.68
But that seems unnecessarily complicated when you can let Oracle work it out for you.
However, if you want the decimals to show trailing zeros then you might need to use that method; but with zeros after the decimal separator:
SELECT TO_CHAR(12345.6, lpad('0', length(trunc(12345.6)), '9') || 'D00') as val
FROM dual;
VAL
---------
12345.60
... which addresses the 3rd and 4th cases you added. I've made it show a leading zero for values less than 1 as well; the generated format model in this case is '99990D00'. The number of nines will still vary depending on the size of your number.
By default Oracle still leaves a space at the start for a potential minus sign. You can avoid that with the FM format modifier:
SELECT TO_CHAR(12345.6, 'FM'
|| lpad('0', length(trunc(12345.6)), '9') || 'D00') as val
FROM dual;
VAL
--------
12345.60
You could always go with the maximum number of digits you expect to be present in the input. If there are fewer digits in the input than your format specifier, it wouldn't affect the outcome in anyway. For instance,
select to_char(12323.5553,'99999D99') from dual
would produce,
123.56
As you said, the length of the input is unknwon. So why would you use a fixed length formater for somthing that is unknown? Does not work. Read your input as String from the beginning and manipulate it as String or even better - BLOB.
Well, to do the rounding correct might be tricky.
So, best check your data if the numbers will realy get so big, because that would mean a lot of work and trouble.
If not more than 38 Digits are needed, you can go with decimal or numeric datatype and (if you insist on a formatter) use the TM formatter for example.
SELECT to_char(cast(1234.456 as decimal( *,2)), 'TM') as a FROM dual
or take the advice that was given above by the other posters.

Oracle to_char function with a number format that has an arbitrary precision and certain scale

This one is pretty simple actually yet I wasn't able to find anything useful.
In my SQL query I have some rounded numbers with a single scale value - round(number,1). If the numbers are rounded to some decimal digit it prints in the format '9,9'.
On the other hand if the numbers are rounded to an integer, only the integer value without the zero after comma is printed although I want my query to select the numbers in '9,9' format even the decimal digit is zero.
In short, I think I need something like for example
to_char((select round(121.01,1), from dual), '*,1') ; to output 121,0.
What is the best way to do this? Thanks in advance
Korhan
All you have to do is specify the number of decimal points you want in your to_char. The problem with using format masks is that you need to specify the number of numbers you want in front of your decimal point.
SQL> select to_char(round(121.01,1),'999.9') from dual;
TO_CHA
------
121.0
SQL> select to_char(round(121.4,1),'999.9') from dual;
TO_CHA
------
121.4
SQL> select to_char(round(121,1),'999.9') from dual;
TO_CHA
------
121.0
SQL> select to_char(round(5121,1),'999.9') from dual;
TO_CHA
------
######
SQL>
There are a number of other formatting options.
Use 0 instead 9 for decimal places:
SELECT TO_CHAR( ROUND( 121.01, 1 ), '990D0' ) num FROM DUAL;
NUM
------
121.0
This simple query may help you,
select to_char(round(121.01,1), '999.0') from dual;
In to_char function:
9 - indicate to block/hide zeros in the output.
0 - indicate to show zero in the output at anywhere in before/after decimal point.
Note:
No. of '9/0's in before/after decimal point is number of digits which you want to display beore/after decimal point.

Resources