Regex match first number if it does not appear at the end - sql

I am currently facing a Regex problem which apparently I cannot find an answer to.
My Regex is embedded in a teradata SQL of the form:
REGEXP_SUBSTR(column, 'regex_pattern')
I want to find the first appearance of any number except if it appears at the end of the string.
For Example:
"YEL2X30" -> "2"
"YEL19XYZ05" -> "19"
"YELLOW05" -> ""
I tried it with '[0-9]+(?!$)/' but this returns me a blank String always.
Thanks in Advance!

Shot in the dark here since I'm unfamiliar with teradata and the supported SQL-functionality. However, reading the docs on the REGEXP_SUBSTR() function it seems like you may want to use the 3rd and 4th possible argument along with a slightly different regular expression:
[0-9]+(?![0-9]|$)
Meaning: 1+ Digits that are not followed by either the end of the string or another digit.
I'd believe the following syntax may work now to retrieve the 1st appearance of any number from the matching results:
REGEXP_SUBSTR(column, '[0-9]+(?![0-9]|$)', 1, 1)
The 3rd parameter states from which position in the source-string we need to start searching whereas the 4th will return the 1st match from any possible multiple matches (is how I read the docs). For example: abc123def456ghi789 whould return 123.
Fiddling around in online IDE's gave me that:
CREATE TABLE TBL (TST varchar(100));
INSERT INTO TBL values ('YEL2X30'), ('YEL19XYZ05'), ('YELLOW05'), ('abc123def456ghi789');
SELECT REGEXP_SUBSTR(TST, '[0-9]+(?![0-9]|$)', 1, 1) as 'RESULTS' FROM TBL;
Resulted in:
RESULTS
2
19
NULL
123
NOTE: I also noticed that leaving out the 3rd and 4th parameter made no difference since they will default back to 1 without explicitly mentioning them. I tested this over here.

Possibly the simplest way is to look for digits followed by a non-digit. Then keep all the digits:
regexp_substr(regexp_substr(column, '[0-9]+[^0-9]'), '[0-9]+')

Related

how to use REGEXP_SUBSTR or INSTR in Oracle SQL to get specific string from a column that varies in character length

I have below values stored in a oracle database table: column name=org and am trying to just get the org. user belongs to, in this case: 'abc', 'xyz' i.e., first occurrence after DC=. How can i achieve this ?
12~OU=Administrators,DC=abc,DC=enter,DC=msft,DC=com
14~OU=Admin,OU=Users,DC=xyz,DC=enter,DC=msft,DC=com
output
abc
xyz
I am pretty new to regex_substr, instr expressions.
Any input will be appreciated.
Thanks in advance.
I would suggest something like regexp_substr(col, '(,|^)DC=([^,]*)(,|$)', 1, 1, '', 2)
The (,|^)DC= bit will match either ,DC= or the start of a line followed by DC= (so it won't match another name like ANOTHERDC=). The ([^,]*) bit will match non-comma characters (depending on whether you need to handle escaped delimiters in your field, it's possible you will need to change this). The (,|$) at the end of the expression matches either a comma or the end of the line (to ensure we've selected the whole segment... but see below). Setting the 4th parameter to 1 ensures we get the first match. The 6th parameter is set to 2 to specify that we only want to return the part of the match within the second ().
Since the matching will be greedy by default, you don't really need to worry about the (,|$) bit and could just use regexp_substr(col, '(,|^)DC=([^,]*)', 1, 1, '', 2). I specified it since I think it's more clear to someone (like me) who doesn't remember whether it defaults to greedy or non-greedy.
Similarly, if you know you don't need to worry about cases where a non-DC name ends with DC, you could just simplify to regexp_substr(col, 'DC=([^,]*)', 1, 1, '', 1).
You could start with something like this and then modify it to suit your requirements.

How to avoid "Regular expressions passed into extraction functions must not have more than 1 capturing group" error when using REGEXP_EXTRACT() [duplicate]

How are non-capturing groups, i.e., (?:), used in regular expressions and what are they good for?
Let me try to explain this with an example.
Consider the following text:
http://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex
Now, if I apply the regex below over it...
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
... I would get the following result:
Match "http://stackoverflow.com/"
Group 1: "http"
Group 2: "stackoverflow.com"
Group 3: "/"
Match "https://stackoverflow.com/questions/tagged/regex"
Group 1: "https"
Group 2: "stackoverflow.com"
Group 3: "/questions/tagged/regex"
But I don't care about the protocol -- I just want the host and path of the URL. So, I change the regex to include the non-capturing group (?:).
(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
Now, my result looks like this:
Match "http://stackoverflow.com/"
Group 1: "stackoverflow.com"
Group 2: "/"
Match "https://stackoverflow.com/questions/tagged/regex"
Group 1: "stackoverflow.com"
Group 2: "/questions/tagged/regex"
See? The first group has not been captured. The parser uses it to match the text, but ignores it later, in the final result.
EDIT:
As requested, let me try to explain groups too.
Well, groups serve many purposes. They can help you to extract exact information from a bigger match (which can also be named), they let you rematch a previous matched group, and can be used for substitutions. Let's try some examples, shall we?
Imagine you have some kind of XML or HTML (be aware that regex may not be the best tool for the job, but it is nice as an example). You want to parse the tags, so you could do something like this (I have added spaces to make it easier to understand):
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
\<(.+?)\> [^<]*? \</\1\>
The first regex has a named group (TAG), while the second one uses a common group. Both regexes do the same thing: they use the value from the first group (the name of the tag) to match the closing tag. The difference is that the first one uses the name to match the value, and the second one uses the group index (which starts at 1).
Let's try some substitutions now. Consider the following text:
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.
Now, let's use this dumb regex over it:
\b(\S)(\S)(\S)(\S*)\b
This regex matches words with at least 3 characters, and uses groups to separate the first three letters. The result is this:
Match "Lorem"
Group 1: "L"
Group 2: "o"
Group 3: "r"
Group 4: "em"
Match "ipsum"
Group 1: "i"
Group 2: "p"
Group 3: "s"
Group 4: "um"
...
Match "consectetuer"
Group 1: "c"
Group 2: "o"
Group 3: "n"
Group 4: "sectetuer"
...
So, if we apply the substitution string:
$1_$3$2_$4
... over it, we are trying to use the first group, add an underscore, use the third group, then the second group, add another underscore, and then the fourth group. The resulting string would be like the one below.
L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.
You can use named groups for substitutions too, using ${name}.
To play around with regexes, I recommend http://regex101.com/, which offers a good amount of details on how the regex works; it also offers a few regex engines to choose from.
You can use capturing groups to organize and parse an expression. A non-capturing group has the first benefit, but doesn't have the overhead of the second. You can still say a non-capturing group is optional, for example.
Say you want to match numeric text, but some numbers could be written as 1st, 2nd, 3rd, 4th,... If you want to capture the numeric part, but not the (optional) suffix you can use a non-capturing group.
([0-9]+)(?:st|nd|rd|th)?
That will match numbers in the form 1, 2, 3... or in the form 1st, 2nd, 3rd,... but it will only capture the numeric part.
?: is used when you want to group an expression, but you do not want to save it as a matched/captured portion of the string.
An example would be something to match an IP address:
/(?:\d{1,3}\.){3}\d{1,3}/
Note that I don't care about saving the first 3 octets, but the (?:...) grouping allows me to shorten the regex without incurring the overhead of capturing and storing a match.
HISTORICAL MOTIVATION:
The existence of non-capturing groups can be explained with the use of parenthesis.
Consider the expressions (a|b)c and a|bc, due to priority of concatenation over |, these expressions represent two different languages ({ac, bc} and {a, bc} respectively).
However, the parenthesis are also used as a matching group (as explained by the other answers...).
When you want to have parenthesis but not capture the sub-expression you use NON-CAPTURING GROUPS. In the example, (?:a|b)c
Let me try this with an example:
Regex Code: (?:animal)(?:=)(\w+)(,)\1\2
Search String:
Line 1 - animal=cat,dog,cat,tiger,dog
Line 2 - animal=cat,cat,dog,dog,tiger
Line 3 - animal=dog,dog,cat,cat,tiger
(?:animal) --> Non-Captured Group 1
(?:=)--> Non-Captured Group 2
(\w+)--> Captured Group 1
(,)--> Captured Group 2
\1 --> result of captured group 1 i.e In Line 1 is cat, In Line 2 is cat, In Line 3 is dog.
\2 --> result of captured group 2 i.e comma (,)
So in this code by giving \1 and \2 we recall or repeat the result of captured group 1 and 2 respectively later in the code.
As per the order of code (?:animal) should be group 1 and (?:=) should be group 2 and continues..
but by giving the ?: we make the match-group non captured (which do not count off in matched group, so the grouping number starts from the first captured group and not the non captured), so that the repetition of the result of match-group (?:animal) can't be called later in code.
Hope this explains the use of non capturing group.
It makes the group non-capturing, which means that the substring matched by that group will not be included in the list of captures. An example in ruby to illustrate the difference:
"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
Groups that capture you can use later on in the regex to match OR you can use them in the replacement part of the regex. Making a non-capturing group simply exempts that group from being used for either of these reasons.
Non-capturing groups are great if you are trying to capture many different things and there are some groups you don't want to capture.
Thats pretty much the reason they exist. While you are learning about groups, learn about Atomic Groups, they do a lot! There is also lookaround groups but they are a little more complex and not used so much.
Example of using later on in the regex (backreference):
<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [ Finds an xml tag (without ns support) ]
([A-Z][A-Z0-9]*) is a capturing group (in this case it is the tagname)
Later on in the regex is \1 which means it will only match the same text that was in the first group (the ([A-Z][A-Z0-9]*) group) (in this case it is matching the end tag).
tl;dr non-capturing groups, as the name suggests are the parts of the regex that you do not want to be included in the match and ?: is a way to define a group as being non-capturing.
Let's say you have an email address example#example.com. The following regex will create two groups, the id part and #example.com part. (\p{Alpha}*[a-z])(#example.com). For simplicity's sake, we are extracting the whole domain name including the # character.
Now let's say, you only need the id part of the address. What you want to do is to grab the first group of the match result, surrounded by () in the regex and the way to do this is to use the non-capturing group syntax, i.e. ?:. So the regex (\p{Alpha}*[a-z])(?:#example.com) will return just the id part of the email.
A Simple Answer
Use them to ensure one of several possibilities occur here (?:one|two) or an optional phrase camp(?:site)? or in general, anywhere you want to establish a group/phrase/section without needing to refer to it specifically.
They keep your captured group(s) count to a minimum.
I cannot comment on the top answers to say this: I would like to add an explicit point which is only implied in the top answers:
The non-capturing group (?...)
does not remove any characters from the original full match, it only reorganises the regex visually to the programmer.
To access a specific part of the regex without defined extraneous characters you would always need to use .group(<index>)
Well I am a JavaScript developer and will try to explain its significance pertaining to JavaScript.
Consider a scenario where you want to match cat is animal
when you would like match cat and animal and both should have a is in between them.
// this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]
// using lookahead pattern it will match only "cat" we can
// use lookahead but the problem is we can not give anything
// at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]
//so I gave another grouping parenthesis for animal
// in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]
// we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]
To complement other good answers in this thread, I want to add an interesting observation that I came across.
Finding: You can have a capturing group inside a non-capturing group.
Problem Details: Have a look at below regex for matching web urls:
var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
Here is my input url string:
var url = "http://www.ora.com:80/goodparts?q#fragment";
The first group in my regex (?:([A-Za-z]+):) is a non-capturing group which matches the protocol scheme (http) and colon (:) character. In continuation it becomes http:. But when I ran below code:
console.debug(parse_url_regex.exec(url));
I could see that the 1st index of the returned array was containing the string http instead (Refer screenshot).
At this point, my thinking was that http and colon : both will not get reported in the output as they are inside a non-capturing group. If the first regex group (?:([A-Za-z]+):) is a non-capturing group then why it is returning http string in the output array?
Explanation: So if you notice, ([A-Za-z]+) is a capturing group (not having ?: at the beginning). But this capturing group is itself inside a non-capturing group (?:([A-Za-z]+):) followed by a : character. That's why the text http still gets captured but the colon : character which is falling inside the non-capturing group (but outside the capturing group ) doesn't get reported in the output array.
In complex regular expressions you may have the situation arise where you wish to use a large number of groups some of which are there for repetition matching and some of which are there to provide back references. By default the text matching each group is loaded into the backreference array. Where we have lots of groups and only need to be able to reference some of them from the backreference array we can override this default behaviour to tell the regular expression that certain groups are there only for repetition handling and do not need to be captured and stored in the backreference array.
(?: ... ) acts as a group ( ... ) but doesn't capture the matched data. It's really much more efficient than a standard capture group. It is use when you want to group something but don't need to reuse it later. #Toto
Let me take to you an example of geo coordinate, the below matches two groups
Latitude,Longitude
([+-]?\d+(?:\.\d+)?),([+-]?\d+(?:\.\d+)?)
Lets take one ([+-]?\d+(?:\.\d+)?)
co-ordinate can be whole number like 58 or could be 58.666
Hence the optional (.666) second part (\.\d+)? is mentioned.
(...)? - for optional
But it is parenthesised, that will be another group of match. and we dont want two matches one for 58 and another for .666, we need single latitude as match. Here comes non-capturing group (?:)
with non-capturing group [+-]?\d+(?:\.\d+)?, 58.666 and 58 both are single match
Its extremely simple, We can understand with simple date example, suppose if the date is mentioned as 1st January 2019 or 2nd May 2019 or any other date and we simply want to convert it to dd/mm/yyyy format we would not need the month's name which is January or February for that matter, so in order to capture the numeric part, but not the (optional) suffix you can use a non-capturing group.
so the regular expression would be,
([0-9]+)(?:January|February)?
Its as simple as that.
I think I would give you the answer. Don't use capture variables without checking that the match succeeded.
The capture variables, $1, etc, are not valid unless the match succeeded, and they're not cleared, either.
#!/usr/bin/perl
use warnings;
use strict;
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
print "Fred wants a $1";
}
else
{
print "Fred dont wants a $1 $2";
}
In the above example, to avoid capturing bronto in $1, (?:) is used.
If the pattern is matched , then $1 is captured as next grouped pattern.
So, the output will be as below:
Fred wants a burger
It is Useful if you don't want the matches to be saved.
Open your Google Chrome devTools and then Console tab: and type this:
"Peace".match(/(\w)(\w)(\w)/)
Run it and you will see:
["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]
The JavaScript RegExp engine capture three groups, the items with indexes 1,2,3. Now use non-capturing mark to see the result.
"Peace".match(/(?:\w)(\w)(\w)/)
The result is:
["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]
This is obvious what is non capturing group.

Using SQL - how do I match an exact number of characters?

My task is to validate existing data in an MSSQL database. I've got some SQL experience, but not enough, apparently. We have a zip code field that must be either 5 or 9 digits (US zip). What we are finding in the zip field are embedded spaces and other oddities that will be prevented in the future. I've searched enough to find the references for LIKE that leave me with this "novice approach":
ZIP NOT LIKE '[0-9][0-9][0-9][0-9][0-9]'
AND ZIP NOT LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
Is this really what I must code? Is there nothing similar to...?
ZIP NOT LIKE '[\d]{5}' AND ZIP NOT LIKE '[\d]{9}'
I will loath validating longer fields! I suppose, ultimately, both code sequences will be equally efficient (or should be).
Thanks for your help
Unfortunately, LIKE is not regex-compatible so nothing of the sort \d. Although, combining a length function with a numeric function may provide an acceptable result:
WHERE ISNUMERIC(ZIP) <> 1 OR LEN(ZIP) NOT IN(5,9)
I would however not recommend it because it ISNUMERIC will return 1 for a +, - or valid currency symbol. Especially the minus sign may be prevalent in the data set, so I'd still favor your "novice" approach.
Another approach is to use:
ZIP NOT LIKE '%[^0-9]%' OR LEN(ZIP) NOT IN(5,9)
which will find any row where zip does not contain any character that is not 0-9 (i.e only 0-9 allowed) where the length is not 5 or 9.
There are few ways you could achieve that.
You can replace [0-9] with _ like
ZIP NOT LIKE '_'
USE LEN() so it's like
LEN(ZIP) NOT IN(5,9)
You are looking for LENGTH()
select * from table WHERE length(ZIP)=5;
select * from table WHERE length(ZIP)=9;
To test for non-numeric values you can use ISNUMERIC():
WHERE ISNUMERIC(ZIP) <> 1

string replace sql select

Hi Ive tried to find an answer to this but cant find one.
Id like to remove some characters and prepend a pound sign to the result of an SQL query which looks as follows (its already using a replace command can I stack these)?:
select fundraiser.Company_Name,
replace(Just_Giving_Campaign,'"label":',''),
sum(fundraising_campaigns.Total_Collected) as donations
from fundraising_campaigns,
fundraiser
where Charity_Name = 'WaterAid'
and fundraising_campaigns.Campaigners_ID = fundraiser.id
group by fundraiser.Company_Name
Can anyone confirm how I would go about adding (£ sign) and remove several sets of characters from a select statement.Certainly dont appear to be able to stack replace statements (e.g.
replace(replace (string, what to match, what to replace it with), what to match, what to replace it with)
Appreciate any thoughts
I am not sure about your question. If I am correct you want to prepend £ and do some nested replace. Hope the below example helps.
select '£'+replace(replace('YourText','x','s'),'You','U')

How SQL/sqlite wildcars work? LIKE operator

How wildcards in sqlite work. Or how LIKE operator matches.
For examle lets say:
1: LIKE('s%s%', 's12s12')
2: LIKE('asdaska', '%sk%')
In 1st example what % matches after 1st s, and how it decides to continue matching % or s after %.
In 2nd example if s matches first then FALSE returned.
Both examples return TRUE. From my Programming knowledge I came up with that LIKE function is some like a recursive function that when 2 possibilities appear function calls itself with 2 different params and uses OR between them, then obviously if one call returns true, upper function directly returns true. If it is so, then LIKE operator is quiet slow to use on large DBs.
P.S. There is one more '_' wildcard which matches exactly one character
I couldnt find any detailed documentation of LIKE operator.
% matches zero or more characters, _ matches exactly one.
Your first pattern 's%s%' would match, 'ss', 's1s', 's1111s', 'ss1111', etc. etc.
However if you wrote 's_s_' it would match 's1s1', but none of the above.