Oracle query to replace same character with different characters based on position - sql

I have a string in Oracle DB in the format 'a|b|c' , '|' being the separator between characters. Want to write an SQL query to transform it into a string in the format 'a,b&c'. First occurrence of '|' to ',' 2nd occurrence to '&'.
If suppose the string comes in the format 'a|b' then output should be 'a&b'.
I'm using multiple regex_replace queries to achieve this right now.
select REGEXP_REPLACE ('a|b|c', '[|]', ',', 1, 1)
from dual
Is there any other solution using one single query?

Nested replaces (see line #6):
SQL> with test (col) as
2 (select 'a|b|c' from dual union all
3 select 'a|b' from dual
4 )
5 select col,
6 regexp_replace(regexp_replace(col, '\|', ',', 1, 1), '\|', '&', 2, 1) result
7 from test;
COL RESULT
----- --------------------
a|b|c a,b&c
a|b a,b
SQL>

If you want to replace the last | in the list with & and all the preceding |s with , then you can use:
SELECT value,
REPLACE(
REGEXP_REPLACE( value, '\|([^|]*)$', '&\1' ),
'|',
','
) AS replaced
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT 'A|B|C|D' FROM DUAL UNION ALL
SELECT 'A|B|C' FROM DUAL UNION ALL
SELECT 'A|B' FROM DUAL UNION ALL
SELECT 'A' FROM DUAL;
Outputs:
VALUE
REPLACED
A|B|C|D
A,B,C&D
A|B|C
A,B&C
A|B
A&B
A
A
fiddle

Related

Oracle REGEXP_REPLACE function to find decimal and special characters

I am working with table data that contains strings with decimal and back-slash like below:
info
1/2.2.2
2/1.1.1
3/1.1.11
I need to use a regular expression to replace the data like below:
info
1/2.2
2/1.1
3/1.1
Don't use a (slow) regular expression, use simple (faster) string functions instead:
SELECT info,
CASE
WHEN INSTR(info, '.', 1, 2) > 0
THEN SUBSTR(info, 1, INSTR(info, '.', 1, 2) - 1)
ELSE info
END AS part
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (info) AS
SELECT '1/2.2.2' FROM DUAL UNION ALL
SELECT '2/1.1.1' FROM DUAL UNION ALL
SELECT '3/1.1.11' FROM DUAL UNION ALL
SELECT '3/1.1' FROM DUAL;
Outputs:
INFO
PART
1/2.2.2
1/2.2
2/1.1.1
2/1.1
3/1.1.11
3/1.1
3/1.1
3/1.1
If you want to update the table then:
UPDATE table_name
SET info = SUBSTR(info, 1, INSTR(info, '.', 1, 2) - 1)
WHERE INSTR(info, '.', 1, 2) > 0
fiddle
For the sake of argument, here's a solution using REGEXP_SUBSTR(). REGEXP_SUBSTR() returns NULL if the pattern is not found. Thanks to MT0 for the CTE so I didn't have to type it up :-)
WITH table_name(ID, info) AS (
SELECT 1, '1/2.2.2' FROM DUAL UNION ALL
SELECT 2, '2/1.1.1' FROM DUAL UNION ALL
SELECT 3, '3/1.1.11' FROM DUAL UNION ALL
SELECT 4, '3/1.1' FROM DUAL UNION ALL
SELECT 5, '4/4' FROM DUAL)
SELECT ID, REGEXP_SUBSTR(info, '\d/\d\.\d') DATA
from table_name;
ID DATA
---------- --------
1 1/2.2
2 2/1.1
3 3/1.1
4 3/1.1
5
5 rows selected.

regexp match character before a specify string (not include)

REGEXP_SUBSTR(label) ,'.*_dis')
this is for sql;
my database is mysql
select REGEXP_SUBSTR(label) ,'.*_dis') as dis ,
substr(label,length(label))-1) as num
from table
table.lable col's data:
1. a_b_dis_12
2. a_dis_13
3. c_d_dis_23
3. c_dis_22
i want to get the character before '_dis' and the numeric part use regexp
1.a_b 12
2.a 13
3.c_d 23
4.c 22
thanks a lot!
You can use regexp_substr as follows:
Select regexp_substr(your_column, '^(.*)_dis_[0-9]+$',1,1,null,1) as dis,
Regexp_substr(your_column, '[0-9]+$') as num
From your table
You can use regexp_replace():
select regexp_replace(col, '^(.*)_dis.*$', '\1'),
regexp_replace(col, '^.*_dis_([0-9]+)', '\1')
from (select 'a_b_dis_12' as col from dual union all
select 'a_dis_13' as col from dual union all
select 'c_d_dis_23' as col from dual union all
select 'c_dis_22' as col from dual
) t;
Here is a db<>fiddle.
I would use regexp_replace() as follows:
select
regexp_replace(label, '_dis_.*$', '') dis,
regexp_replace(label, '^.*_dis_', '') num
from mytable
The first expression suppresses everything from '_dis_ (included) to the end of the string. The second expression removes everything from the beginning of the string until '_dis_' (included).

Extracting substring in Oracle

Let's say I have three rows with value as
1 121/2808B|:6081
2 OD308B|:6081_1:
3 008312100001200|:6081_1
I want to display value only until B but want to exclude everything after B. So as you can see in above data:
from 121/2808B|:6081 I want only 121/2808B
from OD308B|:6081_1: only OD308B
from 008312100001200|:6081_1 only 008312100001200.
Thanks for the Help.
Try this: regexp_substr('<Your_string>','[^B]+')
SELECT
REGEXP_SUBSTR('121/2808B|:6081', '[^B]+')
FROM
DUAL;
REGEXP_S
--------
121/2808
SELECT
REGEXP_SUBSTR('OD308B|:6081_1:', '[^B]+')
FROM
DUAL;
REGEX
-----
OD308
SELECT
REGEXP_SUBSTR('008312100001200.', '[^B]+')
FROM
DUAL;
REGEXP_SUBSTR('0
----------------
008312100001200.
db<>fiddle demo
Cheers!!
You could try using SUBSTR() and INSTR()
select SUBSTR('121/2808B|:6081',1,INSTR('121/2808B|:6081','B', 1, 1) -1)
from DUAL
I think you forgot to mention that you wanted to use | as a field separator, but I deduced this from the expected result from the third string. As such the following should give you what you want:
WITH cteData AS (SELECT 1 AS ID, '121/2808B|:6081' AS STRING FROM DUAL UNION ALL
SELECT 2, 'OD308B|:6081_1:' FROM DUAL UNION ALL
SELECT 3, '008312100001200|:6081_1' FROM DUAL)
SELECT ID, STRING, SUBSTR(STRING, 1, CASE
WHEN INSTR(STRING, 'B') = 0 THEN INSTR(STRING, '|')-1
ELSE INSTR(STRING, 'B')-1
END) AS UP_TO_B
FROM cteData;
dbfiddle here
Assuming Bob Jarvis is correct in the assumption that "|" is also a delimiter (as seems likely) try:
-- define test data
with test as
( select '121/2808B|:6081' stg from dual union all
select 'OD308B|:6081_1:' from dual union all
select '008312100001200|:6081_1' from dual
)
-- execute extract
select regexp_substr(stg , '[^B|]+') val
from test ;

Retrieve certain number from data set in Oracle 10g

1. <0,0><120.96,2000><241.92,4000><362.88,INF>
2. <0,0><143.64,2000><241.92,4000><362.88,INF>
3. <0,0><125.5,2000><241.92,4000><362.88,INF>
4. <0,0><127.5,2000><241.92,4000><362.88,INF>
Above is the data set I have in Oracle 10g. I need output as below
1. 120.96
2. 143.64
3. 125.5
4. 125.5
the output I want is only before "comma" (120.96). I tried using REGEXP_SUBSTR but I could not get any output. It will be really helpful if someone could provide effective way to solve this
Here is one method that first parses out the second element and then gets the first number in it:
select regexp_substr(regexp_substr(x, '<[^>]*>', 1, 2), '[0-9.]+', 1, 1)
Another method just gets the third number in the string:
select regexp_substr(x, '[0-9.]+', 1, 3)
Here is an approach without using Regexp.
Find the index of second occurrence of '<'. Then find the second occurrence of ',' use those values in substring.
with
data as
(
select '<0,0><120.96,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><143.64,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual
)
select substr(x, instr(x,'<',1,2)+1, instr(x,',',1,2)- instr(x,'<',1,2)-1)
from data
Approach Using Regexp:
Identify the 2nd occurence of numerical value followed by a comma
Then remove the trailing comma.
with
data as
(
select '<0,0><120.96,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><143.64,2000><241.92,4000><362.88,INF>' x from dual
UNION ALL
select '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual
)
select
trim(TRAILING ',' FROM regexp_substr(x,'[0-9.]+,',1,2))
from data
This example uses regexp_substr to get the string contained within the 2nd occurance of a less than sign and a comma:
SQL> with tbl(id, str) as (
select 1, '<0,0><120.96,2000><241.92,4000><362.88,INF>' from dual union
select 2, '<0,0><143.64,2000><241.92,4000><362.88,INF>' from dual union
select 3, '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual union
select 4, '<0,0><127.5,2000><241.92,4000><362.88,INF>' from dual
)
select id,
regexp_substr(str, '<(.*?),', 1, 2, null, 1) value
from tbl;
ID VALUE
---------- -------------------------------------------
1 120.96
2 143.64
3 125.5
4 127.5
EDIT: I realized the OP specified 10g and the regexp_substr example I gave used the 6th argument (subgroup) which was added in 11g. Here is an example using regexp_replace instead which should work with 10g:
SQL> with tbl(id, str) as (
select 1, '<0,0><120.96,2000><241.92,4000><362.88,INF>' from dual union
select 2, '<0,0><143.64,2000><241.92,4000><362.88,INF>' from dual union
select 3, '<0,0><125.5,2000><241.92,4000><362.88,INF>' from dual union
select 4, '<0,0><127.5,2000><241.92,4000><362.88,INF>' from dual
)
select id,
regexp_replace(str, '^(.*?)><(.*?),.*$', '\2') value
from tbl;
ID VALUE
---------- ----------
1 120.96
2 143.64
3 125.5
4 127.5
SQL>

SQL Query to show string before a dash

I would like to execute a query that will only show all the string before dash in the particular field.
For example:
Original data: AB-123
After query: AB
You can use substr:
SQL> WITH DATA AS (SELECT 'AB-123' txt FROM dual)
2 SELECT substr(txt, 1, instr(txt, '-') - 1)
3 FROM DATA;
SUBSTR(TXT,1,INSTR(TXT,'-')-1)
------------------------------
AB
or regexp_substr (10g+):
SQL> WITH DATA AS (SELECT 'AB-123' txt FROM dual)
2 SELECT regexp_substr(txt, '^[^-]*')
3 FROM DATA;
REGEXP_SUBSTR(TXT,'^[^-]*')
---------------------------
AB
You can use regexp_replace.
For example
WITH DATA AS (
SELECT 'AB-123' as text FROM dual
UNION ALL
SELECT 'ABC123' as text FROM dual
)
SELECT
regexp_replace(d.text, '-.*$', '') as result
FROM DATA d;
will lead to
WITH DATA AS (
2 SELECT 'AB-123' as text FROM dual
3 UNION ALL
4 SELECT 'ABC123' as text FROM dual
5 )
6 SELECT
7 regexp_replace(d.text, '-.*$', '') as result
8 FROM DATA d;
RESULT
------------------------------------------------------
AB
ABC123
I found this simple
SELECT distinct
regexp_replace(d.pyid, '-.*$', '') as result
FROM schema.table d;
pyID column contains ABC-123, DEF-3454
SQL Result:
ABC
DEF