How to pull a value in between multiple values? - sql

I have a column named Concatenated Segments which has 12 segment values, and I'm looking to edit the formula on the column to only show the 5th segment. The segments are separated by periods.
How would I need to edit the formula to do this?
Would using a substring work?

Alternatively, using good old SUBSTR + INSTR combination
possibly faster on large data sets
which doesn't care about uninterrupted strings (can contain anything between dots)
SQL> WITH
2 -- thank you for typing, #marcothesane
3 indata(s) AS (
4 SELECT '1201.0000.5611005.0099.211003.0000.2199.00099.00099.0000.0000.00000' FROM dual
5 )
6 select substr(s, instr(s, '.', 1, 4) + 1,
7 instr(s, '.', 1, 5) - instr(s, '.', 1, 4) - 1
8 ) result
9 from indata;
RESULT
------
211003
SQL>

Use REGEXP_SUBSTR(), searching for the 5th uninterrupted string of digits, or the 5th uninterrupted string of anything but a dot (\d and [^\.]) starting from position 1 of the input string:
WITH
-- your input ... paste it as text next time, so I don't have to manually re-type it ....
indata(s) AS (
SELECT '1201.0000.5611005.0099.211003.0000.2199.00099.00099.0000.0000.00000' FROM dual
)
SELECT
REGEXP_SUBSTR(s,'\d+',1,5) AS just_digits
, REGEXP_SUBSTR(s,'[^\.]+',1,5) AS between_dots
FROM indata;
-- out just_digits | between_dots
-- out -------------+--------------
-- out 211003 | 211003

Related

Issues with SUBSTR function Oracle_SQL

I used the SUBSTR function for the similar purposes, but I encountered the following issue:
I am extracting 6 characters from the right, but the data in column is inconsistent and for some rows it has characters less than 6, i.e. 5 or 4. So for such rows, the function returns blanks. How can I fix this?
Example Scenario 1:
SUBSTR('0000123456',-6,6)
Output: 123456
Scenario 2 (how do I fix this?, I need it to return '23456'):
SUBSTR('23456',-6,6)
Output: ""
You can use a case expression: if the string length is strictly greater than 6 then return just the last 6 characters; otherwise return the string itself. This way you don't need to call substr unless it is really needed.
Alternatively, if speed is not the biggest issue and you are allowed to use regular expressions, you can write this more compactly - select between 0 and 6 characters - as many as possible - at the end of the string.
Finally, if you don't mind using undocumented functions, you can use reverse and standard substr (starting from character 1 and extracting the first 6 characters; that will work as expected even if the string has length less than 6). So: reverse the string, extract first (up to) 6 characters, and then reverse again to restore the order. WARNING: This is shown only for fun; DO NOT USE THIS METHOD!
with
test_data (str) as (
select '0123449389' from dual union all
select '00000000' from dual union all
select null from dual union all
select 'abcd' from dual
)
select str,
case when length(str) > 6 then substr(str, -6) else str end as case_substr,
regexp_substr(str, '.{0,6}$') as regexp_substr,
reverse(substr(reverse(str), 1, 6)) as rev_substr
from test_data
;
STR CASE_SUBSTR REGEXP_SUBSTR REV_SUBSTR
---------- ------------- ------------- --------------
0123449389 449389 449389 449389
00000000 000000 000000 000000
abcd abcd abcd abcd
One method uses coalesce():
select coalesce(substr('23456', -6, 6), '23456')
Another tweaks the length:
select substr('23456', greatest(- length('23456'), -6), 6)

Get first value and last value

i have below record like '8|12|53|123|97' and i need to find the range of values between 8 to 97, so that i need the number 8 and 97.
You can use REGEXP_SUBSTR as following:
SQL> SELECT
2 REGEXP_SUBSTR('8|12|53|123|97', '^[0-9]+') FIRSTVAL,
3 REGEXP_SUBSTR('8|12|53|123|97', '[0-9]+$') LASTVAL
4 FROM
5 DUAL;
FIRSTVAL LASTVAL
---------- ----------
8 97
SQL>
^ matches the beginning of a string.
$ matches the end of a string.
Cheers!!
Here is a solution which will work for any string which has at least one pipe.
with cte as (
select '8|12|53|123|97' str from dual
)
, rng as (
select to_number(substr(str, 1, instr(str, '|')-1)) as token_1
,to_number(substr(str, instr(str, '|', -1)+1)) as token_2
from cte )
select token_1 + level - 1 as tkn
from rng
connect by level <= (token_2 - token_1) + 1
/
The first subquery is just your test data. The second subquery identifies the first number (token_1) and the last number (token_2) in the string. It uses substr() and instr() just because they are faster than regex. instr() with a negative offset finds the last occurence of the search argument.
The main query generates a range of numbers from the bounds of the rng subquery. Not sure if that's in your requirement (depends on what you mean by "range of values between").
Because this model is not in First Normal Form you are exposed to data quality issues. The query will not produce results if the first or last tokens are not numeric, or there's only one token or the separator is not a pipe.

To extract the specific strings from the given string in Oracle

expression - BR65437812-909#-#BR12340000-990
Need to extract the given expression and update in columns like
a = BR12340000, b = 990
select
SUBSTR(s, 1, INSTR(s, '-') - 1) as a,
SUBSTR(s, INSTR(s, '-', -1) + 1) as b
from
(select 'BR65437812-909#-#BR12340000-990' as s from dual)
Using SUBSTR(string, start, length) we have the following arguments:
For A:
the string to search
1 as the start and
(index_of_the_first_hyphen - 1) as the length. INSTR(string, searchfor) gives us the index of the first hyphen
For B:
Using SUBSTR(string, start) we have arguments:
the string to search
the (index_of_last_hyphen + 1) - this time we use the extra INSTR(string, searchfor, startindex) argument startindex and set it to -1; this makes it search from the end of the string and work backwards, giving us the index of the last hyphen
We don't need a length argument - SUBSTR without length returns the rest of the string to the end
It's important to note that INSTR with a start index of -1 does search backwards but it always returns the index from the start of the string, not the end.
INSTR('dddde', 'd', -1)
12345 -- returns 4, because d is 4 from the start
54321 -- it does not return 2, even though d is 2 from the "start" when searching backwards
You can use regexp_replace to get every character after last #sign firstly, and then split by dash.
with t(str) as
(
select regexp_replace('BR65437812-909#-#BR12340000-990','.*#','') from dual
)
select regexp_replace(str,'-.*','') as a,
regexp_replace(str,'.*-','') as b
from t;
A B
---------- ---
BR12340000 990
Demo
with s as (
select 'BR65437812-909#-#BR12340000-990' str from dual)
select regexp_substr(str, '[^-#]+', 1, 3) a, regexp_substr(str, '[^-#]+', 1, 4) b
from s;
A B
---------- ---
BR12340000 990

How to extract the number from a string using Oracle?

I have a string as follows: first, last (123456) the expected result should be 123456. Could someone help me in which direction should I proceed using Oracle?
It will depend on the actual pattern you care about (I assume "first" and "last" aren't literal hard-coded strings), but you will probably want to use regexp_substr.
For example, this matches anything between two brackets (which will work for your example), but you might need more sophisticated criteria if your actual examples have multiple brackets or something.
SELECT regexp_substr(COLUMN_NAME, '\(([^\)]*)\)', 1, 1, 'i', 1)
FROM TABLE_NAME
Your question is ambiguous and needs clarification. Based on your comment it appears you want to select the six digits after the left bracket. You can use the Oracle instr function to find the position of a character in a string, and then feed that into the substr to select your text.
select substr(mycol, instr(mycol, '(') + 1, 6) from mytable
Or if there are a varying number of digits between the brackets:
select substr(mycol, instr(mycol, '(') + 1, instr(mycol, ')') - instr(mycol, '(') - 1) from mytable
Find the last ( and get the sub-string after without the trailing ) and convert that to a number:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE test ( str ) AS
SELECT 'first, last (123456)' FROM DUAL UNION ALL
SELECT 'john, doe (jr) (987654321)' FROM DUAL;
Query 1:
SELECT TO_NUMBER(
TRIM(
TRAILING ')' FROM
SUBSTR(
str,
INSTR( str, '(', -1 ) + 1
)
)
) AS value
FROM test
Results:
| VALUE |
|-----------|
| 123456 |
| 987654321 |

Retrieve segment from value

I have this value in my field which have 5 segment for example 100-200-300-400-500.
How do I query to only retrieve the first 3 segment? Which mean the query result will display as 100-200-300.
The old SUBSTR and INSTR will be faster and less CPU intensive as compared to REGEXP.
SQL> WITH DATA AS(
2 SELECT '100-200-300-400-500' str FROM dual
3 )
4 SELECT substr(str, 1, instr(str, '-', 1, 3)-1) str
5 FROM DATA
6 /
STR
-----------
100-200-300
SQL>
The above SUBSTR and INSTR query uses the logic to find the 3rd occurrence of the hyphen "-" and then take the substring from position 1 till the third occurrence of '-'.
((\d)+-(\d)+-(\d)+)
If the Position of this sequence is arbitrary, you might go for REGularEXPressions
select regexp_substr(
'Test-Me 100-200-300-400-500 AGain-Home',
'((\d)+-(\d)+-(\d)+)'
) As Result
from dual
RESULT
-----------
100-200-300
Otherwise Simple SUBSTR will do
you have tow way, the first is substring.
The second is fast, us a REGEXP like this.
REGEXP_SUBSTR('100-200-300-400-500','[[:digit:]]{3}-[[:digit:]]{3}-[[:digit:]]{3}')"REGEXPR_SUBSTR" FROM DUAL;