regexp_like to find 10 occurrences of 0's - sql

with smpl as
(
select '000-000-0000' num from dual union
select '0000000000' from dual union
select '00000000000' from dual
)
select * from smpl
where regexp_like(num, '0{10}');
Output:
0000000000
00000000000
How to get records with 10 occurences 0's with optional '-'
Expected:
0000000000
000-000-0000

Use TRANSLATE to strip out the unwanted characters and then LENGTH
with smpl as
(
select '000-000-0000' num from dual union
select '0000000000' from dual union
select '000000000' from dual union
select '00000000000' from dual
)
select * from smpl
where LENGTH( TRANSLATE( num, '0-', '0' ) ) = 10
or compare to 0000000000:
with smpl as
(
select '000-000-0000' num from dual union
select '0000000000' from dual union
select '000000000' from dual union
select '00000000000' from dual
)
select * from smpl
where TRANSLATE( num, '0-', '0' ) = '0000000000'
Outputs:
| NUM |
| :----------- |
| 000-000-0000 |
| 0000000000 |
db<>fiddle here

I want to point out that you can do this strictly with regular expressions. If you are looking for the pattern anywhere in the string:
where regexp_like(num, '(\-*0){10}')
If you are looking for only that pattern in the string:
where regexp_like(num, '^(\-*0){10}\-*$')

With regexp, this is an easy way:
where regexp_count(num, '0') = 10
However, if the only character different from '0' is a '-', I would prefer the non-regexp solution

Related

Sort string and number combination in descending in oralce

I am trying to sort a combination of string and number in descending order .
Input :
P9S1
P7S1
P13S1
P12S2
P10S1
Expected output:
P13S1
P12S2
P10S1
P9S1
P7S1
Here is what I tried
Sample code:
with
inputs (firmware) as (
select 'P9S1' from dual union all
select 'P7S1' from dual union all
select 'P13S1' from dual union all
select 'P12S2' from dual union all
select 'P10S1' from dual
)
select firmware
from inputs
order by
regexp_replace(firmware, '\d+\.\d+') desc ;
But this doesn't work as expected. Any help would be appreciated.
Thanks
You did not actually explain how the strings should turned to numbers.
This would work for your dataset:
order by to_number(regexp_replace(firmware, '\D', '')) desc
The idea is to remove all non-digits characters from the string, turn the resulting string to a number, and use it for sorting.
with inputs (firmware) as (
select 'P9S1' from dual union all
select 'P7S1' from dual union all
select 'P13S1' from dual union all
select 'P12S2' from dual union all
select 'P10S1' from dual
)
select firmware
from inputs
order by to_number(regexp_replace(firmware, '\D', '')) desc ;
| FIRMWARE |
| :------- |
| P13S1 |
| P12S2 |
| P10S1 |
| P9S1 |
| P7S1 |

How to convert vertical string into horizontal in Oracle

O
N
K
A
R
how to convert it into ONKAR. reverse of it I know. But this I am not able to solve.
You can't do what you want generally without also having a second column which provides the ordering for each letter. Assuming you do have a column for the position, we can try:
SELECT LISTAGG(letter, '') WITHIN GROUP (ORDER BY position) word
FROM yourTable;
Demo
Data:
letter | position
O | 1
N | 2
K | 3
A | 4
R | 5
Listagg is right solution for strings up to 4000 bytes cuz it returns varchar2 data type. But for longer strings you may get clob data type.
with s (letter, position) as (
select 'O', 1 from dual union all
select 'N', 2 from dual union all
select 'K', 3 from dual union all
select 'A', 4 from dual union all
select 'R', 5 from dual)
select xmlcast(xmlagg(xmlelement(x, letter) order by position) as clob) c
from s;
C
---------------
ONKAR
You can use this as long as data result has all rows that you want to stick together.
with data as (select 'O' as letter from dual
union all
select 'N' from dual
union all
select 'K' from dual
union all
select 'A' from dual
union all
select 'R' from dual)
SELECT LISTAGG(letter, '') WITHIN GROUP (ORDER BY rownum)
FROM data;
If your data is in a single row separated by newline (ASCII 13) characters then you can just use REPLACE( value, CHR(13) ):
Oracle Setup:
CREATE TABLE test_data ( value ) AS
SELECT 'O' || CHR(13) || 'N' || CHR(13) || 'K' || CHR(13) || 'A' || CHR(13) || 'R' FROM DUAL
Query:
SELECT value, REPLACE( value, CHR(13) ) FROM test_data
Output:
VALUE | REPLACE(VALUE,CHR(13))
:-------- | :---------------------
O | ONKAR
N |
K |
A |
R |
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>

How to replace comma separated text values in a column in Oracle?

I have a table t1 with a varchar col V_RELNIST_SKEY which contains comma separated numbers between 1 and 12 as shown. I want to write a select statement to replace numbers by string. For e.g., value 5,6 should be replaced by five,six and so on.
|V_RELNIST_SKEY|
|6 |
|5,6 |
|1,12 |
|1,2,3,12 |
Oracle Setup:
CREATE TABLE test_data ( value ) as
SELECT '9' FROM DUAL UNION ALL
SELECT '6' FROM DUAL UNION ALL
SELECT '1' FROM DUAL UNION ALL
SELECT '2,3' FROM DUAL UNION ALL
SELECT '5,6,7' FROM DUAL UNION ALL
SELECT '8,4' FROM DUAL UNION ALL
SELECT '1,2,3,4,5,6,7,8,9,10,11,12' FROM DUAL;
Query:
SELECT value,
column_value AS words
FROM test_data t
CROSS JOIN
TABLE(
CAST(
MULTISET(
SELECT LISTAGG(
TO_CHAR(
TO_DATE(
REGEXP_SUBSTR( t.value, '\d+', 1, LEVEL ),
'J'
),
'JSP'
),
','
) WITHIN GROUP ( ORDER BY LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( t.value, '\d+' )
) AS SYS.ODCIVARCHAR2LIST
)
) w;
Output:
VALUE WORDS
-------------------------- ----------------------------------------
9 NINE
6 SIX
1 ONE
2,3 TWO,THREE
5,6,7 FIVE,SIX,SEVEN
8,4 EIGHT,FOUR
1,2,3,4,5,6,7,8,9,10,11,12 ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,
NINE,TEN,ELEVEN,TWELVE
Update
What if I have to replace 1 with A, 2 with B, 3 with C and so on?
SELECT value,
COLUMN_VALUE AS words
FROM test_data t
CROSS JOIN
TABLE(
CAST(
MULTISET(
SELECT LISTAGG(
CHR( 64 + REGEXP_SUBSTR( t.value, '\d+', 1, LEVEL ) ),
','
) WITHIN GROUP ( ORDER BY LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( t.value, '\d+' )
) AS SYS.ODCIVARCHAR2LIST
)
) w;
Output:
VALUE WORDS
-------------------------- ----------------------------------------
9 I
6 F
1 A
2,3 B,C
5,6,7 E,F,G
8,4 H,D
1,2,3,4,5,6,7,8,9,10,11,12 A,B,C,D,E,F,G,H,I,J,K,L

Oracle SQL : Regexp_substr

I have below sample values in a column
Abc-123-xyz
Def-456-uvw
Ghi-879-rst-123
Jkl-abc
Expected output is the third element split by '-', in case there is no third element, the last element will be retrieve.
See expected output below:
Xyz
Uvw
Rst
Abc
Thanks ahead for the help.
SELECT initcap(nvl(regexp_substr(word, '[^-]+', 1,3),regexp_substr(word, '[^-]+', 1,2))) FROM your_table;
Another approach:
SQL> with t1(col) as(
2 select 'Abc-123-xyz' from dual union all
3 select 'Def-456-uvw' from dual union all
4 select 'Ghi-879-rst-123' from dual union all
5 select 'Jkl-Abc' from dual
6 )
7 select regexp_substr( col
8 , '[^-]+'
9 , 1
10 , case
11 when regexp_count(col, '[^-]+') >= 3
12 then 3
13 else regexp_count(col, '[^-]+')
14 end
15 ) as res
16 from t1
17 ;
Result:
RES
---------------
xyz
uvw
rst
Abc
regexp_substr(column, '(.*?-){0,2}([^-]+)', 1, 1, '', 2)
You can also do it without RegEx:
with t1 as(
select 'Abc-123-xyz' as MyText from dual union all
select 'Def-456-uvw' from dual union all
select 'Ghi-879-rst-123' from dual union all
select 'Jkl-Abc' from dual
)
SELECT
SUBSTR(t1.mytext, LENGTH(t1.mytext) - INSTR(REVERSE(t1.mytext), '-') + 2)
FROM t1
;