How to split varchar in oracle - oracle

I have a procedure in where I am taking the input parameters as array of strings.
This String contains like 5-Deal deleted
I want to split this varchar into 5 and Deal deleted.
Here split conditions is -

Try using regexp_substr:
select regexp_substr ('5-Deal deleted' , '[^-]+', 1, rownum) split
from dual
connect by level <= length (regexp_replace ('5-Deal deleted' , '[^-]+')) + 1;
Then you can use BULK COLLECT INTO for store into a variable

For such a simple task, I would go with SUBSTR and INSTR. REGULAR EXPRESSION would be too much resource consuming.
INSTR would find the position of -, i.e. hyphen, and SUBSTR would pick the required portion of the string.
Or,
If your example data is what it looks like for all the rows, then, just extract DIGIT and ALPHA from the string and just concatenate them. This would obviously need REGULAR EXPRESSION.

Try this:
SELECT SUBSTR ('5-Deal deleted', 1, INSTR ('5-Deal deleted', '-') - 1)
AS FIRST,
SUBSTR ('5-Deal deleted', INSTR ('5-Deal deleted', '-') + 1) AS second
FROM DUAL

Related

Oracle Regexp_substr to return a value from a yaml string

I am trying to parse the yaml string to a column in SQL.
I have a yaml string in one of the columns like
country_cd:GB
postal_town_city:London
zip:CT11 A1Cr
I have to write a query to pass the key and get a value. When I pass 'country_cd', I want to receive 'GB'.
I have tried the below script but it is returning 'country_cd:G'. What am I doing incorrectly ?
select trim(regexp_substr('---
country_cd:GB
postal_town_city:London
zip:CT11 A1Cr', '\n?'||'postal_town_city'||'*[:=] *(.+?) *\n?', 1, 1, 'i')) from dual ;
You can use REGEXP_SUBSTR with the m match parameter to parse the string as separate lines:
SELECT REGEXP_SUBSTR(yaml, '^country_cd:(.*)$', 1, 1, 'm', 1) AS value
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (yaml) AS
SELECT 'country_cd:GB
postal_town_city:London
zip:CT11 A1Cr' FROM DUAL;
Outputs:
VALUE
GB
or, you can split the string using simple string functions (which are often quicker than using regular expressions) and then filter for the correct key:
WITH lines (yaml, line_start, separator_pos, line_end) AS (
SELECT yaml,
1,
INSTR(yaml, ':', 1),
INSTR(yaml, CHR(10), 1)
FROM table_name
UNION ALL
SELECT yaml,
line_end + 1,
INSTR(yaml, ':', line_end + 1),
INSTR(yaml, CHR(10), line_end + 1)
FROM lines
WHERE line_end > 0
)
SELECT SUBSTR(yaml, line_start, separator_pos - line_start) AS key,
CASE line_end
WHEN 0
THEN SUBSTR(yaml, separator_pos + 1)
ELSE SUBSTR(yaml, separator_pos + 1, line_end - separator_pos)
END AS value
FROM lines
WHERE SUBSTR(yaml, line_start, separator_pos - line_start) = 'country_cd'
Which outputs:
KEY
VALUE
country_cd
GB
db<>fiddle here
Using REGEXP_SUBSTR with a capture group, we can try:
SELECT yaml,
REGEXP_SUBSTR(yaml_col, '(^|\s)country_cd:(\S+)', 1, 1, NULL, 2) AS country_cd
FROM yourTable;
Here is regex demo.

Need to extract text with REGEXP_SUBSTR - cannot find the right combination

Here is an example of my text- I am trying to get TEXTPART3 AS THE ANSWER:
TEXTPART1 : TEXTPART2: TEXTPART3 - TEXTPART4
I used TRIM(LEADING ':' FROM REGEXP_SUBSTR('textstatementhere', ':.+?-')) - but it is not accounting for the two ":" and the "-" in the text statement I get ' TEXTPART2: TEXTPART3 -'
Can anyone help?
Thanks in advance!
The problem has a more efficient solution using only standard string functions:
with
sample_input (str) as (
select 'TEXTPART1 : TEXTPART2: TEXTPART3 - TEXTPART4' from dual
)
select substr(str, pos, instr(str, '-', pos) - pos - 1) as text_part_3
from (select str, instr(str, ':', 1, 2) + 2 as pos from sample_input)
;
TEXT_PART_3
-----------
TEXTPART3
Leverage the REGEXP_SUBSTR Function to Do All of Your Work
Use a subexpression, (\w), and reference it:
WITH exmple AS (
SELECT
'TEXTPART1 : TEXTPART2: TEXTPART3 - TEXTPART4' txt
FROM
dual
)
SELECT
txt,
regexp_substr(txt, ': (\w*) -', 1, 1, NULL,
1)
FROM
exmple;
I see that you used ., in lieu of \w. Because you chose the meta-character,. (which represents all characters except new line (though that can be included if "n" is set as a pattern matching modifier)), the second colon is thrown in to the matching set.
What does TEXTPART3 include?
Perhaps the meta-character, \w, (which stands for alphanumeric or underscore (_) character), is not what you need.
You could replace it with a non-matching character list to avoid the problems with .:
[^:].
This approach would look like this:
REGEXP_SUBSTR(txt, ': ([^:]*) -',1,1,NULL,1)
Lastly, with the quantiifier associated with this subexpression, I used * which means zero or more matches. I assumed that there would be instances where there could be zero matches for this TEXTPART3. If this is not the case, we can use +.

Convert String to Date field for SQL Oracle

I need to convert a string to a date field. The field stores 30 characters. Dates, when present, are formatted as 'yyyymmdd' (20170202). In all cases, dates have 22 spaces after. I need to format this field as a date field like this: dd-mm-yyyy.
I've tried several formulas:
TO_CHAR(PERSACTION.NEW_VALUE_02, 'dd-mm-yyyy') ,TO_CHAR(PERSACTION.NEW_VALUE_02, 'yyyymmdd'), trim(TO_CHAR(PERSACTION.NEW_VALUE_02, 'yyyymmdd')) with error message: invalid number format model. Your expertise is welcome and appreciated.
to_char(to_date( rtrim(new_value_02), 'yyyymmdd'), 'dd-mm-yyyy')
Should do the trick. rtrim removes spaces on right side of string. Then I convert it to date using the date format specified, and then convert it to a string again in the desired format.
Did tried to convert to date format and then to char again?
TO_CHAR(TO_DATE(PERSACTION.NEW_VALUE_02,'yyyymmdd'),'dd-mm-yyyy')
Please, please, please do not store DATEs and CHARACTER datatypes. This will only lead to issues that can be avoided when using the DATE datatype.
If you want to change the string 20170202 to another string and not actually a date (which would have no intrinsic formatted text representation), you could optionally use a regular expression to transform it, instead of converting to a date and back:
select regexp_replace('20170202 ', '^(\d{4})(\d{2})(\d{2}) +$', '\3-\2-\1')
from dual;
REGEXP_REPLACE(
---------------
02-02-2017
Or you could use substr instead of regexp_substr, which may perform better even if you have to call it three times; using a CTE just to avoid repeating the value:
with t(str) as (
select '20170202 ' from dual
)
select substr(str, 7, 2) ||'-'|| substr(str, 5, 2) ||'-'|| substr(str, 1, 4)
from t;
SUBSTR(STR
----------
02-02-2017
If you do convert to a date and back you would uncover any values which cannot be converted, as they will cause an exception to be thrown. That would imply you have bad data; which would have been avoided by using the right data type in the first place, of course. These will convert any old rubbish, with varying results depending on how far the strings stray from the pattern you expect - but including strings like '20170231' which represent an invalid date. And null value or strings of just spaces will be converted to odd things with the substr version, but you could filter those out.
You can see the kind of variation you would get with some sample data that doesn't match your expectations:
with t(str) as (
select '20170202 ' from dual
union all select '20170231 ' from dual
union all select '2017020c ' from dual
union all select '2017020 ' from dual
union all select '201702021 ' from dual
union all select ' ' from dual
union all select null from dual
)
select str,
regexp_replace(str, '^(\d{4})(\d{2})(\d{2}) +$', '\3-\2-\1') as reg,
substr(str, 7, 2) ||'-'|| substr(str, 5, 2) ||'-'|| substr(str, 1, 4) as sub
from t;
STR REG SUB
------------- ------------- -------------
20170202 02-02-2017 02-02-2017
20170231 31-02-2017 31-02-2017
2017020c 2017020c 0c-02-2017
2017020 2017020 0 -02-2017
201702021 201702021 02-02-2017
- -
--
With the anchors and whitespace expectation, the regular expression doesn't modify anything that doesn't consist entirely of 8 numeric characters. But it can still form invalid 'dates'.

REGEXP_SUBSTR for portion of string

I would like to get:
82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
from the following expression
LASTNAME_FIRSTNAME_82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
Does someone know how I can get this using regexp_substr ?
EDIT
Basically I have a field which has 7 sets each separated by _ . The string I gave is just one example. I wanted to retrieve everything after the second _ . There is no fixed character length so I can not use a substr function. Hence I was using regexp_substr. I was able to get away by using a simplified version
Select FILE_NAME, ( (REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,3)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,4)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,5)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+_',1,6)) ||
(REGEXP_SUBSTR(FILE_NAME,'[^_]+',1,7)) ) as RegExp
from tbl
Here is some more data from the FILE_NAME field
LAST_FIRST_82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
SMITH_JOHN_82961_0130BPQX9QZN9G4P5RDTPA9HR4R_MR_1_1of1
LASTNAME_FIRSTNAME_99999_01V0MU4XUQK0Y24Y9RYTFA7W1CM_MR_3_1of1
To get everything after the second underscore, you do not need regular expressions, but can use something like the following:
select substr(FILE_NAME, instr(FILE_NAME, '_', 1, 2) +1 ) from tbl
The instr returns the position of the second occurrence of '_', starting by the first character; the substr simply gets everything starting from the position given by instr + 1
From your Requirement, you can just go ahead and use the simple SUBSTRfunction. Its faster, and it addresses the simple need to remove the String LASTNAME_FIRSTNAME.
select substr('LASTNAME_FIRSTNAME_82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1', 20) data_string
from dual;
Output:
data_string
-----------------
82961_01B04WZXQQSUGJ4YMRRT2A7TRHK_MR_2_1of1
Unless you have another underlying logic you need to address?
Kindly clarify so i can edit the answer accordingly.

trim value till specified string in oracle pl/sql

i want to trim value of the given string till specified string in oracle pl/sql.
some thing like below.
OyeBuddy$$flex-Flex_Image_Rotator-1443680885520.
In the above string i want to trim till $$ so that i will get "flex-Flex_Image_Rotator-1443680885520".
You can use different ways; here are two methods, with and without regexp:
with test(string) as ( select 'OyeBuddy$$flex-Flex_Image_Rotator-1443680885520.' from dual)
select regexp_replace(string, '(.*)(\$\$)(.*)', '\3')
from test
union all
select substr(string, instr(string, '$$') + length('$$'))
from test
You want to do a SUBSTR where the starting position is going to be the position of '$$' + 2 . +2 is because the string '$$' is of length 2, and we don't want to include that string in the result.
Something like -
SELECT SUBSTR (
'ABCDEF$$some_big_text',
INSTR ('ABCDEF$$some_big_text', '$$') + 2)
FROM DUAL;

Resources