I have a very interesting task, which I don't know how to implement.
I need to store many regular expressions in a database table, and need to be able to find which of them matches the given string.
For example:
id | regexp
---|-------------
1 | ^hello world$
2 | ^I have [0-9] flowers&
3 | ^some other regexp$
4 | ^and another (one|regexp)$
And I need to find which of those expressions matches string "I have 5 flowers". Of course I can SELECT * FROM table and loop through an expressions matching them one by one in PHP, but this would be horrible for server to handle.
Can I somehow index this table or use a special SQL query to handle this task?
I'll appreciate any answer. Thank you.
select * from table where $your_string RLIKE regexp
mysql regular expressions
SELECT * FROM table WHERE 'some stuff' REGEXP `regexp`;
Unfortunately there is no way to use indexes with queries that use regexps.
Related
I have a search page in PHP which uses the following query to fetch content from the database.
SELECT * FROM linkBase WHERE (`title` LIKE '%".$s."%') OR (`descr` LIKE '%".$s."%')
Here is how my DB looks like :
id |title |descr
-----------------------------------------
1 |Hello World |This is a hello world description
2 |PiedPiper |The silicon valley company PiedPiper
3 |StackOverflow |Ask questions on programming
Now, for example, if I run this query with the value of $s = "silicon valley", Then it fetches the row 2. This is fine. But what if the user enters the search term as silicon PiedPiper. It returns no results with the above SQL query. How can I modify the query in such a way that it will return row 2 with the second search term too.
Question summery :
How can I do a search query using PHP and SQL in such a way that a result will be returned even if the the user enters two words which are not placed consequent to each other in the DB
If you need to support an arbitrary order of the words in the search I suggest using the REGEXP MySQL function with a simple "or" regular expression like
SELECT * FROM linkBase WHERE (`title` REGEXP 'silicon|PiedPiper') OR (`descr` REGEXP 'silicon|PiedPiper')
so you can replace the whitespace with PHP and replace them with a pipe symbol (|) and the order of the words don't matter anymore.
This will select all rows that contain at least one of the words, if you need to match all words in the list another regular expression might be necessary.
LIKE '%{".$s."}%' or to be old school INSTR(title, '{'.$s.'}') > 0
I am wondering if it's possible to search through a MySQL field where the field may have something like this:
test - hello
but you have in a string from a user
test: hello
Obviously it's easy on PHP-side to strip the string of any special characters like that, but is it possible to search through MySQL rows and ignore special characters?
Another unique solution is to put wildcards in between each word. As long as the search phrase does not have special characters in it, the correct results will be returned while ignoring any special characters in the results.
For example...
SELECT *
FROM myTable
WHERE somefield LIKE '%test%hello%'
It could be possible if you find and replace all such special character and spaces from user input also column,
i.e.
select * from tablename where replace(replace(columnname,' ',''),':',''),'-','')=replace(replace([USER INPUT],' ',''),':',''),'-','');
You can sort of "ignore" special characters, whitespace, etc. by using the SOUNDEX() function:
mysql> select soundex('test - hello'), soundex('test: hello');
+-------------------------+------------------------+
| soundex('test - hello') | soundex('test: hello') |
+-------------------------+------------------------+
| T234 | T234 |
+-------------------------+------------------------+
So you can search your data like this:
SELECT ...
FROM MyTable
WHERE SOUNDEX(somefield) = SOUNDEX('test: hello');
This won't be indexable at all, so it'll be forced to do a table-scan. If you use MySQL 5.7, you could add a virtual column for the soundex expression, and index that virtual column. That would help performance a lot.
Is there any way that I can compare if a user id is present in deleted_by_id without going through explode function and just use eloquent directly? I am using laravel 4.2 btw. Below is a sample table:
messages
+-----------------------------+------------------+
+ id | message + deleted_by_id +
+-----------------------------+------------------+
+ 1 | hello + 65,72 +
+ 2 | thank you + 54,33,89 +
+-----------------------------+------------------+
I am trying to compare if a user id is present within deleted_by_id so the message will show up on the trash view.
no like or regex, but find_in_set (I guess it's MySQL):
YourModel::whereRaw('find_in_set(?, deleted_by_id)', [$user_id])->get();
And obviously suggestion - normalize the db ;)
You could use a SELECT statement with the LIKE operator as one approach, but this would produce unexpected results as your user id value grew. Another approach would be to use the REGEX feature of MySQL
MySQL Regex
To add to this, since you want to use Eloquent, you could try the whereRaw() statement with Regex...
Message::whereRaw("deleted_by_id REGEX 8{1}9{1}"); //find 89
This is untested, and you would have to update the Regex each time based on what you were looking for, but only option I could see with Eloquent.
Ultimately, your best option is to rethink your table structure so that you can store each user id on its own row.
MySQL Regex Pattern Matching
I am having a table with a column that has few ids that were put into database with multi select. Column for example contains: 1,4,5,7,9. Is it possible to check if this column contains for example number 5 or not in it through MySQL query ?.
I need to select all the people that have number 5 or some other listed in that field and print them through php.
http://dev.mysql.com/doc/refman/5.6/en/string-functions.html#function_find-in-set
SELECT ...
WHERE FIND_IN_SET(5, list_column)
But understand that this search is bound to be very slow. It cannot use an index, and it will cause a full table-scan (reading every row in the table). As the table grows, the query will become unusably slow.
Please read my answer to Is storing a delimited list in a database column really that bad?
You can use #MikeChristensen's answer to be more standard. Another trick with standard SQL is this:
select * from TableName
where ',' || ids || ',' LIKE '%,5,%'
(in standard SQL, || is the string concatenation operator, but in MySQL, you have to SET SQL_MODE=PIPES_AS_CONCAT or SET SQL_MODE=ANSI to get that behavior.)
Another MySQL-specific solution is to use a special word-boundary regular expression, which will match either the comma punctuation or beginning/end of string:
select * from TableName
where ids RLIKE '[[:<:]]5[[:>:]]'
None of these solutions scale well; they all cause table-scans. Sorry I understand you cannot change the database design, but if your project next requires to make the query faster, you can tell them it's not possible without redesigning the table.
Perhaps:
select * from TableName
where ids = '5' -- only 5
or ids like '5,%' -- begins with 5
or ids like '%,5' -- ends with 5
or ids like '%,5,%' -- 5 in the middle somewhere
It probably won't be very fast on large amounts of data. I'd suggest normalizing these multi-selection values into a new table, where each selection is a single row with a link to TableName.
select * from your_table where concat(',',target_column,',') like '%,5,%'
you can write the sql query like this, for example you are looking for the number 5
select * from your_table_name where ids='5'
if you want to check the result with php just tell me i will write it for you :)
I have a database table with lots and lots of words and strings. (Right now it has over 300K entries, but it grows.) What would be the best way to get only those values that fit the pattern? Lets say the table is:
apples
oranges
abba
car
real
tipi
riot
tidy
Now how to retrieve only pattern CVCV (ConsonantVowelConsonantVowel)? Or CVVC, LLLL (letter*4), etc? I could just make a column with different patterns like so:
word: real
patterns: LLLL,CVVC,LVVC,LVVL,LVLC,LLVC,LLLC,LVLL,CLLC,...
and search the database with "SELECT * FROM table WHERE word LIKE $pattern", but I was thinking if there is a better way?
CVCV:
SELECT 'cara' REGEXP '[bcdfghjklmnpqrstvwxz][aeiouy][bcdfghjklmnpqrstvwxz][aeiouy]';
true
SELECT 'abba' REGEXP '[bcdfghjklmnpqrstvwxz][aeiouy][bcdfghjklmnpqrstvwxz][aeiouy]';
false
If you're only looking for 4 letter words than that should be fairly simple to do with a regexp condition. For example, if you don't care what the order of the vowels and the consonants are, then it's as simple as this:
SELECT *
FROM yourTable
WHERE yourField REGEXP '^[a-z]{4}$'
All this says is find a word that starts and ends with 4 letters a-z.
***Note*** This only applies to lowercase letters using this pattern, if you're worried about uppercase letters you can either do:
1) LOWER(yourField) REGEXP '^[a-z]{4}$'
OR
2) yourField REGEXP '^[a-zA-Z]{4}$'
If you would like something similar to this but not quite what I gave you, read up on regular expressions. This is a pretty good starter reference: http://dev.mysql.com/doc/refman/5.1/en/regexp.html
I would suggest you read up on regular expressions a little anyway as they are pretty powerful and fairly useful in a lot of instances of string manipulation.