Remove all dots from a String except first, with Oracle REGEXP_REPLACE - oracle

I want to use the Oracle REGEXP_REPLACE to remove some dots from a String.
I have to remove from the second dot if exists.
For example:
4 => 4
5 => 5
5.1 => 5.1
5.1.1 => 5.11
5.1.2 => 5.12
5.1.2.1 => 5.121
5.1.2.2 => 5.122
6 => 6
I have this
select REGEXP_REPLACE(num, '(\d+)(\.)(\d+)(\.)(\d+)', '\1.\3\5')
from my_table;
the problem is that my query is made just for two dots. If the string has more than two dots, I have to modify the query to accept more dots and so.
Is there any way to do this automatically?
Thanks

A posible "dirty" solution
select REGEXP_REPLACE(num, '(\d+)(\.)(.*)', '\1\2') ||
REPLACE( REGEXP_REPLACE(num, '(\d+)(.*)', '\2') ,'.','')
from my_table;
and although it's not at all clear, it works.

SELECT SUBSTR(mystr, 1, INSTR(mystr,'.'))
|| REPLACE(SUBSTR(mystr, INSTR(mystr,'.')+1),'.')
FROM my_table;

Related

oracle apex - multiple default value for APEX_ITEM.Select_list_from_query_xl with attribute multiple="multiple"

I'm using oracle 18.
I create dynamically an apex_item's select list in multiple selection mode.
Using the parameter P_attributes => 'multiple="multiple" '
It's working fine except when I try to feed it multiple default value
If I set the value to a single element, it's working.
But if I set the value with more than one item no element is selected.
I tried to space the items with , ; : and space with no result.
Please tell there's a way cause i realy need it to work. End of projetc is near and I don't have a B plan.
lHtml := APEX_ITEM.Select_list_from_query(P_idx => 20,
P_value => '2:3',
P_query => 'select ''blue'' d,1 r from dual union select ''red'',2 from dual union select ''green'',3 from dual',
P_attributes => 'multiple="multiple"',
P_item_id => 'testMultiple',
P_item_label => 'Test Multiple Default');
HTP.P ( lHtml );

How to use different group separators for thousands and millions. Oracle

I need to display different results in the next format, example:
40000000 to 40'000,000
I tried using this, but when i try 2 differents group separators i get the "invalid number format model" error:
select to_char(9999999999, '9g999g99999g9', 'NLS_NUMERIC_CHARACTERS='',.''')
from dual;
Also tried using substr and replace but it doesnt work in all the cases (like when the result is 3000000 or 700000000).
This works but it is not the optimal solution.:
SELECT substr(replace('40,000,000',',',''''),0,length(40000000)-2)|| substr('40,000,000',-4) from dual;
What the actual select look like if i use the previous code.
SELECT substr(replace(to_char(oTOTAL_SENIOR, '999,999,999'),',',''''),0,length(oTOTAL_SENIOR)-2)|| substr(to_char(oTOTAL_SENIOR, '999,999,999'),-4) from dual
The previous select gets bugged when i use substr replace and to_char together because of the '999,999,999'.
I also tried using regexp_replace but im not good at it.
I know i need to replace everything but the last 4 characters (,000) but i dont know how.
Any help will be aprreciated.
You'll need someone smarter than me to do that properly, but - meanwhile, see whether this helps.
I'm on XE 11g; in order to avoid "no more data to read from socket" error I got during the final steps of this query (I believe it was due to two string reversings), I created my own "reverse" function. There's undocumented reverse function, but I don't want to use it.
Basically, it reverses a string you pass as a parameter. What do I need it for? I found it simpler to reverse values, split them to 3-by-3-by-3 characters and apply those "strange" separators you want. Also, it makes the whole code simpler. It can be done without it, but - as I said - no more data to read from socket won't allow it. Sorry about that.
Now, someone will say: why didn't you (meaning: me, LF) do that using PL/SQL completely and put everything into a function? No particular reason & no problem in doing it, if necessary.
OK, here it is:
SQL> create or replace function f_reverse (par_string in varchar2)
2 return varchar2
3 is
4 retval varchar2(20);
5 begin
6 select listagg(substr(par_string, level, 1))
7 within group (order by level desc)
8 into retval
9 from dual
10 connect by level <= length(par_string);
11
12 return retval;
13 end;
14 /
Function created.
SQL> select f_reverse('1234') from dual;
F_REVERSE('1234')
---------------------------------------------------------------------
4321
SQL>
Finally, this is what you want:
SQL> with test (id, col) as
2 (select 1, 40100200 from dual union all
3 select 2, 2300400 from dual union all
4 select 3, 700500 from dual union all
5 select 4, 25700 from dual union all
6 select 5, 6300 from dual union all
7 select 6, 555 from dual
8 )
9 select id,
10 regexp_replace(
11 f_reverse(
12 substr(f_reverse(col), 1, 3) ||','||
13 substr(f_reverse(col), 4, 3) || chr(39) ||
14 substr(f_reverse(col), 7)
15 ), '^[^0-9]+', '') result
16 from test;
ID RESULT
---------- ----------
1 40'100,200
2 2'300,400
3 700,500
4 25,700
5 6,300
6 555
6 rows selected.
SQL>
What does it do?
lines #1 - 7 - sample data
lines #9 onward is useful code
lines #12 - 14 - splitting reversed sample data into substrings 3 characters in length
line #12 - concatenated , as this is thousands separator
line #13 - concatenaded chr(13) which is ', a millions separator
line #11 - reversing concatenated "reversed" string back
line #10 - removing possible non-numeric characters from the beginning of the result (those are separators for values that are shorter than "thousand" or "million")

Oracle string operation to exclude specific characters based on delimiter

From the String ES-123456-PSA Spain-101, I need to extract only ES-123456-101 Delimiter position is fixed.
Tried REGEXP_SUBSTR('ES-123456-PSA Spain-101','[^-]+',2,3 ) which gives PSA Spain.
Is there a way to ignore those specific characters and returns rest of them.
If you want ES-123456-101 then use this:
SELECT REGEXP_REPLACE('ES-123456-PSA Spain-101', '[^-]+-', '', 1, 3 )
FROM dual;
If you want ES-12345-101 then could you explain the logic for 12345 not 123456? Typo or omit the last character?
you can also use subtr and instr
with t as
(
select 'ES-123456-PSA Spain-101' as text from dual
)
select substr(text,1,instr(text,'-',1,2)) -- ES-123456-
||substr(text,instr(text,'-',1,3)+1) -- 101
from t

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 string replacement

I have a column in my oracle database which due reasons beyond my control contains a CSV string e.g.
Item a,Item b,Item c,Item d
I want to run an UPDATE statement to get rid of item c. Thus ending up with
Item a,Item b,Item d
How can I achieve this
You could use the Oracle REPLACE function:
UPDATE table
SET col = replace(col, 'item c', '')
You just need to be careful handling it as part of a CSV, e.g stripping a following comma. This could mean replacing 'item c,' first and then replacing 'item c' to capture both cases.
EDIT: ah, I might have misunderstood. My solution is based on removing a particular string from your CSV - if you are looking to always replace the 3rd item then Vincent's answer is the one you'll need
If you have a fairly recent version of Oracle (I believe regular expressions were introduced in Oracle 10), you can use REGEXP_REPLACE:
UPDATE table SET column = REGEXP_REPLACE(column,'[^\,]+,','',1,3)
(Also, please do violent things to the genius who stored CSV this way in a relational database.)
you could use a combination of INSTR and SUBSTR to remove the third field:
SQL> WITH a AS (SELECT 'Item a,Item b,Item c,Item d' col FROM dual)
2 SELECT substr(col, 1, instr(col, ',', 1, 2))
3 || substr(col, instr(col, ',', 1, 3) + 1) sub
4 FROM a;
SUB
--------------------
Item a,Item b,Item d

Resources