Oracle SQL TO_CHAR variable length - sql

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

Related

Oracle SQL query to find special characters for phone numbers

I am trying to write a query to find special character for phone numbers.
Expected phone number is : 2047653894
Actual: 204765389(4, 204-7653894, -2047653894, (204)7653894, 20476+53894, ....
NOTE: I only want to find the phone numbers with special characters. I don't want to replace special characters.
Another option is to remove all non-digits (here, where I live, phone numbers are digits only; I'm not talking about various formats phone numbers might have):
SQL> with test (col) as
2 (select '204765389(4' from dual union all
3 select '204-7653894' from dual union all
4 select '-2047653894' from dual union all
5 select '(204)7653894' from dual union all
6 select '20476+53894' from dual
7 )
8 select
9 col,
10 regexp_replace(col, '\D') result
11 from test;
COL RESULT
------------ ------------------------------------------------
204765389(4 2047653894
204-7653894 2047653894
-2047653894 2047653894
(204)7653894 2047653894
20476+53894 2047653894
SQL>
[EDIT]
If you just want to find phone numbers that contain anything but digits, use regexp_like:
SQL> with test (col) as
2 (select '204765389(4' from dual union all
3 select '204-7653894' from dual union all
4 select '-2047653894' from dual union all
5 select '(204)7653894' from dual union all
6 select '20476+53894' from dual union all
7 select '2047653897' from dual
8 )
9 select col
10 from test
11 where regexp_like(col, '\D');
COL
------------
204765389(4
204-7653894
-2047653894
(204)7653894
20476+53894
SQL>
You can use [[:punct:]] posix along with REGEXP_REPLACE() such as
SELECT REGEXP_REPLACE(col,'[[:punct:]]') AS col
FROM t
assuming each comma-separated value represents a column value within a table
Demo
While you can use regular expressions, they are slow and it may be faster to use simple string functions and use TRANSLATE to find all the non-numeric characters and then replace them:
SELECT TRANSLATE(
phone_number,
'0' || TRANSLATE(phone_number, 'x0123456789', 'x')
'0'
) AS simplified_phone_number
FROM table_name;
Which, for your sample data:
CREATE TABLE table_name (phone_number) AS
SELECT '204765389(4' FROM DUAL UNION ALL
SELECT '204-7653894' FROM DUAL UNION ALL
SELECT '-2047653894' FROM DUAL UNION ALL
SELECT '(204)7653894' FROM DUAL UNION ALL
SELECT '20476+53894' FROM DUAL;
Outputs:
SIMPLIFIED_PHONE_NUMBER
2047653894
2047653894
2047653894
2047653894
2047653894
fiddle
Update
If you want to list phone numbers with non-digit characters then you can also use TRANSLATE to remove the digits and check if there are any other characters:
SELECT *
FROM table_name
WHERE TRANSLATE(phone_number, 'x0123456789', 'x') IS NOT NULL
you could also use REGEXP_LIKE to check that the string is not entirely digits:
SELECT *
FROM table_name
WHERE NOT REGEXP_LIKE(phone_number, '^\d+$')
or that there are non-digits:
SELECT *
FROM table_name
WHERE REGEXP_LIKE(phone_number, '\D')
However, regular expressions are probably going to be slower than simple string functions like TRANSLATE.
fiddle

Regexp pattern for special characters

I have the data in the format like
Input:
Code_1
FAB
?
USP BEN,
.
-
,
Output:
Code_1
FAB
IP BEN,
I need to exclude only the value which have length as 1 and and are special characters
I am using (regexp_like(code_1,'^[^<>{}"/|;:.,~!?##$%^=&*\]\\()\[¿§«»ω⊙¤°℃℉€¥£¢¡®©0-9_+]')) AND LENGTH(CODE_1)>=1
I have also tried REGEXP_LIKE(CODE_1,'[A-Za-z0-9]')
Based on your requirements which I understand are you want data that is not single character AND non-alpha numeric (at the same time), this should do it for you.
The 'WITH' clause just sets up test data in this case and can be thought of like a temp table here. It is a great way to help people help you by setting up test data. Always include data you don't expect!
The actual query starts below and selects data that uses grouping to get the data that is NOT a group of non-alpha numeric with a length of one. It uses a POSIX shortcut of [:alnum:] to indicate [A-Za-z0-9].
Note your requirements will allow multiple non-alnum characters to be selected as is indicated by the test data.
WITH tbl(DATA) AS (
SELECT 'FAB' FROM dual UNION ALL
SELECT '?' FROM dual UNION ALL
SELECT 'USP BEN,' FROM dual UNION ALL
SELECT '.' FROM dual UNION ALL
SELECT '-' FROM dual UNION ALL
SELECT '----' FROM dual UNION ALL
SELECT ',' FROM dual UNION ALL
SELECT 'A' FROM dual UNION ALL
SELECT 'b' FROM dual UNION ALL
SELECT '5' FROM dual
)
SELECT DATA
FROM tbl
WHERE NOT (REGEXP_LIKE(DATA, '[^[:alnum:]]')
AND LENGTH(DATA) = 1);
DATA
----------
FAB
USP BEN,
----
A
b
5
6 rows selected.

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:

Values are not displaying with leading zero in oracle

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

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;