Basically i want to add wildcards to the the col value when searching...
Usually I do this the other way around like this:
WHERE cakes.cake_name LIKE '%$cake_search%'
however now i want it to match the inverse:
the user searches for 'treacle
sponge', i want this to match a row
where the cake_name column =
'sponge'.
is this possible?
WHERE '$cake_search' LIKE concat('%',cakes.cake_name, '%')
should work. It will need a full table scan but so will the inverse query. Have you looked into full text search for MySQL? It will likely make this sort of query more efficient.
Why not using MATCH?
MATCH(`cake_name`) AGAINST ('treacle sponge')
You would have to split the user supplied input on the space character and dynamically construct your query to check the column for those values:
$input = "treacle sponge";
$input_words = explode(' ', $input);
$sql_where = "WHERE cakes.cake_name IN('" . implode("','", $input_words) . "')"; // generates: WHERE cakes.cake_name IN('treacle','sponge')
In order to prevent SQL-Injection, I suggest using prepared statements.
$prepStmt = $conn->prepare('SELECT ... WHERE cakes.cake_name LIKE :cake_search
');
if($prepStmt->execute(array('cake_search'=>"%$cake_search%"))) {
...
}
Or, using full text search:
$prepStmt = $conn->prepare('SELECT ... WHERE MATCH (`cake_name`) AGAINST (:cake_search IN BOOLEAN MODE)');
if($prepStmt->execute(array('cake_search'=>$cake_search_words))) {
...
}
See JSON specialchars JSON php 5.2.13 for a complete example.. ;)
Related
Propel/PHP/Mysql question for you. I have a search box that will search names in a table. I need to concat 2 fields, first_name and last_name, and than do a LIKE % submitted string %. All in propel.
This is what I currently have:
$custQuery = CustomerQuery::create()
->withColumn("CONCAT(first_name, ' ', last_name)", "full_name")
->where("full_name LIKE %?%", $nameInput);
This gives the error:
Cannot determine the column to bind to the parameter in clause "full_name = ?".
Obviously I can't use the virtual column in the where statement. When I try to do the concat inside the where statement, I get the same error.
$custQuery = CustomersQuery::create()
->where("CONCAT(first_name, ' ', last_name) LIKE %?%", $searchStr);
I'd prefer to avoid doing this without parameters:
$custQuery = CustomersQuery::create()
->where("CONCAT(first_name, ' ', last_name) LIKE %$searchStr%");
It works, but I am looking for a more propel orientated method of doing this. Is there a way to do this without a where statement at all?
Thanks a ton!
You have to use pseudo column names. So, if your normal filter method for the customers.first_name column is ->filterByFirstName(), then when you use a ->where() or a ->condition() method, you also have to use the "FirstName" pseudo column name instead of 'first_name'.
So, your problem query:
$custQuery = CustomersQuery::create()
->where("CONCAT(first_name, ' ', last_name) LIKE %?%", $searchStr);
would become:
$custQuery = CustomersQuery::create()
->where("CONCAT(Customers.FirstName, ' ', Customers.LastName) LIKE ?", '%'.$searchStr.'%');
I added the table name in there for you too for good measure, and you need to make the percent signs part of the paramater instead of part of the query statement.
My CMS adds the data from a 'multiple' selectbox to my mysql db in the following format:
["blabla","blabla2","blabla3","blabla4"]
it looks kind of JSONy, so it's probably just that, but how can I use it in a query, for example if I want to select all rows with blabla3 in that column. Can I use IN, or FIND_IN_SET ? They probably chose this format for a reason, at least that's what I thought :D
Thanks guys, Id love to add a more appropriate title, but I couldn't think of one.
It's an array. You can use IN to find all the matches:
$in = "(" . implode(', ', array_map($blahs, function($b) use ($conn) {
return "'" . $conn->escape($b);
})) . ")";
$sql = "SELECT * FROM yourTable WHERE blahCol IN $in";
I'm trying to retrieve all the data id from a database where their tags(array) is like a given value.
This is what I have done so far...
$new_string = 'nice phone';
$construct = mysql_query("SELECT tag_array, name, id FROM details
WHERE tag_array LIKE $new_string%")
or die("<p>died 20: $construct<br>" . mysql_error());
while($getThis = mysql_fetch_array($construct)){
echo $getThis['id'].'<br />';
echo stripslashes($getThis['name']).'<br />';
}
It doesn't work ATALL.
Could you please point me to the right direction?
I'm really struggling!!
You should put $new_string in quotes.
NOTE It is very bad practice and you should always escape all variables you are passing to SQL. You should really read up on SQL injection and other security issues.
Also if you want to match $new_string anywhere in tag_array (which you most likely want), you need to add dollar sign in front of it too. You can read up more at MySQL reference manual.
So in the end:
"SELECT tag_array, name, id FROM details WHERE tag_array LIKE '%" . mysql_real_escape_string($new_string) . "%'"
You should sanitise the data before putting it in the query like:
$new_string = "blah...; DROP TABLE tag_array; #";
$sql = mysql_real_escape_string($new_string);
$sql = "SELECT tag_array, name, id FROM details WHERE tag_array LIKE %'$sql'%"
This is not enough though it just helps preventing sql inject, consider using regular expressions to clean the data. If you don't yet know about regexp check out this site: regexp info. It helped me mutch.
Right now I'm just using a simple
WHERE name LIKE '%$ser%'
But I'm running into an issue - say the search is Testing 123 and the "name" is Testing, it's not coming back with any results. Know any way to fix it? Am I doing something wrong?
If you want to search for 'Testing' or '123' use OR:
WHERE (name LIKE '%Testing%' OR name LIKE '%123%')
Note however that this will be very slow as no index can be used and it may return some results you didn't want (like "4123"). Depending on your needs, using a full text search or an external database indexing product like Lucene might be a better option.
That's how LIKE works - it returns rows that completely contain the search string, and, if you use "%" optionally contain something else.
If you want to see if the field is contained in a string, you can do it this way:
SELECT * FROM `Table` WHERE "Testing 123" LIKE CONCAT("%",`name`,"%")
As Scott mentioned, you cannot check to see if the search contains the column value, it works the other way round.
so if $ser = "testing" and table has a row name = testing 123 it will return
For what you're trying to do you'll need to tokenize the search query into terms and perform an OR search with each of them or better still check out mysql full text search for a much better approach
After the variable $ser is replaced, the query is:
WHERE name LIKE '%Testing 123%'
You should build the query separating by words:
WHERE name LIKE '%$word[1]%$word[2]%'
not efficient (as your example) but working as you want:
WHERE name LIKE '%$ser%' OR '$ser' LIKE CONCAT('%', name, '%')
As mentioned by Mark and others, a full text search method may be better if possible.
However, you can split the search string on word boundary and use OR logic—but check for the whole string first, then offer the option to widen the search:
NOTE: Input sanitization and preparation not shown.
1. Query with:
$sql_where = "WHERE name LIKE '%$ser%'";
2. If zero results are returned, ask user if they would like to query each word individually.
3. If user requests an 'each word' search, query with:
$sql_where = get_sql_where($ser);
(Working) Example Code Below:
$ser = 'Testing 123';
$msg = '';
function get_sql_where($ser){
global $msg;
$sql_where = '';
$sql_where_or = '';
$ser = preg_replace("/[[:blank:]]+/"," ", trim($ser)); //replace consecutive spaces with single space
$search_words = explode(" ", $ser);
if($search_words[0] == ''){
$msg = 'Search quested was blank.';
}else{
$msg = 'Search results for any of the following words:' . implode(', ', $search_words);
$sql_where = "WHERE name LIKE '%$ser%'";
foreach($search_words as $word){
$sql_where_or .= " OR name LIKE '%$word%'";
}
}
return $sql_where . $sql_where_or;
}
$sql_where = get_sql_where($ser);
//Run query using $sql_where string
Is there any way to check if a column is "anything"? The reason is that i have a searchfunction that get's an ID from the URL, and then it passes it through the sql algorithm and shows the result. But if that URL "function" (?) isn't filled in, it just searches for:
...AND column=''...
and that doesn't return any results at all. I've tried using a "%", but that doesn't do anything.
Any ideas?
Here's the query:
mysql_query("SELECT * FROM filer
WHERE real_name LIKE '%$searchString%'
AND public='1' AND ikon='$tab'
OR filinfo LIKE '%$searchString%'
AND public='1'
AND ikon='$tab'
ORDER BY rank DESC, kommentarer DESC");
The problem is "ikon=''"...
and ikon like '%' would check for the column containing "anything". Note that like can also be used for comparing to literal strings with no wildcards, so, if you change that portion of SQL to use like then you could pre-set the variable to '%' and be all set.
However, as someone else mentioned below, beware of SQL injection attacks. I always strongly suggest that people use mysqli and prepared queries instead of relying on mysql_real_escape_string().
You can dynamically create your query, e.g.:
$query = "SELECT * FROM table WHERE foo='bar'";
if(isset($_GET['id'])) {
$query .= " AND column='" . mysql_real_escape_string($_GET['id']) . "'";
}
Update: Updated code to be closer to the OP's question.
Try using this:
AND ('$tab' = '' OR ikon = '$tab')
If the empty string is given then the condition will always succeed.
Alternatively, from PHP you could build two different queries depending on whether $id is empty or not.
Run your query if search string is provided by wrapping it in if-else condition:
$id = (int) $_GET['id'];
if ($id)
{
// run query
}
else
{
// echo oops
}
There is noway to check if a column is "anything"
The way to include all values into query result is exclude this field from the query.
But you can always build a query dynamically.
Just a small example:
$w=array();
if (!empty($_GET['rooms'])) $w[]="rooms='".mysql_real_escape_string($_GET['rooms'])."'";
if (!empty($_GET['space'])) $w[]="space='".mysql_real_escape_string($_GET['space'])."'";
if (!empty($_GET['max_price'])) $w[]="price < '".mysql_real_escape_string($_GET['max_price'])."'";
if (count($w)) $where="WHERE ".implode(' AND ',$w); else $where='';
$query="select * from table $where";
For your query it's very easy:
$ikon="";
if ($id) $ikon = "AND ikon='$tab'";
mysql_query("SELECT * FROM filer
WHERE (real_name LIKE '%$searchString%'
OR filinfo LIKE '%$searchString%')
AND public='1'
$ikon
ORDER BY rank DESC, kommentarer DESC");
I hope you have all your strings already escaped
I take it that you are adding the values in from variables. The variable is coming and you need to do something with it - too late to hardcode a 'OR 1 = 1' section in there. You need to understand that LIKE isn't what it sounds like (partial matching only) - it does exact matches too. There is no need for 'field = anything' as:
{field LIKE '%'} will give you everything
{field LIKE 'specific_value'} will ONLY give you that value - it is not partial matching like it sounds like it would be.
Using 'specific_value%' or '%specific_value' will start doing partial matching. Therefore LIKE should do all you need for when you have a variable incoming that may be a '%' to get everything or a specific value that you want to match exactly. This is how search filtering behaviour would usually happen I expect.