Search multiple fields MySQL - php

I have a database like this :
ID | Name | Model | Type
1 | Car | 4 | C
2 | Bar | 2 | B
3 | Car | 4 | D
4 | Car | 3 | D
And a form like this :
Name :
Model :
Type :
Now, I would like to search only the name, for example "Car" and it returns lines 1, 3, 4. (I left Model and Type empty)
If I search "Car" in Name and 4 in Model, it returns lines 1, 3. (I left Type empty)
And if I search "Car" in Name and "D" in Type, it returns line 3, 4 (I left Model empty)
Is it possible to do this in one query ?
This is what I had :
SELECT *
FROM items
WHERE (:name IS NOT NULL AND name = :name)
AND (:model IS NOT NULL AND model = :model)
AND (:type IS NOT NULL AND type = :type)
But it doesn't work.
I would like to fill only 2 on 3 fields and the the "WHERE" adapts and ignore the blank field.
EDIT 1 : It is a little hard to explain but I have a form. I want to have only one required field, the two others are optional but if I also fill the one other or two others fields, they act like a filter.
So the name field is required (in the form). If I fill only the name field, it will select only where name = :name.
If I fill name + model, it will select where name = :name AND model = :model.
and so on...
Thank you for your help.

I'm not sure what you mean by "blank", but assuming you mean NULL, you can do something like this:
SELECT *
FROM items
WHERE (:name IS NULL OR name = :name) AND
(:model IS NULL OR model = :model) AND
(:type IS NULL OR type = :type);
That problem with this query is that it is very hard for MySQL to use indexes for it, because of the or conditions. If you have a large amount of data, and want to use indexes, then you should construct the where clauses based on the parameters that actually have data.

Here's an alternative approach using PHP. You'll need to update the variables.
<?php
$query = 'SELECT *
FROM items
WHERE 1 = 1 ';
//below used for testing can be remove
//$_GET['name'] = 'test';
//$_GET['car'] = 'test2';
//$_GET['type'] = 'test3';
if(!empty($_GET['name'])) {
$query .= ' and name = ? ';
$params[] = $_GET['name'];
}
if(!empty($_GET['car'])) {
$query .= ' and car = ? ';
$params[] = $_GET['car'];
}
if(!empty($_GET['type'])) {
$query .= ' and type = ? ';
$params[] = $_GET['type'];
}
if(!empty($params)) {
$dbh->prepare($query);
$sth->execute($params);
//fetch
} else {
echo 'Missing Values';
}
The 1=1 is so you can append and search field for each field with a value otherwise you'd need to see if it'd already been set.

Related

Search bar should ignore “-”, Caps and spaces (132D123 and 132 d 123 should return true) ? php

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) . "'" ;
...

How to echo a PHP variable from MySQL results

To automate my PHP to generate JSON, I saved the name of variable in database
(e.g. > $test_value_1).
In my php file I have the value of this variable (e.g. > $test_value_1 = "TEST VALUE 1")
After this I do a query to echo this variable, but, instead of returning the value of variable (TEST VALUE 1), always return just the text save in database ("$teste_value_1")
To understand better, look my database, variable, query, response and what I need:
TABLE: attributes
id_attribute | attribue_string | attribute_value
1 | test_string_1 | $test_value_1
2 | test_string_2 | $test_value_2
VARIABLES:
$test_value_1 = "Test Value 1";
$test_value_2 = "Teste Value 2";
QUERY:
$query_array = mysqli_query($connect,"
SELECT GROUP_CONCAT(CONCAT('{id:', a.attribute_string, ',value_name:', a.attribute_value, '}') SEPARATOR ', ') AS concat
FROM rel_categories_attributes AS rca
INNER JOIN categories AS c ON c.id_category = rca.categories_id_category
INNER JOIN attributes AS a ON a.id_attribute = rca.attributes_id_attribute
WHERE id_category = '{$id_category}'
");
WHILE ($reg_cat = mysqli_fetch_array($query_array)){
echo $teste_query = $reg_cat["concat"] . ",";
RESPONSE: {id:test_string_1,value_name:$test_value_1}, {id:teste_string_2,value_name:$test_value_2}, (WRONG)
WHAT I NEED: {id:test_string_1,value_name:TEST VALUE 1}, {id:teste_string_2,value_name:TESTE VALUE 2},
While this seems like a horrible design, you can do it using variable variables. But you'll need to do the output formatting in PHP, not in MySQL.
$query_array = mysqli_query($connect,"
SELECT a.attribute_string, a.attribute_value
FROM rel_categories_attributes AS rca
INNER JOIN categories AS c ON c.id_category = rca.categories_id_category
INNER JOIN attributes AS a ON a.id_attribute = rca.attributes_id_attribute
WHERE id_category = '{$id_category}'
");
$result = array();
while ($row = mysqli_fetch_assoc($query_array) {
$result[] = array('id' => $row['attribute_string'], 'value_name' => ${$row['attribute_value']});
}
echo json_encode($result);
However, variable variables can almost always be improved by using an associative array. Instead of having variables like $test_value_1 and $test_value_2, create an array whose keys are "test_value_1" and "test_value_2", and then use $array[$row['attribute_value']].
But even better would be to put all the details in the database itself, rather than hard-coding them in the scripts. You can then join with that table to translate the attribute value to the appropriate string.

How can I select data from table based on one or multiple condition?

I am working using MySQL/PHP, I wanted to select data from a table based on one or more condition but using minimum if statements.
For example if I have a table
Students | Register | End | Points
Mark | 14/1 | 18/6 | 14
Dina | 18/12 | 19/2 | 1
Karl | 1/1 | 1/2 | 9
I have a form where user can look for data based on one or more criteria (register, end, points) based on the data he chose to set.
If he only set one of the criteria lets say after an date, he will get all results based on that date.
If he set two or three conditions maybe (register and end) or (end and points) or even (register and end and points) he will get the result based on all conditions joint together not only one of them or all of them separately.
when I use AND between conditions and the user don't set one of the conditions it returns empty query.
when I use OR between conditions and the user choose multiple conditions it returns data but based on each of conditions separately not joining it.
Queries I tried:
SELECT * FROM table WHERE Register >= '$choice1' OR End <= '$choice2' OR Points = '$choice3';
SELECT * FROM table WHERE Register >= '$choice1' AND End <= '$choice2' AND Points = '$choice3';
What is the best way to do that?
Use php to build your WHERE clause, something like this:
$condition = '';
if($choice1 != '')
$condition .= "Register >= '$choice1'";
if($choice2 != '')
$condition .= ($condition != '' ? " AND " : '') . "End <= '$choice2'";
if($choice3 != '')
$condition .= ($condition != '' ? " AND " : '') . "Points = '$choice3'";
$sql = "SELECT * FROM table" .($condition != '' ? " WHERE $condition;" : ";");

PHP profile columns visibility + MySQL

I'm seeking for the best method to implement the column visibility in users profile.
Imagine the following scenario:
Name : stackoverflow | [checkbox] visible = 1
Address: New York | [checkbox] visible = 0
Phone : 312 021 11 | [checkbox] visible = 1
Email : stack#stack.com | [checkbox] visible = 1
With this, I have two tables: profile and profile_visibility
profile
ID
ID_User (joins with the User table)
Address
Phone
Email
profile_visibility
ID
ID_User (joins with the User table)
Address
Phone
Email
The fields of profile_visibility are all (except id_user and id) of tinyint data.
Now, I would like to make a loop to all columns to check if that column is visibile or not, instead of making conditions (because I have more than that columns). Something like:
$profile = $this->profile($id); // gets the info (as array) of profile
$visibility = $this->profile_visibility($id); // gets the visibility of fields
for($i = 0; $i <= sizeof($profile) - 1; $i++){
/* I can't match $profile with $visibility because the values are different..
$profile[$i]['name'] == $visibility[$i]['name']
$profile[$i]['name'] > it's equal to: 'stackoverflow'
$visibility[$i]['name'] > it's equal to: '1'
*/
}
EDIT: Solved -> But it's not the best solution, see #niyou solution.
foreach($visibility as $key => $val) {
if($val == 1){
if(array_key_exists($key, $profile)){
$content .= "<tr>
<td class='text-align-right'>
<b>" . ucfirst($key) . "</b>:
</td>
<td class='width-100'>" . $profile[$key] . "</td>
<td>
</td>
</tr>";
}
}
}
I think its a matter of your design:
I would create a table profile_fields where i define my possible data fields
profile_fields: field_id,field_name,field_position,...
My other Table holds the information whether a field ist visible or not for a user - named user_fields
user_fields: user_field_id, user_id, field_id, visible
Now you can easily query only those fields which are visible for a user:
SELECT field_id, field_name
FROM profile_fields
LEFT JOIN user_fields USING (field_id)
WHERE user_id=$user_id AND visible=true

Wrong data retrieved from database

So, I want to retrieve the order of the elements of a list. The order is set before by the user, and are stored in the table below. Because I also want to retrieve name and description of the list elements I need to combine two tables (see below).
However, what is actually retrieved is an array containing 16 elements (should be four because it only exists four elements as for now). The array is too long to post here, but I put it in a phpFiddle to be found here if you're interested.
Well, I have really tried to find what's wrong (probably something easy as always), but with no luck.
Thanks a lot for your time and help!
listModel.php:
public function GetOrderedElements($userId, $listId) {
// $userId = 46
// $listId = 1
$query = "SELECT le.listElemId, le.listElemName, le.listElemDesc, lo.listElemOrderPlace
FROM listElement AS le
INNER JOIN listElemOrder AS lo
ON le.listId = lo.listId
WHERE lo.userId = ?
AND lo.listId = ?
ORDER BY listElemId";
$stmt = $this->m_db->Prepare($query);
$stmt->bind_param("ii", $userId, $listId);
$listElements = $this->m_db->GetOrderedElements($stmt);
return $listElements;
}
database.php:
public function GetOrderedElements(\mysqli_stmt $stmt) {
if ($stmt === FALSE) {
throw new \Exception($this->mysqli->error);
}
if ($stmt->execute() == FALSE) {
throw new \Exception($this->mysqli->error);
}
if ($stmt->bind_result($listElemId, $listElemName, $listElemDesc, $listElemOrderPlace) == FALSE) {
throw new \Exception($this->mysqli->error);
}
$listElements = array();
while ($stmt->fetch()) {
$listElements[] = array('listElemId' => $listElemId,
'listElemName' => $listElemName,
'listElemDesc' => $listElemDesc,
'listElemOrderPlace' => $listElemOrderPlace);
}
var_dump($listElements);
$stmt->Close();
return $listElements;
}
from the database:
listElemOrder:
listElemOrderId | listId | listElemId | userId | listElemOrderPlace
1 1 1 46 1
4 1 2 46 4
2 1 3 46 2
3 1 4 46 3
listElement:
listElemId | listElemName | listId | listElemDesc | listElemOrderPlace
1 Elem A 1 Derp NULL
2 Elem B 1 Herp NULL
3 Elem C 1 Lorum NULL
4 Elem D 1 Ipsum NULL
Note: 'listElemOrderPlace' in the table listElement is the final order of the elements (all users average), not to be mixed with the one with the same name in the other table, that's only a specific user's order of the list elements (which is the interesting one in this case).
You forgot to add listElemId to your join criteria:
FROM listElement AS le
INNER JOIN listElemOrder AS lo
ON le.listId = lo.listId
AND le.listElemId = lo.listElemId -- add this criterion
Since the columns are named identically in both tables, you can abbreviate to:
FROM listElement AS le
INNER JOIN listElemOrder AS lo
USING (listId, listElemId)
This second form also has the advantage of avoiding "ambiguous column" errors when there is in fact no ambiguity.

Categories