How to get number between special character in oracle - sql

Can you help to get below output in oracle
File_20170902_Name.txt
File200_Name_20170902_1.txt
File400_20170902_Name_1.txt
File1_name_20170902.txt
I am expecting output like
20170902
20170902
20170902
20170902
Thanks in advance!!

Assuming that all the 8 digit numbers in your filenames are dates and are preceded by a _ and followed by an _ or .txt, you may use
select REGEXP_SUBSTR(files,'_(\d{8})(_|.txt)',1,1,NULL,1) as dt FROM t;
Demo
But some time number character will change like 6 (YYMMDD) character
This will match a sequence of 6 to 8 characters between _ or _ and .txt
REGEXP_SUBSTR(files,'_((\d{6,8}))(_|)',1,1,NULL,1)
Demo2
But, This isn't a comprehensive regex to match dates. i.e it could match digits like 20189999 or 180000 if they are part of filename. if you want to detect only dates, then you may have to combine them with methods specified here: Valid Date Checks in Oracle

Try this demo: http://sqlfiddle.com/#!4/c361c/4
select
regexp_replace(str,'.*(\d{8}).*','\1') as x
from table1
| X |
|----------|
| 20170902 |
| 20170902 |
| 20170902 |
| 20170902 |

Try this
create table tst (x varchar2(30));
insert into tst values ('File_20170902_Name.txt');
insert into tst values ('File200_Name_20170902_1.txt');
insert into tst values ('File400_20170902_Name_1.txt');
insert into tst values ('File1_name_20170902.txt');
Select x,
case
when substr(x, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]') + 1, 1) between chr(48) and chr(57) Then
substr(x, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]') + 1, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 2) - REGEXP_INSTR(x, '[^a-z|A-Z|0-9]') - 1)
else substr(x, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 2) + 1, REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 3) - REGEXP_INSTR(x, '[^a-z|A-Z|0-9]', 1, 2) - 1)
end as t
From tst
Note: this query wont support if the number start after more than 2 special character like File_name_test_20170902.txt

The following both work about the same - the use a regular expression to make the basic selection, then make use of either a second call to REGEXP_SUBSTR or use "normal" string functions to get rid of the delimiters. I prefer the nested calls to REGEXP_SUBSTR over the use of TRANSLATE or REPLACE but you can take your pick:
Nested calls to REGEXP_SUBSTR:
WITH cteFiles AS (SELECT 'File_20170902_Name.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File200_Name_20170902_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File400_20170902_Name_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File1_name_20170902.txt' AS FILENAME FROM DUAL)
SELECT FILENAME, REGEXP_SUBSTR(REGEXP_SUBSTR(FILENAME, '_[0-9]+[_.]'), '[^_.]+') AS FINAL_NUMS
FROM cteFiles;
Using REPLACE:
WITH cteFiles AS (SELECT 'File_20170902_Name.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File200_Name_20170902_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File400_20170902_Name_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File1_name_20170902.txt' AS FILENAME FROM DUAL)
SELECT FILENAME, REPLACE(REPLACE(REGEXP_SUBSTR(FILENAME, '_[0-9]+[_.]'), '_', NULL), '.', NULL) AS FINAL_NUMS
FROM cteFiles;
Using TRANSLATE:
WITH cteFiles AS (SELECT 'File_20170902_Name.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File200_Name_20170902_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File400_20170902_Name_1.txt' AS FILENAME FROM DUAL UNION ALL
SELECT 'File1_name_20170902.txt' AS FILENAME FROM DUAL)
SELECT FILENAME, TRANSLATE(REGEXP_SUBSTR(FILENAME, '_[0-9]+[_.]'), '0123456789_.', '0123456789') AS FINAL_NUMS
FROM cteFiles;
SQLFiddle here
Best of luck.

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.

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

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

how to find the same two-digit numbers in a sequence of characters regular expressions SQL

I would like to print out strings of characters in which at least two numbers are repeated in SQL
EX
11-22-33
11-22-44
22-22-33
55-22-33
11-66-33
11-88-33
33-88-33
77-77-22
OUTPUT :
22-22-33
77-77-22
33-88-33
But I have no idea how to write a regular expression that would help me
For this fixed format of NN-NN-NN, you could just use string functions and test the three possible combinations:
select *
from mytable
where substr(val, 1, 2) = substr(val, 3, 2)
or substr(val, 1, 2) = substr(val, 5, 2)
or substr(val, 3, 2) = substr(val, 5, 2)
We could get a little fancy and use a lateral join instead of the repeating or conditions. This scales better if you have more than 3 parts (the number of combinations increases rapidly, which makes the or solution less convinient):
select t.*
from mytable t
cross apply (
select count(distinct part) cnt_distinct_part
from (
select substr(t.val, 1, 2) part
union all select substr(t.val, 3, 2)
union all select substr(t.val, 5, 2)
) x
) x
where x.cnt_distinct_part < 3
You can use the regular expression (^|-)(\d+)(-\d+)*-\2(-|$) to match pairs of numbers of any number of digits or number of terms.
(^|-) matches either the start-of-the-string ^ or a hyphen - contained in the first capturing group ();
followed by one-or-more digit characters \d+ contained in the second capturing group () to match the first of the pair of the numbers;
then a third capturing group () which is matched zero-or-more times * containing a - followed by one-or-more digits \d+ to match any amount of numbers between the pair of matched numbers;
then a hyphen -;
then a duplicate of the second capturing group \2 which will match the second of the pair of numbers;
then either a hyphen - or the end-of-the-string $
Giving the query:
SELECT value
FROM table_name
WHERE REGEXP_LIKE( value, '(^|-)(\d+)(-\d+)?-\2(-|$)' );
Which, for the sample data:
CREATE TABLE table_name ( value ) AS
SELECT '11-22-33' FROM DUAL UNION ALL
SELECT '11-22-44' FROM DUAL UNION ALL
SELECT '22-22-33' FROM DUAL UNION ALL
SELECT '55-22-33' FROM DUAL UNION ALL
SELECT '11-66-33' FROM DUAL UNION ALL
SELECT '11-88-33' FROM DUAL UNION ALL
SELECT '33-88-33' FROM DUAL UNION ALL
SELECT '77-77-22' FROM DUAL UNION ALL
SELECT '11-77-77' FROM DUAL UNION ALL
SELECT '11-177-77' FROM DUAL UNION ALL
SELECT '11-77-771' FROM DUAL UNION ALL
SELECT '123-456-123' FROM DUAL UNION ALL
SELECT '1-2-2' FROM DUAL UNION ALL
SELECT '99999-99999-0' FROM DUAL UNION ALL
SELECT '1-2-3-4-5-6-7-8-9-0-11-2-13' FROM DUAL;
Outputs:
| VALUE |
| :-------------------------- |
| 22-22-33 |
| 33-88-33 |
| 77-77-22 |
| 11-77-77 |
| 123-456-123 |
| 1-2-2 |
| 99999-99999-0 |
| 1-2-3-4-5-6-7-8-9-0-11-2-13 |
db<>fiddle here

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 ;

Get substring with REGEXP_SUBSTR

I need to use regexp_substr, but I can't use it properly
I have column (l.id) with numbers, for example:
1234567891123!123 EXPECTED OUTPUT: 1234567891123
123456789112!123 EXPECTED OUTPUT: 123456789112
12345678911!123 EXPECTED OUTPUT: 12345678911
1234567891123!123 EXPECTED OUTPUT: 1234567891123
I want use regexp_substr before the exclamation mark (!)
SELECT REGEXP_SUBSTR(l.id,'[%!]',1,13) from l.table
is it ok ?
You can try using INSTR() and substr()
DEMO
select substr(l.id,1,INSTR(l.id,'!', 1, 1)-1) from dual
You want to remove the exclamation mark and all following characters it seems. That is simply:
select regexp_replace(id, '!.*', '') from mytable;
Look at it like a delimited string where the bang is the delimiter and you want the first element, even if it is NULL. Make sure to test all possibilities, even the unexpected ones (ALWAYS expect the unexpected)! Here the assumption is if there is no delimiter you'll want what's there.
The regex returns the first element followed by a bang or the end of the line. Note this form of the regex handles a NULL first element.
SQL> with tbl(id, str) as (
select 1, '1234567891123!123' from dual union all
select 2, '123456789112!123' from dual union all
select 3, '12345678911!123' from dual union all
select 4, '1234567891123!123' from dual union all
select 5, '!123' from dual union all
select 6, '123!' from dual union all
select 7, '' from dual union all
select 8, '12345' from dual
)
select id, regexp_substr(str, '(.*?)(!|$)', 1, 1, NULL, 1)
from tbl
order by id;
ID REGEXP_SUBSTR(STR
---------- -----------------
1 1234567891123
2 123456789112
3 12345678911
4 1234567891123
5
6 123
7
8 12345
8 rows selected.
SQL>
If you like to use REGEXP_SUBSTR rather than regexp_replace then you can use
SELECT REGEXP_SUBSTR(l.id,'^\d+')
assuming you have only numbers before !
If I understand correctly, this is the pattern that you want:
SELECT REGEXP_SUBSTR(l.id,'^[^!]+', 1)
FROM (SELECT '1234567891123!123' as id from dual) l