format a lengthy number with commas in Oracle - sql

I have a requirement to convert the very lengthy amount to a comma separated value in oracle. I was searching in google. but I got some solutions which works only for small numbers. But not for lengthy number. Below is the solution I have. But not working properly. I was getting ############... if I run the below.
SELECT TO_CHAR(6965854565787645667634565432234565432345643265432345643242087,
'99G999G999G9999', 'NLS_NUMERIC_CHARACTERS=",."') as test
FROM dual;
Desired output:
6,965,854,565,787,645,667,634,565,432,234,565,432,345,643,265,432,345,643,242,087
Please help me. thanks in advance.

Please check if below query can help.
SELECT ltrim(regexp_replace('00'
|| '6965854565787645667634565432234565432345643265432345643242087', '(...)', ',\1' ),',|0') AS t
FROM dual;

Numbers in Oracle can't have more than 38 significant digits. You have many more than that.
If I may, what kind of "amount" is that? My understanding is that Oracle was designed to handle real-life values. What possible meaning is there to the sample number you posted?
Added: Original poster in a comment (below) stated that he is getting the same error with a shorter number, only 34 digits.
Two issues. First, the format model must have at least the needed number of digits (of 9's). to_char(100000, '9G999') will produce the output #### because the format model allows only 4 digits, but the input is 6 digits.
Then, after that is corrected, the output may still look incorrect in the front-end application, like SQL*Plus. In SQL*Plus the default width of a number column is 10 (I believe). That can be changed to 38, for example with the command set numwidth 38. In other front-ends, like Toad and SQL Developer, the default numeric width is a setting that can be changed through the graphical user interface.
More added - actually the result of to_char is a string, and by default strings of any length should be displayed OK in any front-end, so the numeric width is probably irrelevant. (And, in any case, it does not affect the displaying of strings, including the result of to_char().)

SELECT TO_CHAR(
6676345654322345654323456432654323456,
'999G999G999G999G999G999G999G999G999G999G999G999G999',
'NLS_NUMERIC_CHARACTERS=",."') as test FROM dual
TEST
------------------------------------------------------------
6,676,345,654,322,345,654,323,456,432,654,323,456

#AlexPoole pointed out that perhaps your input is a string.
I didn't get that vibe; but if in fact your input IS a string, and if you know the length is no more than 99 digits, you could do something like below. If your strings can be longer than 99, replace 99 below with a sufficiently large multiple of 3. (Or, you can replace it with a calculated value, 3 * ceil(length(str)/3)).
with
inputs ( str ) as (
select '12345678912345' from dual
)
-- WITH clause is only for testing/illustration, not part of the solution
select ltrim(regexp_replace(lpad(str, 99, ','), '(.{3})', ',\1'), ',') as test
from inputs;
TEST
------------------
12,345,678,912,345

Related

Extracting string between two characters in sql oracle database

I need to extract a string that will located between two characters, with always the same pattern
sample string:
A CRN_MOB_H_001 a--> <AVLB>
What is in bold AVLB is what I want to extract, the whole string will always have the same pattern, and everything that is before the < is irrelevant to me.
The string will always have the same pattern:
Some string with possible special characters such as <>, although very unlikely so, it can be ignored if too complicated
a space
then -->
a space
and then the part that is interesting <XXXXXXX>
The XXXXXXX representing the part I want to extract
thank you for your time.
I have tried several things, could not get anywhere I wanted.
Please try this REGEXP_SUBSTR(), which selects what is in the angled brackets when they occur at the end of the string.
Note the WITH clause just sets up test data and is a good way to supply data for people to help you here.
WITH tbl(str) AS (
SELECT 'A CRN_MOB_H_001 a--> <AVLB>' FROM dual
)
SELECT REGEXP_SUBSTR(str, '.*<(.*)>$', 1, 1, NULL, 1) DATA
FROM tbl;
DATA
----
AVLB
1 row selected.

How to understand to_number formatting in PosgreSQL

I'm not getting behavior that I expect from PostgreSQL's function "to_number" based on my reading of the formatting documentation. So I'm probably reading it wrong. Can someone explain this so that I'll know what to expect in other similar contexts?
-- I find this intuitive:
# select to_number( '12,345.67', '99999.999') ;
to_number
-----------
12345.67
-- I find this surprising:
# select to_number( '12,345.67', '99999.99') ;
to_number
-----------
12345.6
-- EDIT: I found this surprising new variation:
# select to_number( '12,345.67', '999999.99') ;
to_number
-----------
12345.67
Why did my final hundredths digit get dropped in the second case?
EDIT: It seems that the issue is not anything to do with rounding or with how many digits appear to the right of the decimal in my format. Rather, the issue has to do with the total number of characters the format contains and therefore the total number of characters that get parsed. I think the final complete answer will be a slight variation on what mu is too short posted.
In practice I could just always return more digits than I think I need. But that's not very satisfying. It will probably bite me someday. Note: It's not an issue with '9' vs '0' in the format. Those behave identically in to_number, which I find slightly surprising... but clearly documented in the above link.
The problem is that your "number" has a comma as a thousands separator but your pattern does not. Lining them up vertically to make the comparison easier:
12,345.67
99999.99
^
We see that the pattern is looking for a number but it finds a comma. Your pattern doesn't quite match the string you're using so you get unexpected results.
If you add the separator to your pattern (see Table 9.26: Template Patterns for Numeric Formatting in the documentation) then you'll get what you're looking for:
=> select to_number('12,345.67', '99,999.99');
to_number
-----------
12345.67
(1 row)
I will start by thanking mu. His answer was clearly helpful. But I'm posting a separate answer because I think his answer as stated misses an important part of the answer.
I have not looked at any PostgreSQL code, so my answer comes purely from observation of its behavior. When I created my first format, I implicitly assumed something like the following:
# My pseudocode for select to_number( '12,345.67', '99999.99') ;
# I guessed PostgreSQL would do this:
1. Parse up to 5 digits
2. [optionally] find a decimal
3. [optionally] if decimal was found, find up to 2 more digits
in this example:
1. Up to five digits: 12345
2. Decimal: yes
3. Two more digits: 67
4. All together: 12345.67
# But in fact what it does is closer to this:
1. Parse up to 8 characters
2. Find the first decimal point in the parsed characters
3. In the set of parsed characters, find up to 5 characters before the decimal
4. In the set of parsed characters, find up to 2 characters after the decimal.
in this example:
1. Up to 8 characters: 12,345.6
2. First decimal: the penultimate character
3. Before decimal: 12345
4. After decimal: 6
5. All together: 12345.6
Therefore, my problem was fundamentally that PostgreSQL was parsing only 8 characters, but I was passing in 9 characters. Thus the solutions are:
# Mu's suggestion: include comma in the format. Now the format is 9 characters.
# This way it parses all 9 characters:
select to_number('12,345.67', '99,999.99');
to_number
-----------
12345.67
# Or include another character before the decimal
# This way it also parses 9 characters before limiting to 5.2:
select to_number( '12,345.67', '999999.99') ;
to_number
-----------
12345.67
# Or include another character after the decimal
# This way it parses 9 characters before limiting to 5.3:
select to_number( '12,345.67', '99999.999') ;
to_number
-----------
12345.67
And once you look at it like that, it becomes clear why otherwise inscrutable degenerate cases work as they do:
# like this one work as they do:
select to_number('1x2,3yz45.67', '9999999.9999');
to_number
-----------
12345.67
select to_number('12.3.45.67', '9999999.9999');
to_number
-----------
12.3456
I'm not sure that I would have specified the behavior like this. But now it's much clearer what to expect.

Using regexp_replace to remove letters from numbers

I've got a bunch of data with altitude - some of it just numbers, some include meters at the end or '. I also have few ranges 1200-1300 etc (I guess it the second problem would have to be solved a different way). I tried experimenting with regexp_replace but [^a-z] doesn't seem to be working.
Any of you have a good idea on how to get rid of everything that's not a digit? Also, if you could recommend good website/book/course on how to clear data, I'd be much appreciated. Thanks!
Let's leave the ranges (like 1200-1300) to the side, since - even regardless of any kind of programming - it is not clear what you would want to "extract" from that. And, you may also have problems with things like '5 ft 10 in' or similar, if they are possible in your data. (And it is not clear what the whole thing means if all altitudes aren't using the same unit of measurement anyway - some are in meters, some in feet, the info disappears when you just keep the number).
To remove all the non-digits from a string and to keep the digits, you do NOT need regular expressions, which may be quite slow (an order of magnitude slower!) than standard string functions.
One way to remove all non-digit characters uses the TRANSLATE function. Like so:
translate(input_string, '0123456789' || input_string, '0123456789')
The function "translates" (replaces) 0 with 0, 1 with 1, etc., and any character in the input string that hasn't already appeared earlier in the second argument (which in this case means "non-digit") to nothing (null, zip, disappears, is removed).
Example (note the use of TO_NUMBER to also convert to actual numbers):
with
data (input_string) as (
select '1500' from dual union all
select '2100 m' from dual union all
select '535 ft' from dual
)
select input_string,
to_number(translate(input_string, '0123456789' || input_string,
'0123456789')) as extracted_number
from data;
INPUT_STRING EXTRACTED_NUMBER
------------ ----------------
1500 1500
2100 m 2100
535 ft 535

TOAD SQL - LPAD Number, but also add decimals?

Basically what I'm trying to do is add '000' to a number (between 5-8 characters in length) and make the whole numbers have decimals.
What I came up with is:
SELECT DISTINCT
'000' || TO_CHAR(Blah, '9,999,999.99') AS "Data"
FROM Blah database
While this does what I ideally want, there is a gap between the zeroes of either 3 or 4 depending on the number. Obviously I don't want the gap there. Where am I going astray?
Use trim(to_char(x, '9,999,999.99')) this way you will avoid gap

sql query for alphanumeric ID in hex

I want to be able to differentiate between a string that is alphnumeric and a string that is in hex format.
My current query is:
<columnName> LIKE '?_____=' + REPLICATE('[0-9A-Fa-f]',16)
I found this method of searching for hex ID's online and I thought it was working. However after getting a significantly larger sample size I can see a high false positive rate in my results. The problem is that this gives me all the results I do want but it also gives me a bunch of results I dont care about. For example:
I want to see:
<url>.php?mains=d7ad916d1c0396ff
but i dont want to see:
<url>.php?mblID=2007012422060265
The difference between the 2 strings is that the 16 characters at the end that i want to collect are all numeric and not a hex ID. What are some ways you guys use to limit the results to hex ID only? Thanks in advnace.
UPDATE:
Juergen brought up a good point, the second number could be a hex value to. Not all hex numbers contain [a-F]. I would like to rephrase the question to state that I am looking for an ID with both letters and numbers in it, not just numbers.
The simplest way is just to add a separate clause for that restriction:
<columnName> LIKE '?_____=' + REPLICATE('[0-9A-Fa-f]',16)
AND <columnName> NOT LIKE '?_____=' + REPLICATE('[0-9]',16)
It should be fairly simple to determine if a string contains only numbers...
Setting up a test table:
CREATE TABLE #Temp (Data char(32) not null)
INSERT #Temp
values ('<url>.php?mains=d7ad916d1c0396ff')
,('<url>.php?mblID=2007012422060265 ')
Write a query:
SELECT
right(Data, 16) StringToCheck
,isnumeric(right(Data, 16)) IsNumeric
from #Temp
Get results:
StringToCheck IsNumeric
d7ad916d1c0396ff 0
2007012422060265 1
So, if the IsNumeric function returns 0, it could be a hex string.
This makes several assumptions:
The rightmost 16 characters are what you want to check
You only ever hit 16 characters. I don't know when the string would get too long to check.
A non-numeric character means hex. Any chance of "Q" or "~" being embedded in the string?