I am trying to build the logic to create a multi word LIKE statement for use with PDO.
This takes the search string $str to build the multiple parts of the LIKE section:
$str = $_POST['str'];
$keywords = preg_split('/[\s]+/', $str);
$totalKeywords = count($keywords);
$search = "%$str%";
$sql_str = " AND post_content LIKE :search0 ";
for($i=1 ; $i < $totalKeywords; $i++){
$search_bit = ":search" . $i;
$sql_str .= " AND post_content LIKE $search_bit ";
}
This is the SQL statement - with the $sql_str slotted into the correct point:
$sql = "SELECT d.ID
, d.post_date
, d.post_content
, d.post_cat_id
, d.post_label
, c.fld_cat
FROM tbl_log_days d
, tbl_log_cats c
WHERE d.post_cat_id = c.fld_id " . $sql_str . "
ORDER BY post_date";
Then for binding the variables, I have tried two approaches:
$stmt = $pdo->prepare($sql);
if (!empty($sql_str)) {
foreach ($keywords as $key => &$keyword){
$foo = '%'.$keyword.'%';
$stmt->bindParam(':search' . $key, $foo);
}
}
And also this (without the ampersand before the $keyword in the foreach line):
$stmt = $pdo->prepare($sql);
if (!empty($sql_str)) {
foreach ($keywords as $key => $keyword){
$foo = '%'.$keyword.'%';
$stmt->bindParam(':search' . $key, $foo);
}
}
However, when I search for e.g. "past hill" and check the resulting SQL that is actually run (I enabled query logging in MySQL), it only takes the last word in the search string:
SELECT d.ID
, d.post_date
, d.post_content
, d.post_cat_id
, d.post_label
, c.fld_cat
FROM tbl_log_days d
, tbl_log_cats c
WHERE d.post_cat_id = c.fld_id AND post_content LIKE '%past%' AND post_content LIKE '%past%'
ORDER BY post_date
I have done a var_dump of the $keyword variable when running a search and it returns:
string(4) "hill"
string(4) "past"
I can't work this one out. Is it possible to do what I'm trying to do?
I would do something like this
for($i=1 ; $i < $totalKeywords; $i++){
$search_num = "search" . $i;
$search_bit = ":" . $search_num;
$sql_str .= " AND post_content LIKE $search_bit ";
$foo = '%'.$keyword.'%';
$V[$search_bit] = $foo;
}
$query = $pdo->prepare($sql);
$query->execute($V);
(I haven't tested this code, so please excuse typos.)
I asked the same question on Sitepoint:
https://www.sitepoint.com/community/t/multi-word-like-prepared-statement-for-pdo-query/223738/5
And got a solution there:
$stmt = $pdo->prepare($sql);
if (!empty($sql_str)) {
for ($x = 0; $x<$totalKeywords; $x++) {
// add the percent signs, or make a new copy of the array first if you want to keep the parameters
$keywords[$x] = "%" . $keywords[$x] . "%";
$stmt->bindParam(':search' . $x, $keywords[$x]);
}
}
Related
Ok so when a user types their search phrase in the search input, I would like it to match the exact phrase or the key words entered.
I.e
So the title of a post is "Search the Database"
$searchVal = "Search database";
WHERE post_title LIKE '%" . $searchVal . "%'
The above code doesn't find a match as the title has "the" between Search Database.
How could I get it to match.
I thought maybe using explode but Im getting an error:
$sVals = explode(" ", $searchVal);
foreach ($sVals as $s) {
$querySearchVals .= "OR post_title LIKE '%" . $s . "%'";
}
Hope that makes sense.
Cheers
Maybe this could help
$search_key = $_POST['searchkey']; //take the search text from the post method
$search_words = array();
$search_words = explode(" ",$search_key);
$q_string = "";
$last_index = intval(count($search_Words)) - 1;
for($i = 0; $i<count($search_Words);$i++)
{
$q_string = $q_string . " post_title LIKE '%$search_words[$i]%' ";
if($i != $last_index)
$q_string = $q_string . " OR ";
}
And to make it even more accurate, you may skip the articles like A, The, An etc
You may want to insert the % in between the words and execute with 1 where clause. some thing like below should work.
$searchVal = "Search database";
$querySearchVals = "post_title LIKE '%";
$sVals = explode(" ", $searchVal);
foreach ($sVals as $s) {
$querySearchVals .= $s."%";
}
$querySearchVals .= "'";
echo $querySearchVals;
Hope it helps!
I am trying to craft a multiword search that will query multiple columns in a table. My code works great thus far for a single column, but as you can imagine using it for more then one column becomes an issue.
If I add orWhere it won't work, and I don't really want to create more for loops because it will become quite cumbersome. Any Ideas?
$query = $request->getParameter("article-search");
$keywords = explode(" ", $query);
for( $i = 1; $i <= count( $keywords ); $i++ ){
$q->addWhere("a.title LIKE ?", "%" . $keywords[$i - 1] . "%");
}
I just did it like this.. Maybe it helps somebody..
$now = "some other parameter";
$parts = explode(" ",trim($searchtext));
$clauses=array();
// static paramtter setted here
$parameters = array(
':now' => $now
);
$i = 0;
foreach ($parts as $part){
// for every word make new search query and parameter
$parameters[":param".$i] = "%".$part."%";
if($i == 0){
$clauses = "v.description LIKE :param".$i." OR v.name LIKE :param".$i." OR v.sale LIKE :param".$i;
} else {
$clauses .= " OR v.description LIKE :param".$i." OR v.name LIKE :param".$i." OR v.sale LIKE :param".$i;
}
$i ++;
}
$qb->select('v')
->from('MyBundle\Entity\Voucher', 'v')
->where('v.date_start <= :now')
->andWhere('v.date_end >= :now')
->andWhere($clauses)
->setParameters($parameters);
Usually I would write this as a query that looks something like the following:
$query = "`where column like '%$keywordOne%' or column like '%keywordTwo%'`";
Though I'm not sure how you implement that with the query-building tool you have there.
Here's a quick example that might help build the where portion of the query using the array of keywords you have:
<?php
$keywords = array("bing", "bang", "jump");
$query_start = 'where colummName';
$like_portion = "like '%" . implode("%' or columnName like '%", $keywords) . "%'";
if(sizeof($keywords) > 0) {
echo "`$query_start $like_portion`";
} else {
// No keywords
}
?>
Let me know if there's anything I can clarify here
Maybe you can consider using "union"? Also, for such complex queries, I would use native SQL instead of ORM practice.
I am trying to implement a multiple and keyword search in my application, but it searches only for the last word in the input and ignores the rest of the input can someone please help me with issue, below is my code...
$where_clause=array();
if(!empty($vResume_screen))
{
// trim whitespace from the stored variable
$trimmed = trim($vResume_screen);
// separate key-phrases into keywords
$trimmed_array = explode(" ",$trimmed);
// count keywords
$trimm_total = count($trimmed_array);
$i = 0;
$searchstring = '';
// looping to get the search string
foreach ($trimmed_array as $trimm)
{
if ($i != 0 and $i != $wordcount)
{
$searchstring .= " AND ";
}
$searchstring .= "resume_text LIKE '%$trimm%'";
// incrementing the value
$i = $i + 1;
}
$where_clause[]="resume_text like '%".$searchstring."%'";
}
I just changed your code a little bit, take a look...
$where_clause=array();
if(!empty($vResume_screen))
{
// separate key-phrases into keywords
$trimmed_array = explode(" ", trim($trimmed));
// count keywords
$trimm_total = count($trimmed_array);
$searchstring = '';
// looping to get the search string
foreach ($trimmed_array as $trimm)
{
if (!empty($searchstring)) {
$searchstring .= " OR "; //If you want to put the same condition for different keywords, you need to use OR.
}
$searchstring .= " resume_text LIKE '%" . $trimm . "%' ";
}
array_push($where_clause, $searchstring);
}
I dont know why you need the $where_clause to be an array but i did not change...
When I need to loop over something while generating a query from each element, I would use something like
$queryStr = "INSERT INTO tableName (x,y) VALUES ";
for ($i = 0 ; $i < $len ; $i++)
{
$queryStr .= "( ".$thing[$i]['x'].", ".$thing[$i]['b']."), ";
}
//extra code to remove the last comma from string
Would there be an alternative?
I don't mind performance too much (knowing the length of the array is not too big), just something that looks nicer.
Using a prepared statement:
$sql = 'INSERT INTO tableName (x, y) VALUES (:x, :y)';
$sth = $dbh->prepare($sql);
for ($i = 0 ; $i < $len ; $i++)
{
$sth->execute(array(
':x' => $thing[$i]['x'],
':y' => $thing[$i]['b']));
}
More examples: http://www.php.net/manual/en/pdo.prepare.php
A slight improvement to get rid of last part (removing latest comma). You can first create an array of values, then use implode function like:
$queryStr = "INSERT INTO tableName (x,y) VALUES ";
for ($i = 0 ; $i < $len ; $i++)
{
$values[] = "( ".$thing[$i]['x'].", ".$thing[$i]['b'].")";
}
$queryStr .= implode(',', $values);
I like using array_walk and implode for things like this:
$values = array(
array(1, 2, 3),
array(4, 5, 6),
. . .
);
// an array to hold the values to insert
$query = array();
// walk the values and build the query array
array_walk($values, function($v) use(&$query) {
$query[] = "(" . implode(", ", $v) . ")";
});
// dump the output
echo implode(", ", $query);
The result looks like this:
(1, 2, 3), (4, 5, 6), ...
Maybe not much cleaner, but at least it gets rid of the for loop :-)
You could use implode() with array_map():
implode(', ', array_map(function($v) { return '(' . $v['x'] . ', ' . $v['b'] . ')'; }, $things));
Demo
$strCols = '`'.implode('`, `',array_keys($arrValues)).'`'; //Sets the array keys passed in $arrValues up as column names
if ($bolEscape){ //Checks if $bolEscape is true
$arrValues = $this->escape($arrValues); //Calls the escape function
$strValues = '"'.implode('","',array_values($arrValues)).'"'; //Sets the array values passed in $arrValues up as data for the columns
}else{
$strValues = '"'.implode('","',array_values($arrValues)).'"'; //Sets the array values passed in $arrValues up as data for the columns WITHOUT escaping
}
//Creates the SQL statement for the query
$strSQL = 'INSERT INTO `' . $strTable . '` (' . $strCols . ') VALUES (' . $strValues . ')';
Thats part of the database class I have written... I pass in the arrValues ('ColumnName'=>'Value')
I have tree arrays like this
$keys = array("elment1","elment1","elment2","elment1");
// This one can have duplicates values
$operator = array("=","<",">","=");
// Operators for MySql query
$queries = array("query1","query2","query3","query4");
// This one can have mixed values
I want to know how to combine this tree arrays to have a query like this:
$string = "SELECT FROM tables
WHERE
(elment1 = query1 OR elment1<query2 OR elment1=query4)
// For the group of duplicates keys
AND
elment2 > query3";
// For the non duplicates
I need this for multi-filter queries.
The user should push a button to add keys, operator and query as many times as he like.
I'm using jquery to create form elements, and each() function to generate 3 arrays, before posting all to php.
You asked a question in French, I'll answer in English and you can use Google Translate if you need a translation. [Utilisez Google Translate pour traduire cette réponse si vous voulez.]
First of all, you'll need to concatenate the pieces. Pay attention to the mysql_real_escape_string, which makes the whole operation a little bit safer.
$joined = array();
for($i = 0, $size = sizeof($keys); $i < $size; ++$i) {
$joined[$i] = $keys[$i] . " " . $operator[$i] . " '" . mysql_real_escape_string($queries[$i]) . "'";
}
Then you can use implode:
$string = 'SELECT [...] WHERE (' . implode(' OR ', $joined) . ')';
Bonjour,
Here is the code. tried and tested.
Voila le code... essayer avec succé
$keys = array("elment1","elment1","elment2","elment1");
// this one can have duplicates values ,
$operator = array("=","<",">","=");
// operators for Mysql query
$queries = array("query1","query2","query3","query4");
// mixtes values
$joined = array();
for($i = 0, $size = sizeof($keys); $i < $size; ++$i)
{
$joined[$keys[$i]][] = $keys[$i] . $operator[$i] . $queries[$i];
}
foreach ($joined as $key => &$value)
{
$value = implode(' OR ', $value);
$value = "(" . $value . ")";
}
$query = implode(' AND ', $joined);
print $query;