Splitting records which has | delimiter [closed] - sql

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm having a two columns say Value column is having records like 'abc|comp|science|raja' and I want to split this records like abc,comp,science,raja and I need to compare it with another column say CHECKER which is having record as science
Value
abc|comp|science|raja
Checkers
science

You don't need to split the string and you don't even need a regular expression; just check whether the checker string (with leading a trailing delimiters) is a sub-string of value (with leading and trailing delimiters):
Oracle Setup:
CREATE TABLE your_table ( value, checker ) as
SELECT 'abc|comp|science|raja', 'science' FROM DUAL UNION ALL
SELECT 'abc|def|ghi', 'xyz' FROM DUAL UNION ALL
SELECT 'abc', 'abc' FROM DUAL UNION ALL
SELECT 'abcdef', 'abc' FROM DUAL
Query:
SELECT *
FROM your_table
WHERE '|' || value || '|' LIKE '%|' || checker || '|%';
Output:
VALUE | CHECKER
:-------------------- | :------
abc|comp|science|raja | science
abc | abc
db<>fiddle here

You can split your pipe delimited string in individual values and represent that as a table. Then you can just join to your Checkers table.
The web is full of examples, here are 2 ways to do it.
The REGEXP way...
WITH test_tab AS
(SELECT 'abc|comp|science|raja' str FROM dual
)
SELECT regexp_substr (str, '[^|]+', 1, rownum) split
FROM test_tab
CONNECT BY LEVEL <= LENGTH (regexp_replace (str, '[^|]+')) + 1;
If you have Application Express in your database, you can use apex_string to do the magic for you:
SELECT
column_value
FROM
TABLE(apex_string.split(
'abc|comp|science|raja',
'|'
));

Here's one option:
SQL> with test (id, value, checkers) as
2 (select 1, 'abc|comp|science|raja', 'science' from dual union all
3 select 2, 'xyz|bla|nothing' , 'zzz' from dual
4 )
5 select t.id,
6 regexp_substr(t.value, '[^\|]+', 1, column_value) val,
7 column_value rn,
8 t.checkers,
9 --
10 case when regexp_substr(t.value, '[^\|]+', 1, column_value) = t.checkers then 'Match'
11 else 'No match'
12 end what
13 from test t cross join table(cast(multiset(select level from dual
14 connect by level <= regexp_count(t.value, '\|') + 1
15 ) as sys.odcinumberlist))
16 order by t.id, rn;
ID VAL RN CHECKER WHAT
---------- --------------------- ---------- ------- --------
1 abc 1 science No match
1 comp 2 science No match
1 science 3 science Match
1 raja 4 science No match
2 xyz 1 zzz No match
2 bla 2 zzz No match
2 nothing 3 zzz No match
7 rows selected.
SQL>

It sounds like you just want to check whether the checker is in the value, in that case you can do this:
with mytable as
( select 'abc|comp|science|raja' value
, 'science' as checker
from dual
union all
select 'science|abc|comp|raja'
, 'science'
from dual
union all
select 'abc|comp|raja|science'
, 'science'
from dual )
select x.value
from mytable x
where regexp_like(value, '(^|\|)' || checker || '($|\|)')
The regex_like is searching inside the value for the checker with either a pipe or the end of the string, so it will match the keyword at the beginning, in the middle or at the end of the string. But it would not match "sciences".
Alternatively if you want to see all the rows and check whether they passed the "check" you could do:
with mytable as
( select 'abc|comp|science|raja' value
, 'science' as checker
from dual
union all
select 'science|abc|comp|raja'
, 'science'
from dual
union all
select 'abc|comp|raja|science'
, 'science'
from dual
union all
select 'abc|comp|raja|sciences'
, 'science'
from dual )
select x.value
, x.checker
, case when regexp_substr(value, '(^|\|)' || checker || '($|\|)') is not null
then 'Y'
end as passed
from mytable x

Related

Remove semicolon from the end or individually

I am getting an output of one table as
FILE_NUM SNO
Read;write;Listen; 1
Listen; 2
; 3
Write;READ; 4
I want to tweak the above column such as ; at the end is removed and if only ";" is given it should be removed like
FILE_NUM SNO
Read;write;Listen 1
Listen 2
3
Write;READ 4
Use RTRIM():
SELECT RTRIM(FILE_NUM, ';') AS FILE_NUM, SNO
FROM yourTable
ORDER BY SNO;
You could also use REGEXP_REPLACE here:
SELECT REGEXP_REPLACE(FILE_NUM, ';$', '') AS FILE_NUM, SNO
FROM yourTable
ORDER BY SNO;
Right-trim it.
SQL> with test (file_num) as
2 (select 'read;write;listen;' from dual union all
3 select 'listen;' from dual union all
4 select ';' from dual union all
5 select 'write;read;' from dual
6 )
7 select file_num,
8 rtrim(file_num, ';') result
9 from test;
FILE_NUM RESULT
------------------ ------------------
read;write;listen; read;write;listen
listen; listen
;
write;read; write;read
SQL>

How do I extract the first 3 consonates from a string field SQL?

how can I extract from a field in records that contain names only the first 3 consonants and if a name does not have 3 consonants it adds the first vowel of the name?
For example, if I had the following record in the People table:
Field:Name
VALUE:Richard result=> RCH
FIELD:Name
VALUE:Paul result=> PLA
Here's one option; read comments within code.
Sample data:
SQL> with test (name) as
2 (select 'Richard' from dual union all
3 select 'Paul' from dual
4 ),
Query begins here:
5 temp as
6 -- val1 - consonants; val2 - vowels
7 (select
8 name,
9 translate(upper(name), '#AEIOU', '#') val1,
10 translate(upper(name), '#BCDFGHJKLMNPQRSTWXYZ', '#') val2
11 from test
12 )
13 -- finally: if there are enough consonants (val1's length is >= 3), return the first 3
14 -- letters (that's WHEN).
15 -- Otherwise, add as many vowels as necessary (that's what ELSE does)
16 select name,
17 case when length(val1) >= 3 then substr(val1, 1, 3)
18 else val1 || substr(val2, 1, 3 - length(val1))
19 end result
20 from temp;
NAME RESULT
------- --------------
Richard RCH
Paul PLA
SQL>
Just for fun using regexp:
select
name
,substr(
regexp_replace(
upper(name)
,'^([AEIOU]*)([^AEIOU]*)([AEIOU]*)([^AEIOU]*)([AEIOU]*)([^AEIOU]*).*'
,'\2\4\6\1\3\5'
),1,3) as result
from test;
([AEIOU]*) - is a group of vowels, 0 or more characters
([^AEIOU]*) - is a group of not-vowels (or consonants in this case), 0 or more characters
so this regexp looks for a pattern (vowels1)(consonants1)(vowels2)(consonants2)(vowels3)(consonants3) and reorders it to (consonants1)(consonants2)(consonants3)(vowels1)(vowels2)(vowels3)
then we just take first 3 characters from the reordered string
Full test case:
with test (name) as
(select 'Richard' from dual union all
select 'Paul' from dual union all
select 'Annete' from dual union all
select 'Anny' from dual union all
select 'Aiua' from dual union all
select 'Isaiah' from dual union all
select 'Sue' from dual
)
select
name
,substr(
regexp_replace(
upper(name)
,'^([AEIOU]*)([^AEIOU]*)([AEIOU]*)([^AEIOU]*)([AEIOU]*)([^AEIOU]*).*'
,'\2\4\6\1\3\5'
),1,3) as result
from test;
NAME RESULT
------- ------------
Richard RCH
Paul PLA
Annete NNT
Anny NNY
Aiua AIU
Isaiah SHI
Sue SUE
7 rows selected.

SUBSTR to ADD value in oracle

I have table with column having data in below format in Oracle DB.
COL 1
abc,mno:EMP
xyz:EMP;tyu,opr:PROF
abc,mno:EMP;tyu,opr:PROF
I am trying to convert the data in below format
COL 1
abc:EMP;mno:EMP
xyz:EMP;tyu:PROF;opr:PROF
abc:EMP;mno:EMP;tyu:PROF;opr:PROF
Basically trying to get everything after : and before ; to move it substitute comma with it.
I tried some SUBSTR and LISTAGG but couldn't get anything worth sharing.
Regards.
Here's one option; read comments within code.
SQL> with test (id, col) as
2 -- sample data
3 (select 1, 'abc,mno:EMP' from dual union all
4 select 2, 'xyz:EMP;tyu,opr:PROF' from dual union all
5 select 3, 'abc,mno:EMP;tyu,opr:PROF' from dual
6 ),
7 temp as
8 -- split sample data to rows
9 (select id,
10 column_value cv,
11 regexp_substr(col, '[^;]+', 1, column_value) val
12 from test cross join
13 table(cast(multiset(select level from dual
14 connect by level <= regexp_count(col, ';') + 1
15 ) as sys.odcinumberlist))
16 )
17 -- finally, replace comma with a string that follows a colon sign
18 select id,
19 listagg(replace(val, ',', substr(val, instr(val, ':')) ||';'), ';') within group (order by cv) new_val
20 from temp
21 group by id
22 order by id;
ID NEW_VAL
---------- ----------------------------------------
1 abc:EMP;mno:EMP
2 xyz:EMP;tyu:PROF;opr:PROF
3 abc:EMP;mno:EMP;tyu:PROF;opr:PROF
SQL>
Using the answer of littlefoot, if i were to use cross apply i wouldnt need to cast as multiset...
with test (id, col) as
-- sample data
(select 1, 'abc,mno:EMP' from dual union all
select 2, 'xyz:EMP;tyu,opr:PROF' from dual union all
select 3, 'abc,mno:EMP;tyu,opr:PROF' from dual
),
temp as
-- split sample data to rows
(select id,
column_value cv,
regexp_substr(col, '[^;]+', 1, column_value) val
from test
cross apply (select level as column_value
from dual
connect by level<= regexp_count(col, ';') + 1)
)
-- finally, replace comma with a string that follows a colon sign
select id,
listagg(replace(val, ',', substr(val, instr(val, ':')) ||';'), ';') within group (order by cv) new_val
from temp
group by id
order by id;
You do not need recursive anything, just basic regex: if the pattern is always something,something2:someCode (e.g. you have no colon before the comma), then it would be sufficient.
with test (id, col) as (
select 1, 'abc,mno:EMP' from dual union all
select 2, 'xyz:EMP;tyu,opr:PROF' from dual union all
select 3, 'abc,mno:EMP;tyu,opr:PROF' from dual union all
select 3, 'abc,mno:EMP;tyu,opr:PROF;something:QWE;something2:QWE' from dual
)
select
/*
Grab this groups:
1) Everything before the comma
2) Then everything before the colon
3) And then everything between the colon and a semicolon
Then place group 3 between 1 and 2
*/
trim(trailing ';' from regexp_replace(col || ';', '([^,]+),([^:]+):([^;]+)', '\1:\3;\2:\3')) as res
from test
| RES |
| :------------------------------------------------------------- |
| abc:EMP;mno:EMP |
| xyz:EMP;tyu:PROF;opr:PROF |
| abc:EMP;mno:EMP;tyu:PROF;opr:PROF |
| abc:EMP;mno:EMP;tyu:PROF;opr:PROF;something:QWE;something2:QWE |
db<>fiddle here

Oracle SQL - How to Cut out characters from a string with SUBSTR?

I have values like "ABC1234", "ABC", "DEF456", "GHI" etc. in a specific column which I need.
Now I need to split this string but only if the character (e.g. "ABC") are followed by digits.
So if the value is "ABC1234" then I need to cut out ABC and 1234 seperated. But if there is only "ABC" as a value, I just need the "ABC". I can't find any solution with SUBSTR. Do you have any idea?
Note: The length of the characters can differ from 1 to 10 and also the length from the digits (sometimes there isn't any like I showed you).
So if the value is "ABC1234" then I need to cut out ABC and 1234
seperated. But if there is only "ABC" as a value, I just need the
"ABC".
Amidst of other solutions, I propose one solution as shown below:
Logic:
1) Replace all the digits to 1. Check the position of the digit occurring in the string. If
there is no digit in the string then use the String.
2) Extract the alphabets from 1st position to the position where
digit starts.
3) Extract the digit from the position it starts till end. If digit doesnot exists the set it NULL
--Dataset Preparation
with test (col) as
(select 'ABC1234' from dual union all
select 'ABC' from dual union all
select 'dEfH456' from dual union all
select '123GHI' from dual union all
select '456' from dual
)
--Query
select col Original_Column,
CASE
WHEN (instr(regexp_replace(col,'[0-9]','1'),'1',1)) = 0
then col
else
substr( col,1,instr(regexp_replace(col,'[0-9]','1'),'1',1)-1)
end Col_Alp,
CASE
WHEN (instr(regexp_replace(col,'[0-9]','1'),'1',1)) = 0
then NULL
Else
substr( col,instr(regexp_replace(col,'[0-9]','1'),'1',1))
END col_digit
from test
where regexp_like(col, '^[a-zA-Z0-9]+$');
Result:
SQL> /
Original_Column Col_Alp col_digit
---------- ----- -----
ABC1234 ABC 1234
ABC ABC NULL
dEfH456 dEfH 456
123GHI NULL 123GHI
456 NULL 456
Using SUBSTR (and INSTR and TRANSLATE):
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE data ( value ) AS
SELECT 'ABC1234' FROM DUAL UNION ALL
SELECT 'ABC123D' FROM DUAL UNION ALL
SELECT 'ABC ' FROM DUAL UNION ALL
SELECT 'ABC' FROM DUAL UNION ALL
SELECT 'DEFG456' FROM DUAL UNION ALL
SELECT 'GHI' FROM DUAL UNION ALL
SELECT 'JKLMNOPQRS9' FROM DUAL;
Query 1:
SELECT value,
SUBSTR( value, 1, first_digit - 1 ) AS prefix,
TO_NUMBER( SUBSTR( value, first_digit ) ) AS suffix
FROM (
SELECT value,
INSTR(
TRANSLATE( value, '-1234567890', ' ----------' ),
'-',
1
) AS first_digit
FROM data
)
WHERE SUBSTR( value, first_digit ) IS NOT NULL
AND TRANSLATE( SUBSTR( value, first_digit ), '-1234567890', ' ' ) IS NULL
Results:
| VALUE | PREFIX | SUFFIX |
|-------------|------------|--------|
| ABC1234 | ABC | 1234 |
| DEFG456 | DEFG | 456 |
| JKLMNOPQRS9 | JKLMNOPQRS | 9 |
Try this below query for scenarios mentioned , I didn't split if characters followed by numbers:
with test (col) as
(select 'ABC1234' from dual union all
select 'ABC' from dual union all
select 'dEfH456' from dual union all
select '123GHI' from dual union all
select '456' from dual
)
select col,reverse(trim(regexp_replace(reverse(col),'^[0-9]+',' '))) string ,trim(regexp_replace(col,'^[a-zA-Z]+',' ')) numbers from test
if like to move that characters&string to any place my case statement
with test (col) as
(select 'ABC1234' from dual union all
select 'ABC' from dual union all
select 'dEfH456' from dual union all
select '123GHI' from dual union all
select '456' from dual
)
select v.col,case when v.string=v.numbers THEN NULL ELSE string end string , v.numbers
from (select col,reverse(trim(regexp_replace(reverse(col),'^[0-9]+',' '))) string ,trim(regexp_replace(col,'^[a-zA-Z]+',' ')) numbers from test) v
Would something like this do?
SQL> with test (col) as
2 (select '"ABC1234", "ABC", "dEf456", "123GHI", "456"' from dual),
3 inter as
4 (select trim(regexp_substr(replace(col, '"', ''), '[^,]+', 1, level)) token
5 from test
6 connect by level <= regexp_count(col, ',') + 1
7 )
8 select regexp_substr(token, '^[a-zA-Z]+') letters,
9 regexp_substr(token, '[0-9]+$') digits
10 from inter
11 where regexp_like(token, '^[a-zA-Z]+[0-9]+$');
LETTERS DIGITS
---------- ----------
ABC 1234
dEf 456
SQL>

Comma separated string to list [duplicate]

This question already has answers here:
split string into several rows
(3 answers)
Closed 6 years ago.
I have a string which as values as below:
Countries = USA, Canada, Italy
I would like to seperate them and display it as list like below
Countries
USA
Canada
Italy
How can I do this using SQL?
There are multiple solutions posted in the Splitting Delimited Strings topic of the Oracle documentation pages.
One is:
Sample Data:
CREATE TABLE table_name ( id, list ) AS
SELECT 1, 'a,b,c,d' FROM DUAL UNION ALL -- Multiple items in the list
SELECT 2, 'e' FROM DUAL UNION ALL -- Single item in the list
SELECT 3, NULL FROM DUAL UNION ALL -- NULL list
SELECT 4, 'f,,g' FROM DUAL; -- NULL item in the list
Query:
SELECT t.id,
v.COLUMN_VALUE AS value,
ROW_NUMBER() OVER ( PARTITION BY id ORDER BY ROWNUM ) AS lvl
FROM table_name t,
TABLE(
CAST(
MULTISET(
SELECT REGEXP_SUBSTR( t.list, '([^,]*)(,|$)', 1, LEVEL, NULL, 1 )
FROM DUAL
CONNECT BY LEVEL < REGEXP_COUNT( t.list, '[^,]*(,|$)' )
)
AS SYS.ODCIVARCHAR2LIST
)
) v;
Output:
ID ITEM LVL
---------- ------- ----------
1 a 1
1 b 2
1 c 3
1 d 4
2 e 1
3 (NULL) 1
4 f 1
4 (NULL) 2
4 g 3
You can use a regex_substr and a connect by
select regexp_substr( 'USA, Canada, Italy','[^,]+', 1, level) from dual
connect by regexp_substr('USA, Canada, Italy', '[^,]+', 1, level) is not null;