I'm working through this tutorial online: http://goo.gl/qnk6U
The database table: ajax_search
Firstname | Lastname | Age | Hometown | Job
-------------------------------------------
Joe | Smith | 35 | Boulder | CIA
Steve | Apple | 36 | Denver | FBI
(Types are all varchar except age is an int.)
My question. Is the sql select statement below written correctly to query "Joe 35"? For some reason, I can only query "Joe" and it works, but not combining search terms.
$sql = "select * from ajax_search where FirstName like '%$rec%' or LastName like '%$rec%' or Age like '%$rec%' or Hometown like '%$rec%'";
Assuming your query is "Joe 35", then no. Your query matches any row where any of the four fields contains "Joe 35" (in a single field). To query for a user with name Joe and age 35, you'd need to split the search query and do something like:
WHERE Firstname LIKE "$firstname" AND Age LIKE "$age"
You need to split that sting from search query:
$columns = array("Firstname", "Lastname", "Age", "Hometown", "Job");
$string = ""; // acquire query string
$split = explode(" ", $string);
$search_words = array();
foreach ($split as $word) {
$search_words[] = $word;
}
Create query to search all over the fields:
$first = true;
$sql = "select * from ajax_search where";
foreach ($search_words as $word) {
foreach ($columns as $col) {
$sql .= (($first) ? " " : " OR") . "`$col` LIKE \"%" . $word . "%\"";
$first = false;
}
}
Then run this query.
Another and also a better solution would be more complicated word(tag) based indexing, because this can generate morbid queries when used with more words.
Related
Currently when i search the registration number 131-D-12345 I have to type the hyphens to get the results, but I wish to ignore “-”, caps and spaces (so for instance "132D123" and "132 d 123" should return true).
How can I do that in PHP?
<?php
require('/home/s3022041/sqlC/dbConnect.php');
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $_POST['get_id']);
$id = $_POST['get_id'];
$query = "SELECT * FROM cars WHERE Registration_Number = '$id' ";
$query_run = mysqli_query($connection, $query);
?>
If I understood your question correctly
Your database looks something like this example
1 | 987-D-987
2 | 654-E-456
3 | 789-D-123
4 | 678-Z-123
And for example,if you search for 654 e 456 you are expecting to get entry 2.
Well you could use good old string functions...
<?php
$id = $_POST['get_id'];
$stp1 = preg_replace("/[^a-zA-Z0-9]/", "", $id); //grab only the alphanumerics
$stp2 = strtoupper($stp1); //Make all alphabets uppercase
$stp3 = preg_replace('/\d+/', '',$stp2); //extract the alphabets part
$newsearchid = str_replace($stp3,"-".$stp3."-",$stp2); //put hyphens before and after the alphabet part
echo "spaces or lower case .i will return this".$newsearchid; //now the search string looks like one in the database
require('/home/s3022041/sqlC/dbConnect.php');
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $newsearchid);
$query = "SELECT * FROM cars WHERE Registration_Number = '$newsearchid' ";
$query_run = mysqli_query($connection, $query);
?>
if you search for "987 d 987" or "987 d987" or "987d987" or "987D987" or "987-d-987" or "987,d#987" you will still get entry 1 from db.
Basically any search in the format [number][alphabet][number] will always return true
Do I understand correctly that the registration numbers in the database dò contain the hyphens ?
In that case, you should modify your query to hold wildcards (e.g. https://www.guru99.com/wildcards.html)
As for the case, either convert the case of the PHP variable before entering it in the query ( strtoupper(), strtolower() ), or try to solve your case in your table definition.
If the database entries do not hold the hyphens, you can filter them out the variable using a replace or preg_replace() to remove them.
Edit
if I assume your database holds very uniform inputs, like this :
ID | registration
----+---------------
1 | 132D123
2 | 234D324
3 | 456D546
4 | 678D123
then you can prepare your search term as follows :
$searchReg = $_POST['get_id'] ; // take your unmodified POST-ed registration
$searchReg = strtoupper($searchReg) ; // make all characters upper-case, as DB entries are all uppercase
$searchReg = preg_replace("/[\s-]?/", "", $searchReg) ; // replace all whitespaces and hyphens by an empty string - i.e. remove them
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $searchReg);
$id = $searchReg;
...
If however, your database is not formatted very strictly, like :
ID | registration
----+---------------
1 | 132D123
2 | 234d324
3 | 456-D-546
4 | 678-d-123
Then you need to make your SQL query cover the searchterm using wildcards :
$searchReg = $_POST['get_id'] ; // take your unmodified POST-ed registration
$searchReg = preg_replace( "/[\s-]?/", "%", $searchReg) ; // replace all whitespaces and hyphens by a SQL wildcard
if(isset($_POST['searchById']))
{
$search = mysqli_real_escape_string($connection, $searchReg);
$id = $searchReg;
$query = "SELECT * FROM cars WHERE Registration_Number LIKE '" . strtoupper($id) ."' OR Registration_Number LIKE '" . strtolower($id) . "'" ;
...
I have a dynamic Matrix box where users can unlimited drugs, the data comes through like this:
[addindividuals] => [{"Drug":"Calpol","Strength":"100mg","Form":"Liquid","Quantity":"1"},{"Drug":"Paracetamol","Strength":"200mg","Form":"Tablet","Quantity":"16"}]
What I'm trying to achieve is to have each line inserted into a new row (MySQL) and inserts into their relevant columns like so:
Columns: | Drug | Strength | Form | Quantity
Row1 | Calpol | 100mg | Liquid | 1
Row2 |Paracetamol | 200mg | Tablet | 16
I'm guessing its using the exploded function> (I'm a novice) and then sql to insert the strings?
If you have the values as a json string collection, First you need to explode then the string then use a for each to loop through each string then use another for each to make single row. Please have a below code this may help you.
$addindividuals = '{"Drug":"Calpol","Strength":"100mg","Form":"Liquid","Quantity":"1"},{"Drug":"Paracetamol","Strength":"200mg","Form":"Tablet","Quantity":"16"}';
$exploded_array = explode('},',$addindividuals);
$final_query = "INSERT INTO `table_name` (`Drug`,`Strength`,`Form`,`Quantity`) VALUES ";
$exploded_array[0] = $exploded_array[0].'}';
foreach($exploded_array as $exploded_element)
{
$single_row = '(';
$json_decode = json_decode($exploded_element,true);
foreach($json_decode as $key => $value)
{
$single_row .= "'$value',";
}
$single_row = substr($single_row,0,-1);
$single_row .= '),';
$final_query .= $single_row;
}
$final_query = substr($final_query,0,-1);
echo $final_query;
I hope you can help :)
This is how the table looks:
+------------+----------------+------------------+---------+
| firstName | lastName | email | etc... |
+------------+----------------+------------------+---------+
| John | Doe | john#doe.com | etc... |
+------------+----------------+------------------+---------+
| John | Michaels | john#michaels.es | etc... |
+------------+----------------+------------------+---------+
This is how the code looks:
if($_GET['search-customers'] != '') {
$busqueda = $_GET['search-customers'];
$query->andWhere("(c.firstName LIKE '%$busqueda%' OR c.lastName LIKE '%$busqueda%' OR c.email LIKE '%$busqueda%')");
}
With that QUERY:
If I input: John in the search box, it gives me the 2 results.
OK
If I input: John D in the search box, it doesn't give me any result. FAIL
All right, I understand, When I type "John D", it try to find first in firstName (doesn't match) and also it doesn't match lastName or email.
How can I combine them?
The idea its to find the complete string in all possibilities.
Thanks!
I will provide you a different alternative using MySQL's Full-Text Search Functions. Lets begin to prepare the table:
ALTER TABLE persons ADD FULLTEXT (`firstname`, `lastname`);
Now, firstname and lastname are columns to be used by full-text in order to search for matches:
SELECT * FROM persons
WHERE MATCH (firstname,lastname)
AGAINST ('John D' IN NATURAL LANGUAGE MODE);
The result will be:
+------------+----------------+------------------+---------+
| firstName | lastName | email | etc... |
+------------+----------------+------------------+---------+
| John | Doe | john#doe.com | etc... |
+------------+----------------+------------------+---------+
| John | Michaels | john#michaels.es | etc... |
+------------+----------------+------------------+---------+
Why both? Because John (as a word) was found, however John Doe is in the first row because has much similitude with the term of search.
Say, that lets apply this tool with Doctrine. I will assume that your model looks like this:
class Person{
/** #column(type="string", name="firstname")*/
protected $firstName;
/** #column(type="string", name="lastname")*/
protected $lastName;
/** #column(type="string")*/
protected $email;
}
Lets create the search function:
public function search($term){
$rsm = new ResultSetMapping();
// Specify the object type to be returned in results
$rsm->addEntityResult('Models\Person', 'p');
// references each attribute with table's columns
$rsm->addFieldResult('p', 'firstName', 'firstName');
$rsm->addFieldResult('p', 'lastName', 'lastname');
$rsm->addFieldResult('p', 'email', 'email');
// create a native query
$sql = 'select p.firstName, p.lastname, p.email from persons p
where match(p.firstname, p.lastname) against(?)';
// execute the query
$query = $em->createNativeQuery($sql, $rsm);
$query->setParameter(1, $term);
// getting the results
return $query->getResult();
}
Finnally, and example:
$term = 'John D';
$results = search($term);
// two results
echo count($results);
Additional notes:
Before mysql 5.7, Full-Text only can be added just to MyISAM tables.
Only can be indexed CHAR, VARCHAR, or TEXT columns.
When using IN NATURAL LANGUAGE MODE in a search, mysql returns an empty resultse when the results represent < 50% of the records.
Maybe you could use the explode function like this:
$busqueda = $_GET['search-customers'];
$names = explode(' ',$busqueda);
if(count($names)>1){
$query->andWhere("(c.firstName LIKE '%{$names[0]}%' AND c.lastName LIKE '%{$names[1]}%')");
}else{
$query->andWhere("(c.firstName LIKE '%$busqueda%' OR c.lastName LIKE '%$busqueda%' OR c.email LIKE '%$busqueda%')");
}
but, using like %word% is inefficient, because it can't use index.
Finally, I decided to concat firstName and lastName. I excluded the email then the query looks like that:
$busqueda = $_GET['search-customers'];
$names = explode(' ',$busqueda);
$hasemail = strpos('#', $busqueda);
if ( $hasemail ) {
$query->andWhere("c.email LIKE '%$busqueda%'");
} else {
$query->andWhere("( CONCAT(c.firstName,' ',c.lastName) LIKE '%$busqueda%' OR c.email LIKE '%$busqueda%')");
}
In your repository you could do something like this:
public function findByTerms($terms) : array
{
$alias = "d";
$qb = $this->createQueryBuilder($alias);
foreach (explode(" ", $terms) as $i => $term) {
$qb
->andWhere($qb->expr()->orX( // nested condition
$qb->expr()->like($alias . ".name", ":term" . $i),
$qb->expr()->like($alias . ".description", ":term" . $i)
))
->setParameter("term" . $i, "%" . $term . "%")
;
}
return $qb->getQuery()->getResult();
}
The Query Builder is able to generate complex queries that scale to your needs
Please could someone help me? I want to select all values in mysql table where the column that i want to check get a value is mix with aingle or array of values....... So to be more clear I have a table to store all messages from many sender to one or many reciever....
my functions is
public static function find_messagesTo_by_user_id($mess_to=0) {
global $database;
$mess_to = $database->escape_value($mess_to);
$sql = "SELECT * FROM ".self::$table_name;
$sql .= " WHERE mess_to = '{$mess_to}'";
$sql .= " AND mess_deleted = 0";
$sql .= " ORDER BY mess_created_date DESC";
$result_array = parent::find_by_sql($sql);
return $resultrray;
}
So 'mess_to ' has array and single value .... they are only numbers Like (1, 15, 25 ,26 ,27 , array(1,25, 27) , 31, 42, .......)
Please, i break my head on it :)
I waiting for any help?
Building on #Maluchi's answer. Make sure your data looks like:
| mess_to |
+-----------------+
| ,123, |
| ,123,456,152,1, |
| ,456,567, |
| ,3, |
So surround each value in ,. then you can safely do:
WHERE `mess_to` LIKE "%,{$mess_to},%"
This ensures that $mess_to = 1 will match only the 2nd row, and not the 1st as well.
You could also denormalize your data and make a table to JOIN on.
If I'm reading it correctly, $mess_to is passed into the function and could contain either a single value or it could be passed in an array.
When matching multiple values, the SQL should be looking for a comma-separated list. The where clause needs to be IN the list rather than EQUAL to the list.
Try:
public static function find_messagesTo_by_user_id($mess_to=0) {
global $database;
$mess_to = $database->escape_value($mess_to);
$sql = "SELECT * FROM ".self::$table_name;
$sql .= " WHERE mess_to IN (" . implode(',', $mess_to) . ")";
$sql .= " AND mess_deleted = 0";
$sql .= " ORDER BY mess_created_date DESC";
$result_array = parent::find_by_sql($sql);
return $resultrray;
}
See this line in particular:
$sql .= " WHERE mess_to IN (" . implode(',', $mess_to) . ")";
Code edited with geomagas's comments! (Thank you geomagas!)
asuming your column is like this
| mess_to |
+---------+
| 1 |
| 1,2,3,4 |
| 2 |
| 3 |
you can use the LIKE operator:
$sql .= " WHERE mess_to LIKE '%{$mess_to}%'";
this will match every row where mess_to has the string value of $mess_to (your column data type should be string for this to work).
Logged in $Account = 2; $SearchString = "Sally Do";
$search_array = explode(' ',$SearchString);
People table example:
ID | Account | FirstName | LastName | Misc Other
---------------------------------------------------
1 | 1 | John | Doe | Testing
2 | 2 | John | Doe | Pick Me
3 | 2 | Jonh | Bob | Not Me
If possible I would like to search all table fields without the need to specify them and to escape the values for the LIKE or preferably using CodeIgniter's Active Query.
SELECT * FROM poeple WHERE Account = 2 AND
(
PHP
foreach $search_array
{
FirstName LIKE '%svalue%' OR LastName LIKE '%svalue%'
}
)
Escaping breaks the SQL query and I'm sure I'm probably just doing something wrong...
$this->db->escape($search_array[0]);
$this->db->escape($search_array[1]);
I would much prefer a pure active query but I'm not sure it's possible?
$query = $this->db->select('*')->from('people')->where('Account', $Account)->like(???)->get();
The issue mostly with active query is the lack of ( ) support so the Account doesn't become an OR.
Decided to use an existing escaping function (built into CI) to use with a non-Active Query
function escape_string($str, $like = FALSE)
{
if (is_array($str)){
foreach ($str as $key => $val){
$str[$key] = escape_string($val, $like);
}
return $str;
}
mysql_real_escape_string($str);
if ($like === TRUE){
$str = str_replace(array('%', '_'), array('\\%', '\\_'), $str);
}
return $str;
}
try this way
$this->db->select('*');
$this->db->from('people');
$this->db->where('acount',$account);
if($first_name!='')
{
$this->db->like('first_name',$first_name);
}
if($last_name!='')
{
$this->db->like('last_name',$last_name);
}
Try this one.
$where = "(firstname LIKE '%".$value."%' OR lastname LIKE '%".$value."%')";
$this->db->SELECT('*');
$this->db->from('people');
$this->db->where($where);
$this->db->where('account', $account);
$this->db->get();