How to use LIKE and wildcards in mysql statements - php

I've researched this but couldn't find a solution for my specific problem.
I have a column containing data in a certain format. Here are some examples:
1
6
14
1;6;14;16
etc...
I need a mysql statement which for example it will select all columns where 16 occurs.
I've tried this but it's also selecting columns where 1 and 6 occur:
"SELECT * FROM tbl WHERE kategorien LIKE '%".$_GET['katid']."%' AND status = 1 ORDER BY pos ASC"
Thanks in advance for any help!

You can try creating a helper function like this:
// Helper function
function getLike($str, $deliminator = ';', $field = 'kategorien') {
if (false !== strpos($str, $deliminator)) {
$strParts = explode($deliminator, $str);
return "($field LIKE '%". implode("%' OR $field LIKE '%", $strParts) . "%')";
} else {
return "$field LIKE '%$str%'";
}
}
// Debug
var_dump(getLike('1;6;14;16'));
Outputs:
string '(kategorien LIKE '%1%' OR kategorien LIKE '%6%' OR kategorien LIKE '%14%' OR kategorien LIKE '%16%')' (length=100)
In your query, you'd use it like this:
"SELECT * FROM tbl WHERE ". getLike($_GET['katid']) ." AND status = 1 ORDER BY pos ASC"

You could use MySQL function FIND_IN_SET:
SELECT * FROM tbl
WHERE
FIND_IN_SET('16', REPLACE(kategorien, ';', ','))>0
however, it is usually not a good idea to store comma separated values in a single field, please have a look at this question: Is storing a delimited list in a database column really that bad?

Related

Search query and ordering by matches with my sql

Hi am currently stuck here, been doing research on how to write a mysql statement for a flexible search for products and order them by relevance on a project am working on have seen a few but wasn't helpful please i need help on how to make it work, my current method doesn't work, here it is.
User types in search field and submits "iPad 3rd Generation".
My script breaks the string into words like so.
$termsExploded = array_unique(explode(' ', $term));
No i use php to create an sql query based on the number of words found.
$i = 0;
foreach ($termsExploded as $word) {
if (strlen($word)>1) {
if ($i == 0) {
$where_query = $where_query." name LIKE '%".$word."%'";
}
else{
$where_query = $where_query." OR name LIKE '%".$word."%'";
}
$i++;
}
}
The where query variable now looks like this.
name Like '%ipad%' Or name Like '%3rd%' Or name Like '%Generation%'
Now search for the products ids like so.
$IDs = "SELECT DISTINCT id FROM store_items WHERE".$where_query;
I now create a second where query based on the IDs returned like so
$where_query_s = null;
$i = 0;
foreach ($IDs as $result) {
$returnID = $result->id;
if ($i == 0) {
$where_query_s = $where_query_s." id = ".$returnID."";
}
else{
$where_query_s = $where_query_s." OR id = ".$returnID."";
}
$i++;
};
Now i select the products again based on the distinct IDs returned like so
$items = "SELECT * FROM store_items WHERE".$where_query_s;
Now this works to get the products but how can i sort it based on best match?
Assuming you want to order by the number of matches then build up another string as follows:-
ORDER BY IF(name Like '%ipad%', 1, 0) + IF(name Like '%3rd%', 1, 0) + IF(name Like '%Generation%', 1, 0) DESC
But this will be slow, and takes no account of indexing to improve performance nor of plural / singular (ie, it someone searches for 'flies' it won't rank 'fly' properly).
To put that more into code:-
$where_query = array();
$order_query = array();
foreach ($termsExploded as $word)
{
if (strlen($word)>1)
{
$where_query[] = " name LIKE '%".$word."%'"
$order_query[] = " IF(name Like '%".$word."%', 1, 0)"
}
}
$IDs = "SELECT DISTINCT id FROM store_items WHERE ".implode(' OR ', $where_query)." ORDER BY ".implode(' + ', $order_query)." DESC";
Arrange for your query to look like this:
select field1, field2, etc, count(*) records
from store_items
where blah blah blah
group by field1, field2, etc
order by records desc
If the table is MyISAM based or if it is InnoDB and the version is Mysql 5.6 or greater, then you can use full text search (see http://dev.mysql.com/doc/refman/5.6/en/fulltext-search.html)
effectively you want a query similar to
SELECT * FROM store_items WHERE MATCH (name) AGAINST ('iPad 3rd Generation')
ORDER BY MATCH (name) AGAINST ('iPad 3rd Generation')

PHP MySQL REGEX match search

I want to fetch data from my user table which tag id stored like :
userid tagid
5036 |4815|324|
1396 |1393|4567|
2676 |2669|345|2345|
I have a tagid array like as
Array
(
[0] => 4815
[1] => 4567
)
Need to fetch data using mysql where in condition like "select * from user where tagid in ()".
Is there any preg_match function for it?
Suggest you loop the array and append using likes, something like:
$tags = array(2,4,6);
$query = 'select * from user where ';
foreach($tags as $i=>$tag) {
if ($i>0) $query.=' or '; // or and?
$query.='tagid like "%|'.$tag.'|%"';
}
Because you're having to use a wildcard on both sides of the match they would both be about the same (I think regexp may be a little faster in your case).
The problem is that you may have false positives because of the chance of a substring in your searches because of the lack of normalization.
An example:
Searching for %15%
Matches 915,15,150,215790
Because of this, you should actually do this, since in this case, LIKE would not be sufficient unless you always wrap the IDs in the pipe characters |:
<?php
$ids = array('115','215','225');
foreach($ids as $id){
$query = "select * from user where tagid regexp '[^0-9]*$id[^0-9]*'";
}
?>
At which point you could use this:
<?php
$ids = array('115','215','225');
foreach($ids as $id){
$query = "select * from user where tagid like '%|$id|%'";
}
?>
You can do it like that:
$tagid = array(4815,4567);
$query = "select * from user where tagid regexp '\|("
. implode("|", $tagid) . ")\|'";
then you obtain:
select * from user where tagid regexp '\|(4812|4567)\|'

Finding a list of comma separated keywords

When I run my code I cannot retrieve the entry that I am targeting because the keywords that are being run through the query are not the same as the keywords in the database.
Keywords:
$keywords = 'spaghetti,macaroni,hamburger';
Query:
mysql_query("SELECT * FROM ---- WHERE keywords LIKE '%$keywords%' ORDER BY id DESC LIMIT 1");
I am targeting an entry with these keywords:
food, restaurant, hamburger, spaghetti, taco,pie
I may be missing something simple here since I've been working for 12 hours straight. However, I've had no luck with anything I've tried to do to work around this issue.
From my point of view the query should be returning the target entry since there are 2 matching keywords.
What should I be doing differently?
$like = array();
$keywords = explode(',' , $keywords);
foreach($keywords as $keyword) {
$like[] = "`keywords` LIKE '%$keyword%'";
}
$like = implode(' OR ', $like);
$query = "SELECT * FROM `table` WHERE $like ORDER BY id DESC LIMIT 1";
You need to break up the keywords and do a separate LIKE comparison for each one
SELECT * FROM mytable
WHERE keywords LIKE '%spaghetti%' OR keywords LIKE '%macaroni%'
-- ...
You could do something like this
<?php
$keywords = 'spaghetti,macaroni,hamburger';
$query = "SELECT * FROM mytable WHERE 1=1";
$keywords = explode(',', $keywords);
if (count($keywords)) {
$query .= sprintf(
" AND (%s)",
implode(' OR ', array_map(function($word){
return "keywords LIKE '%{$word}%'";
}, $keywords))
);
}
echo $query;
// SELECT * FROM mytable WHERE 1=1 AND (keywords LIKE '%spaghetti%' OR keywords LIKE '%macaroni%' OR keywords LIKE '%hamburger%')
As you can see from the comments, there are better ways to handle this, but I'm assuming that this rudimentary question is looking for a simple answer.
I'm not doing any input sanitization, or adding any other fail safes. Building queries like this is not very reliable and you should continue to learn about PHP/MySQL to avoid common pitfalls in the future. However, I believe more advanced approaches are a bit out of your reach at the moment. If someone else would like to provide better techniques that they think the OP can grasp, by all means, go for it :)
Storing multiple values as a CSV inside a column is a common SQL anti-pattern. It's hard to use and even harder to optimize:
How to fix the Comma Separated List of Doom
You have to use LIKE with separeted works, you can try this:
$keywords = 'spaghetti,macaroni,hamburger';
$arrayWords = explode(',', $keywords);
$like = '';
foreach($arrayWords as $word)
$like .= empty($like) ? " keywords LIKE '%$word%' " : " OR keywords LIKE '%$word%' ";
mysql_query("SELECT * FROM ---- WHERE $like ORDER BY id DESC LIMIT 1");
mysql_query("SELECT * FROM ---- WHERE keywords LIKE '%". implode("%' OR keywords LIKE '%", explode(",", $keywords)) ."%' ORDER BY id DESC LIMIT 1");
Try this, it may be faster than using multiple or clauses
Select * from mytable
where keywords REGEXP 'spaghetti|macaroni|hamburger'

Combining `where` and `like` statements by using the CI activerecords

To cut a long story short: Is it possible and if it is - how can I build a query that looks somewhat like this one
SELECT * FROM a
WHERE row = 1 AND
(other_row LIKE '%..%' OR another_row LIKE '%..%')
Basically I cann't come up / find a solution to this problem. I just cann't seem to figure how to add the brackets to the activerecords query. Is that even possible?
My current code:
$data = $this->where('row', 1)
->like('another_row', '...')
->or_where('row', 1)
->like('other_row', $search)
->get('a')
->result();
Result:
SELECT * FROM (`a`) WHERE `row` = 1 OR `row` = 1 AND `another_row` LIKE '%...%' AND other_row` LIKE '%...%'
You can try this.
$query = $this->db->select('*')
->from('a')
->where('row',1)
->where("(other_row LIKE '%%' OR another_row LIKE '%%' )")
->get();
foreach ($query->result() as $row) {
//do sth.
}
You can write custom query string (from active record class)
Custom string:
You can write your own clauses manually:
$where = "name='Joe' AND status='boss' OR status='active'";
$this->db->where($where);
I also having problem with or_where so i simply make my custom query like
$this->db->query("SELECT * FROM `a` WHERE `row`=1 AND (CONDITION1 OR CONDITION2)")
$sql= "SELECT * FROM `a`
WHERE row = '1' AND
(other_row LIKE '%" . $value . "%' OR another_row LIKE '%" . $value . "%')";
$this->db->query($sql);
Why dont you try this:
$this->db->where("row = 1 AND
(other_row LIKE '%..%' OR another_row LIKE '%..%')");
$this->db->get('a');
It's how you can write custom WHERE in CI. If it is not what u r looking for, feel free to explain
You can use the following:
$this->db->like('title', 'match', 'before');
It will produce:
WHERE `title` LIKE '%match' ESCAPE '!'
$this->db->where('salary_range_min >= ',$salarymin)
$this->db->where('salary_range_max <= ',$salarymax)
$this->db->where('job_title like '.$title.'% or skill like %'.$title.'%');
// OR */
$this->db->where('job_title like '.$title.'% or skill like %'.$title.'%',FALSE);
// OR */
$this->db->where('job_title like '.$title.'% or skill like %'.$title.'%',NULL);
Try this out

Query with a PHP foreach using OR and LIKE %?

I have sort of a tricky problem, and I want to see if there is an easier way about solving it.
I have let's say
$numbers= $_GET['numbers']; //resulting in $numbers=array(1,2,3)
The count in the array may vary depending on the $_GET value...
These need to search using '%" . $number. "%' because there might be more than one number in the row separated by commas
My ideal result would perform a search for the $numbers(1,2,3) with:
SELECT * FROM database WHERE numbers LIKE('%1%' OR '%2%' OR '%2%')
No need to inject many OR operators for each element of the Array. Instead you can use rlike (the regex matcher operator of MySQL) and simplify your code to a great extent like this:
$numbers = array(1,2,3);
$sql = 'SELECT * from `database` WHERE number rlike "^'.implode('|', $numbers).'$"';
// $sql becomes: SELECT * from `database` WHERE number rlike "^1|2|3$"
$like_part = implode(' OR ', array_map(function($i) {
return "(_utf8 '%{$i}%' USING latin1)";
}, $numbers)
);
Use the foreach to build the where string, then add it to the query.
$query = '...';
$where = '';
foreach ($numbers as $number) {
$where .= ...
}
$query .= $where;
I won't mention that you should normalize your tables and use prepared queries.
This code:
<?php
$numbers = array(1,2,3);
$sql = "SELECT * FROM table WHERE numbers LIKE ('%" . implode("%' OR '%", $numbers) . "%')";
Resulting this query:
SELECT * FROM table WHERE numbers LIKE ('%1%' OR '%2%' OR '%3%')
to the effect of:
$query = "select * from table where condition like ('text before '".implode("' text after text before'", $array)." ' text after')"
$query = "select * from table where numbers like (\"_utf8 '%" . implode("%' using latin1\", $_GET['numbers']) . "%' using latin1 OR _utf8 '%\")
[not sure if implode is needle/haystack or vice versa]
1 - SELECT * FROM b AS B INNER JOIN a AS A ON A.a=B.a WHERE A.a RLIKE '^1-|^2-|^3'
2 - SELECT * FROM b AS B INNER JOIN a AS A ON A.a=B.a WHERE (A.a LIKE '1-%' OR A.a LIKE '2-%' OR A.a LIKE '3-%')
First query took around
Memory usage = It is taking time
Execution time = It is taking time
PHPMYADMIN Showing rows 0 - 24 (138 total, Query took 1.1243 seconds.) - Tested with very less data than through direct PHP script
Second query took around
Memory usage = 1198.0807113647 MB
Execution time = 30.719851970673 Seconds
PHPMYADMIN - Showing rows 0 - 24 (138 total, Query took 0.0018 seconds.) - Tested with very less data than through direct PHP script
Foreach took around
Memory usage = 972.3137588501 MB
Execution time = 10.898797988892 Seconds
Configuration
32GB RAM
Intel I9 - 10th gen CPU#2.81GHz
PHP 7.3
MYSQL - 5.7.31
Table size - 2M million data generated by SQL procedure
SHOW VARIABLES LIKE 'have_query_cache'; // YES
Fetched data size 275093
Indexing - Available
Count of variable in LIKE operator 4739 (i.e. 1,2,3... in RLIKE '^1-|^2-|^3....etc')
Memory uage calculated by php function memory_get_usage();
Objections welcomes.

Categories