I need to find a pattern which will give me a substring which follows logic to substring from the right side, after the third _
.
What I want to achieve is to retrieve everything up until 3rd _
.
I tried this SQL, but it did not work
select
SUBSTRING('22D_XYZ_xy_100_xyz_123', 1, position('_' in REVERSE('22D_XYZ_xy_100_xyz_123')) - 1) as result;
It returns the 22D
whereas I expect 22D_XYZ_xy
2
Answers
You could try this query
See demo here
The phrase, "substring which follows logic to substring from the right side, after the third
_
," is difficult to understand. I infer that the intended behavior is to extract the subtring that includes all text before the third_
from the right and not all text before the third_
from the left. When searching from the left, there is also ambiguity as to expected behavior if there are less than three_
characters: should the entire string be returned or should the result beNULL
? Unfortunately, the example input,22D_XYZ_xy_100_xyz_123
, and expected output,22D_XYZ_xy
, are consistent with all of these cases. The following query demonstrates all three interpretations:Executing the query gives the following:
To search from the right, a positive lookahead zero-length assertion,
(?=(_[^_]*){3}$)
, is used to check that the unmatched portion of the string begins with_
and includes exactly three_
characters. If the assertion is false, thenNULL
is returned.To find the left substring with no more than two
_
characters, the regular expression matches up to two substings of zero or more non-_
characters followed by a single_
along with any non-_
characters prior to the next_
or the end of the string.Finding the left substring preceding a required third
_
is similar to finding the left substring with no more than two_
characters, except that the occurrence specifier for the group is{2}
instead of{0,2}
and a positive lookahead zero-lengh assertion,(?=_)
ensures that_
is the first unmatched character. As with the search from the right, if the assertion is false, then NULL is returned.