I've got a load of paths in a MySQL Database (5.7.17-0ubuntu0.16.04.2) and the user chooses a selection of paths, I want to select all those paths and those below, but I've hit an issue.
Say the user wants "/root/K" I need to do a select for:
a. /root/K%
b. /root/K
How can I get the REGEXP to match the end of a field or a / ?
I've tried the following:
original query:
where path REGEXP ('/root/K/|/root/J/J/') # this works but doesn't show the items in that path, only ones below
where path REGEXP '/root/K[/\z]' # does the same as above
where path REGEXP '/root/K(?=/|$)' # Get error 1139, repetition-operator invalid
I've also tried: Regex to match _ or end of string but that gives error 1139
Any other suggestions?
There is no support for lookarounds, not \z anchor in MySQL regex. You may use a normal capturing group:
WHERE path REGEXP '/root/K(/|$)'
It will match
/root/K - literal char sequence
(/|$) - either / or end of entry.
Related
I'm using the following regex (https://regex101.com/r/Kt9sNj/1) in PHP to get all the files in the third level of a directory:
/^(\/[^\/]*){1,4}\/?$/m
Then if I have the following data:
/home/myuser/folder_example/first_file.txt
/home/myuser/folder_example/second_file.txt
/home/myuser/folder_example/third_file.txt
I get:
first_file.txt
second_file.txt
third_file.txt
I try to use this in a MySQL query that contains an array of a json object.
My Query is:
SELECT data->'$.files' AS File
FROM table
WHERE user = 'myuser';
And I get:
["/home/myuser/folder_example/first_file.txt","/home/myuser/folder_example/second_file.txt","/home/myuser/folder_example/third_file.txt"]
But when I use that regex on my sql query:
SELECT data->'$.files' AS File
FROM table
WHERE user = 'myuser'
AND data->'$.files' REGEXP '^(\/[^\/]*){1,4}\/?$';
I need to get this (all files under that directory):
["first_file.txt","second_file.txt","third_file.txt"]
It doesn't work. Do you know why?
The function REGEXP returns 1 if the pattern matches and will return the full match as the pattern does match the example strings.
In your pattern you are repeating a capturing group, which will capture the last value of the iteration in group 1, but it still contains a leading forward slash that you don't want in the output.
What you might do is match the first /, and then use a quantifier {3} to repeat exactly 3 times a part ending on a / using a non capture group.
Then capture the filename in group 1, and refer to that group using '$1' in the replacement using REGEXP_REPLACE
^/(?:[^/]*/){3}(\S+\.[^.\s]+)$
Regex demo | Mysql with replace demo
So I'm trying to code a PHP script, but we'll just leave it at the SQL part of things since this is where the issue is arising. I've a SELECT * query which should only grab from the rows where the user ID matches, and the badge ID meets their userID followed by an underscore. Although, it's grabbing results that shouldn't be included?
Here's my SQL query:
SELECT *
FROM `user_badges`
WHERE `user_id` = 1
AND `badge_id` LIKE '%1_%'
That should only return badges that start/contain 1_, it is grabbing all the badges that do contain/start with 1_ but it's also grabbing it215. If I search a different user ID, for example my own, it will grab all the badges with 3_ AND it's also grabbing ACH_RoomDecoFurniCount31 which is confusing because it doesn't contain 3_. Maybe there's more to it? Could someone please point me in the right direction.
You need to escape the _ as it's a wildcard character. Your query would should be like this:
SELECT *
FROM `user_badges`
WHERE `user_id` = 1
AND `badge_id` LIKE '%1\_%'
_ is also a wildcard in SQL - A substitute for a single character
_ is also a wildcard character. It means "any single character" (whereas % is "any sequence of characters").
You could escape/quote that _ or use the LOCATE function instead of a pattern match.
WHERE badge_id LIKE '%1\_%'
WHERE locate('1_', badge_id) > 0
_ is a wildcard "_ matches exactly one character." so what you are saying is:
% : starts with anything(or nothing)
1: contains 1
_: has exactly 1 of % (or anything, or nothing)
http://dev.mysql.com/doc/refman/5.7/en/string-comparison-functions.html
I have to compare a column value with a user input numbers. The string in the column is in the format 8|5|12|7|
Now, I need to compare a user input values 2,5,3 with this column value
When I use LIKE operator as '%2|%' I got the output by matching with column value |12|
How do I match the string by using Regular Expression or any other way?
If I understand the question correct, then to make sure that you get 2|.. or ..|2|.. or |2, you need to add or clauses
where col like '%|2|%'
or col like '2|%'
or col like '%|2'
or col='2'
Something similar to this to test for 2 in this example 12|8|12|5|12|7|2|12|22
# (^|\|)2(\||$)
#
#
# Match the regex below and capture its match into backreference number 1 «(^|\|)»
# Match this alternative (attempting the next alternative only if this one fails) «^»
# Assert position at the beginning of the string «^»
# Or match this alternative (the entire group fails if this one fails to match) «\|»
# Match the character “|” literally «\|»
# Match the character “2” literally «2»
# Match the regex below and capture its match into backreference number 2 «(\||$)»
# Match this alternative (attempting the next alternative only if this one fails) «\|»
# Match the character “|” literally «\|»
# Or match this alternative (the entire group fails if this one fails to match) «$»
# Assert position at the end of the string, or before the line break at the end of the string, if any (line feed) «$»
REGEXP "(^|\|)2(\||$)"
This allows for the column value to just be 2 or 2|anything or anything|2 or first thing|2|end thing.
By looking your column design, one of the way u can do is LIKE '%|2|%'
It is bad design to build "arrays" in a cell. Use a separate table.
Anyway, FIND_IN_SET() is a function that does the work a lot easier than a regexp. (But you have to use ',')
I have a regexp to validate user email address.
/^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+#((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,})$/i"
With the help of active record, I want to fetch from a database all the users whose email address doesn't match this regexp. I tried the following scope to achieve the desired result, but all I get is ActiveRecord::Relation.
scope :not_match_email_regex, :conditions => ["NOT email REGEXP ?'", /^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+#((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,})$/"]
This gives me the following query:
SELECT `users`.* FROM `users` WHERE (email REGEXP '--- !ruby/regexp /^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\\-+)|([A-Za-z0-9]+\\.+)|([A-Za-z0-9]+\\++))*[A-Za-z0-9]+#((\\w+\\-+)|(\\w+\\.))*\\w{1,63}\\.[a-zA-Z]{2,})$/\n...\n')
I also tried to define this scope in the following way with the same result:
scope :not_match_email_regex, :conditions => ["email REGEXP '(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+#((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,})'"]
The query it generates is:
SELECT `users`.* FROM `users` WHERE (email REGEXP '(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+-+)|([A-Za-z0-9]+.+)|([A-Za-z0-9]+++))*[A-Za-z0-9]+#((w+-+)|(w+.))*w{1,63}.[a-zA-Z]{2,})')
How can I fetch all records that match or don't match the given regex?
EDIT 12-11-30 small corrections partly according to the comment by #innocent_rifle
The suggested Regexp here is trying to make the same matches as in the original question
1. In my solution when I first wrote it I forgot that you must escape \ in strings because I was testing directly in MySQL. When discussing Regexps it's confusing to use Regexps in strings, so I will use this form instead e.g. /dot\./.source which (in Ruby) will give "dot\\.".
2. REGEXP in MySQL (manual for 5.6, tested in 5.0.67) are using "C escape syntax in strings", so WHERE email REGEXP '\.' is still the same as WHERE email REGEXP '.', to find the character "." you must use WHERE email REGEXP '\\.', to achieve that you must use the code .where([ 'email REGEXP ?', "\\\\."]). It's more readable to use .where([ 'email REGEXP ?', /\\./.source ]) (MySQL needs 2 escapes). However, I prefer to use .where([ 'email REGEXP ?', /[.]/.source ]), then I don't have to worry about how many escapes you need.
3. You don't need to escape "-" in a Regexp, not when using that in [] either as long as that character is the first or the last.
Some errors I found: it's the first regexp-or "|" in you expression, and it should be as a String in the query, or using Regexp#source which I prefer. There was also an extra quote at the end I think.
Except from that are you really sure the regexps works. If you try it in the console on a string?
Also be aware of that you won't catch emails with NULL in db, in that case you must add (<your existing expr in parentheses>) OR IS NULL
Regexp syntax in my MySQL verion.
I also tested what #Olaf Dietsche wrote in his suggestion, it seems that it's not needed, but it's strongly recommended to follow the standard syntax anyway (NOT (expr REGEXP pat) or expr NOT REGEXP pat).
I have done some checking, these things must be changed: use [A-Za-z0-9_] instead of \w, and \+ is not valid, you must use \\+ ("\\\\+" if string), easier with [+] (in both Regexp or string).
It leads to following REGEXP in MySQL
'^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]+)|([A-Za-z0-9]+[+]+))*[A-Za-z0-9]+#(([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]))*[A-Za-z0-9]{1,63}[.][a-zA-Z]{2,}$'
Small change suggestions
I don't understand your regexp exactly, so this is only changing your regexp without changing what it will find.
First: change the whole string as I described above
Then change
(([A-Za-z0-9]+_+)|([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]+)|([A-Za-z0-9]+[+]+))*
to
([A-Za-z0-9]+[-+_.]+)*
and
#(([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]))*
to
#([A-Za-z]+[-.]+)*
Final code (change to ..., :conditions => ...syntax if you prefer that). I tried to make this find the same strings as in the comment by #innocent_rifle, only adding "_" in expressions to the right of #
.where([ 'NOT (email REGEXP ?)', /^([A-Za-z0-9]+[-+_.]+)*[A-Za-z0-9]+#([A-Za-z0-9]+[-._]+)*[A-Za-z0-9_]{1,63}[.][A-Za-z]{2,}$/.source ])
For validating email addresses, you might want to consider How to Find or Validate an Email Address. At least, this regexp looks a bit simpler.
According to MySQL - Regular Expressions the proper syntax is
expr REGEXP pat
for a match, and
expr NOT REGEXP pat or NOT (expr REGEXP pat)
for the opposite. Don't forget the braces in the second version.
I'm trying to get info from a table using a browser path column in the table. This is what the query looks like:
select * from selwowscheduler sc
join browser b on sc.scheduledbrowser = b.browserid
where b.browserpath like '*iexplore C:\Program Files\Internet Explorer\iexplore.exe'
Thing is, this returns nothing. I can put %iexplore.exe instead of *iexplore C:\Program Files\Internet Explorer\iexplore.exe and that returns something (though more than I want).
I thought maybe it was the literals \ so I replaced the \ with \\, but that didn't work either (Still returns nothing).
Does anyone know why this isn't working?
Thanks.
EDIT: I know * is not a wild card, it is part of what is on the path. We use it to initiate different browsers on different PCs.
You have to escape a backslash like that \\\\. Try:
where b.browserpath like '%iexplore C:\\\\Program Files\\\\Internet Explorer\\\\iexplore.exe'
The problem is with the the Like syntax what is the * supposed to be matching against because * is not a special character % means match any character 0 or more and _ means match any one character.
Also if you cannot use like to accomplish what you need I would look into Regexp which uses regular expressions to match against and are usually more adaptable then simple Like comparisons
Well first off * is not a valid wildcard for mysql as near as I can tell which is why the query returns nothing (it is looking for a path with '*' in it). My guess without knowing exactly what you are looking for is that some variant of the % wildcard would work. It can be in the middle of the string such as:
where b.browserpath like 'C:%iexplore'
This would return all paths on "C" that end in iexplore. This:
where b.browserpath like 'C:\Program Files%.exe'
returns the paths to anything on "C:\Program Files" that has an ending of ".exe" and so on.