Oracle 01481. 00000 - "invalid number format model" - oracle

This is my query i have used to get the value as money. Nut when concat value getting above exception. The query is
select to_char(b.balance,'9999.'||d.number_of_decimal_places) from balance b, decimal d
Am stuck with this problem.

If you have numeric number_of_decimal_places values like 1, 2, 3 etc. then you are constructing a format model like, for example, '9999.2' instead of '9999.99'.
You can convert that integer value to the format model with rpad or lpad:
select to_char(b.balance,'9999.'||rpad('9', d.number_of_decimal_places, '9'))
from balance b, decimal d
Or for trailing zeros:
select to_char(b.balance,'9999.'||rpad('0', d.number_of_decimal_places, '0'))
from balance b, decimal d
If you have string number_of_decimal_places values like '9', '99', '999' etc. then the concatenation you have will work unless you have an invalid value in one of the rows, which would be any character other than a 9 or a 0.
That includes spaces, which you could have in a varchar2 or char field. Either way you could remove those with trim:
select to_char(b.balance,'9999.'||trim(d.number_of_decimal_places))
from balance b, decimal d
But if you have any other characters then you will need to identify and correct the data in those rows; and even with spaces it would be better to fix the data if it's a varchar2 column.
It would be better to use new-style joins; I haven't changed these examples because it isn't clear if you are doing a cartesian product or have just omitted the join conditions.

If number_of_decimals returns a value like 2 then:
SELECT TO_CHAR( b.balance, RPAD( '9999.', 5 + d.number_of_decimals, '9' ) )
FROM balance b
CROSS JOIN
decimal d

For whatever reason, the concatenation of '9999.'||d.number_of_decimal_places is generating an invalid mask. We can only guess at the actual table values, presence of spaces, or whatever else may be causing issues with what it is doing.
So your solution is to run:
select '9999.'||d.number_of_decimal_places from decimal d
See what the actual format mask is that you are generating, and adjust as necessary.

Related

Cast bigint to decimal(18,5) in hive

I'm trying to cast a bigint to decimal(18,5) in hive and I'm not getting any fraction values after converting to decimal(18,5).
Let's take the below bigint values
99000
999000
499000
350000
344000000
After casting to decimal(18,5), I'm expecting something like below
0.99000
9.99000
4.99000
3.50000
3440.00000
I'm trying the below query.
select col_a, cast(col_a as decimal(18,5)) from table;
From above query, I'm getting output same as input
99000
999000
499000
350000
344000000
Also, I tried dividing the input with 10^5 and casting to decimal(18,5).
select col_a, cast(col_a/100000 as decimal(18,5)) from table;
Above query is returning the fraction values, but not having 5 digits after the decimal.
0.99
9.99
4.99
3.5
344000000
Could someone please correct me what I'm missing or doing wrong here.
DECIMAL type do not permit values larger than the range implied by the column definition.
DECIMAL(5,0) column supports a range of -99999 to 99999.
DECIMAL(M,D) column permits up to M - D digits to the left of the decimal point.
For example DECIMAL(5,2) permits -999.99 to 999.99
And the trailing zeroes are not displayed. If you need them guaranteed to be displayed, use string type and rpad() function to add zeroes at the end or something like that.
If the number cannot be cast to decimal, NULL is returned, for example the following cast returns NULL:
select cast(1234567890L as decimal(3,1))
It is not clear why do you expect cast a bigint to decimal(18,5) to produce some fractional numbers. cast does not divide your initial numbers.

How to convert char to number with mask

I can't convert char symbols with dot to number. I get exception
ORA-01481 invalid format mask
Which mask would work for me? I need unlimited number of characters before the dot.
The star or n symbol doesn't work
select to_number('840.11', '*.99') from dual
The behaviour of to_number depends on database or even session settings, so in order to be sure to convert it the way you need, you need to supply the numeric characters, like this:
select to_number('840.11', '999.99', ' NLS_NUMERIC_CHARACTERS = ''. ''') from dual
Now if you have a higher number of digits before the dot, you can simply enlarge the format mask, like this:
select to_number('234234840.11', '99999999999999.99', ' NLS_NUMERIC_CHARACTERS = ''. ''')
from dual
There is no direct way to specify a dynamic amount of digits before the dot, but there is some kind of workaround described here:
Dynamic length on number format in to_number Oracle SQL
You can build a fitting formatmask using TRANSLATE and then ROUND (or TRUNC) the solution of the transformation to your needed accuracy:
SELECT ROUND(TO_NUMBER('840.1155',TRANSLATE('840.1155', '123456789', '000000000')),2) FROM dual
=> 840.12

Oracle joining tables where the matching process starts after certain digits

I have joined two tables which contain words as well as values. The matching of the words works. The matching of the values do not. The reason is that the values in the table "GATTUNGSDATEN" always start with 4 zeros whereas in the table BONDMAPPING not. E.g. 00001234 = 1234. What query could I use in order to have the matching process started after 4 digits?
select MET_SEC_INDEX_GATTUNGSDATEN.ranl, MET_SEC_INDEX_GATTUNGSDATEN.vvranlwx,
V_AR_BONDMAPPING.MUREXEXTERNALID
from V_AR_BONDMAPPING
RIGHT JOIN MET_SEC_INDEX_GATTUNGSDATEN
ON V_AR_BONDMAPPING.MUREXEXTERNALID = MET_SEC_INDEX_GATTUNGSDATEN.ranl IN
('%%%%')
where vvranlwi=34
If it's always four leading zeroes you can use SUBSTR():
from V_AR_BONDMAPPING
RIGHT JOIN MET_SEC_INDEX_GATTUNGSDATEN
ON V_AR_BONDMAPPING.MUREXEXTERNALID = substr(MET_SEC_INDEX_GATTUNGSDATEN.ranl, 5)
This trims the leading four characters from MET_SEC_INDEX_GATTUNGSDATEN.ranl
If you know the length of the identifiers you could pad the shorter identifier with leading zeroes
select lpad(1234, 8, '0') from dual
=>
00001234
select lpad('00001234', 8, '0') from dual
=>
00001234
This will implicitly convert the numbers into VARCHAR2s however, which on the other hand is what would happen anyways during the comparison

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 cursor removes leading zero

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

Resources