I have pre parameters determining what is passed into my query. In one case I want to search for ALL UUIDs, and in another case I want to search for specific UUID numbers. I would like to do this in one query statement instead of breaking it into two seperate calls (like below)
example 1:
$uuidtosearchfor = "1234";
$query = "SELECT ID,name,UUID FROM table where active = 1 AND UUID ='$uuidtosearchfor'";
exmaple 2:
$query = "SELECT ID,name,UUID FROM table where active = 1";
so instead I want this:
if(rule1)
$uuidtosearchfor = "*"; // return everything
else
$uuidtosearchfor = "2134"; // return everything
$query = "SELECT ID,name,UUID FROM table where active = 1 AND UUID = '$uuidtosearchfor' ";
If you use LIKE instead of =, you can use % as wildcard. But LIKE isn't exactly the same as =.
With = you could construct the query as UUID=UUID. The downside is, you cannot use prepared statements and have to take care about escaping the parameter yourself.
Actually, I don't see how any of these makes your life easier. I'd rather construct the query such that the condition is not added if you want to match all uuids.
Related
I have a php search form with two fields. One for $code another for '$name'.The user uses one or the other, not both.
The submit sends via $_POST.
In the receiving php file I have:
SELECT * FROM list WHERE code = '$code' OR name = '$name' ORDER BY code"
Everything works fine, however I would like that $code is an exact search while $name is wild.
When I try:
SELECT * FROM list WHERE code = '$code' OR name = '%$name%' ORDER BY code
Only $code works while $name gives nothing. I have tried multiple ways. Changing = to LIKE, putting in parentheses etc. But only one way or the other works.
Is there a way I can do this? Or do I have to take another approach?
Thanks
If you only want to accept one or the other, then only add the one you want to test.
Also, when making wild card searches in MySQL, you use LIKE instead of =. We also don't want to add that condition if the value is empty since it would become LIKE '%%', which would match everything.
You should also use parameterized prepared statements instead of injection data directly into your queries.
I've used PDO in my example since it's the easiest database API to use and you didn't mention which you're using. The same can be done with mysqli with some tweaks.
I'm using $pdo as if it contains the PDO instance (database connection) in the below code:
// This will contain the where condition to use
$condition = '';
// This is where we add the values we're matching against
// (this is specifically so we can use prepared statements)
$params = [];
if (!empty($_POST['code'])) {
// We have a value, let's match with code then
$condition = "code = ?";
$params[] = $_POST['code'];
} else if (!empty($_POST['name'])){
// We have a value, let's match with name then
$condition = "name LIKE ?";
// We need to add the wild cards to the value
$params[] = '%' . $_POST['name'] . '%';
}
// Variable to store the results in, if we get any
$results = [];
if ($condition != '') {
// We have a condition, let's prepare the query
$stmt = $pdo->prepare("SELECT * FROM list WHERE " . $condition);
// Let's execute the prepared statement and send in the value:
$stmt->execute($params);
// Get the results as associative arrays
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
The variable $results will now contain the values based on the conditions, or an empty array if no values were passed.
Notice
I haven't tested this exact code IRL, but the logic should be sound.
I have a form for users to enter some information. After the form being submitted, it should query a database with the values that the user entered.
My problem here is that if some of the values that the user entered are null, it should remove from the query.
This is my code:
if(isset($_POST['submit']))
{
include("../includes/header.php");
include ("../scripts/db/connect.php");
//Gets variables from $_POST
$negocio = $_POST['negocio'];
$imovel = $_POST['imovel'];
$distrito = $_POST['distrito'];
$concelho = $_POST['concelho'];
$freguesia = $_POST['freguesia'];
$query = "SELECT * FROM imoveis WHERE negocio = $negocio and imovel = $imovel and distrito = $distrito and concelho = $concelho and freguesia = $freguesia";
}
Imagine if $negocio, $imovel, $concelho and $freguesia are equal to null, the query should be:
$query = "SELECT * FROM imoveis WHERE distrito = $distrito;
How can I do this?
Generate your query string dynamcilly depending on which value are set
or not null, and than use that query
Run this code in a seperate file you will understand the point, after removing or adding comment to any variable, ($name,$street, $address or $qualification )
// you will see query will change depending on the set variable,
//I am using these name you can use any name for your variable
$name='my name';
//$address='some where on earth';
$street='this is my street';
//$qualification='i am very much qualified';
//now create the array only with the values which are not empty or not nul,
//I am using empty you can use null if you want with this example you can use any thing.
if(!empty($name)) $query_string_second_part[]=" AND name = '$name'";
if(!empty($address)) $query_string_second_part[]=" AND address = '$address'";
if(!empty($street)) $query_string_second_part[]=" AND street = '$street'";
if(!empty($qualification)) $query_string_second_part[]=" AND qualification = '$qualification'";
//hand type the first part for the query
$query_string_First_Part= "SELECT * FROM myTableName WHERE";
//Implode the array, if you want to see how it look like use echo,
$query_string_second_part= implode(" ", $query_string_second_part);
//as you can see we are adding AND with every value, so we need to remove the first AND
//with one space
//Make sure you give space in the second parameter. else it wont work means "" not correct but " " is correct
//Hint --> use one space in between the double qoutes
$query_string_second_part= preg_replace("/AND/", " ", $query_string_second_part, 1);
//Join the first and second part together to create a full query
$query_string=$query_string_First_Part.$query_string_second_part;
echo ($query_string);//see how our query look like at the moment
You can add an input null check to each clause. So for example where you do this:
distrito = $distrito
You might instead do this:
(distrito = $distrito or $distrito IS NULL)
or perhaps:
(distrito = $distrito or $distrito = '')
Depending on the data types, the actual input being used to build the query, etc. Might take some tweaking and debugging when manually building a query like this (I suspect using prepared statements with query parameters will make this cleaner, as well as more secure), but the idea is the same either way.
Basically you're instructing it to match the row based on the value, or match the row based on the lack of value. So for any given clause, if the supplied value is null/empty, then all rows match and the clause becomes moot.
I'm trying to write a simple, full text search with PHP and PDO. I'm not quite sure what the best method is to search a DB via SQL and PDO. I found this this script, but it's old MySQL extension. I wrote this function witch should count the search matches, but the SQL is not working. The incoming search string look like this: 23+more+people
function checkSearchResult ($searchterm) {
//globals
global $lang; global $dbh_pdo; global $db_prefix;
$searchterm = trim($searchterm);
$searchterm = explode('+', $searchterm);
foreach ($searchterm as $value) {
$sql = "SELECT COUNT(*), MATCH (article_title_".$lang.", article_text_".$lang.") AGINST (':queryString') AS score FROM ".$db_prefix."_base WHERE MATCH (article_title_".$lang.", article_text_".$lang.") AGAINST ('+:queryString')";
$sth = $dbh_pdo->prepare($sql);
$sql_data = array('queryString' => $value);
$sth->execute($sql_data);
echo $sth->queryString;
$row = $sth->fetchColumn();
if ($row < 1) {
$sql = "SELECT * FROM article_title_".$lang." LIKE :queryString OR aricle_text_".$lang." LIKE :queryString";
$sth = $dbh_pdo->prepare($sql);
$sql_data = array('queryString' => $value);
$sth->execute($sql_data);
$row = $sth->fetchColumn();
}
}
//$row stays empty - no idea what is wrong
if ($row > 1) {
return true;
}
else {
return false;
}
}
When you prepare the $sql_data array, you need to prefix the parameter name with a colon:
array('queryString' => $value);
should be:
array(':queryString' => $value);
In your first SELECT, you have AGINST instead of AGAINST.
Your second SELECT appears to be missing a table name after FROM, and a WHERE clause. The LIKE parameters are also not correctly formatted. It should be something like:
sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE '%:queryString%' OR aricle_text_".$lang." LIKE '%:queryString%'";
Update 1 >>
For both SELECT statements, you need unique identifiers for each parameter, and the LIKE wildcards should be placed in the value, not the statement. So your second statement should look like this:
sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE :queryString OR aricle_text_".$lang." LIKE :queryString2";
Note queryString1 and queryString2, without quotes or % wildcards. You then need to update your array too:
$sql_data = array(':queryString1' => "%$value%", ':queryString2' => "%$value%");
See the Parameters section of PDOStatement->execute for details on using multiple parameters with the same value. Because of this, I tend to use question marks as placeholders, instead of named parameters. I find it simpler and neater, but it's a matter of choice. For example:
sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE ? OR aricle_text_".$lang." LIKE ?";
$sql_data = array("%$value%", "%$value%");
<< End of Update 1
I'm not sure what the second SELECT is for, as I would have thought that if the first SELECT didn't find the query value, the second wouldn't find it either. But I've not done much with MySQL full text searches, so I might be missing something.
Anyway, you really need to check the SQL, and any errors, carefully. You can get error information by printing the results of PDOStatement->errorCode:
$sth->execute($sql_data);
$arr = $sth->errorInfo();
print_r($arr);
Update 2 >>
Another point worth mentioning: make sure that when you interpolate variables into your SQL statement, that you only use trusted data. That is, don't allow user supplied data to be used for table or column names. It's great that you are using prepared statements, but these only protect parameters, not SQL keywords, table names and column names. So:
"SELECT * FROM ".$db_prefix."_base"
...is using a variable as part of the table name. Make very sure that this variable contains trusted data. If it comes from user input, check it against a whitelist first.
<< End of Update 1
You should read the MySQL Full-Text Search Functions, and the String Comparison Functions. You need to learn how to construct basic SQL statements, or else writing even a simple search engine will prove extremely difficult.
There are plenty of PDO examples on the PHP site too. You could start with the documentation for PDOStatement->execute, which contains some examples of how to use the function.
If you have access to the MySQL CLI, or even PHPMyAdmin, you can try out your SQL without all the PHP confusing things. If you are going to be doing any database development work as part of your PHP application, you will find being able to test SQL independently of PHP a great help.
I'd like to create a query in MySQL that has an optional value. When the value is specified the query is filtered by that value, when the value is not all rows are returned. Here's the idea:
public function doQuery($item = 'ANY_VALUE') {
$query = "SELECT * FROM table WHERE item = ?";
db->fetchAll($query,array($item))
...
}
doQuery(); // Returns everything
doQuery($item='item1'); // Returns only rows where item = 'item1'
Is there an easy way to do this without creating two query strings depending on the value of $item?
As far as I know, no such "any" placeholder exists.
If you can use LIKE, you could do
SELECT * FROM table WHERE item LIKE '%'
if you can append a condition, you could nullify the item clause like this:
SELECT * FROM table WHERE item = ? OR 1=1
(won't work in your example though, because you are passing "item" as a parameter)
That's all the options I can see - it's probably easiest to work with two queries, removing the WHERE clause altogether in the second one.
This would probably work, but I*m not sure whether it's a good idea from a database point of view.
public function doQuery($item = 'ANY_VALUE') {
$query = "SELECT * FROM table WHERE item = ? OR 1 = ?";
db->fetchAll($query,array($item, ($item == 'ANY_VALUE' ? 1 : 0))
...
}
Better way to do this is first generate sql query from the parameter you need to bother on, and then execute.
function doQuery($params) {
$query = 'SELECT * FROM mytable ';
if (is_array($params) // or whatever your condition ) {
$query .= 'WHERE item = ' . $params[0];
}
$query .= ' ;';
// execute generated query
execute($query);
}
You cannot get distinct results without giving distinct query strings.
Using $q = "... WHERE item = '$item'" you DO create distinct query strings depending on the value of $item, so it is not that different from using
$q = "..." . ($item=='ANY_VALUE' ? something : s_th_else);.
That said I see two or three options:
use function doQuery($item = "%") { $query = "SELECT ... WHERE item LIKE '$item'"; ...}
But then callers to that function must know that they must escape a '%' or '_' character properly if they want to search for an item having this character literally (e.g. for item = "5% alcoholic solution", giving this as argument would also find "50-50 sunflower and olive oil non alcoholic solution".
use function doQuery($item = NULL) { $query = "SELECT ..."; if ($item !== NULL) $query .= " WHERE item = '$item' "; ...} (where I use NULL to allow any other string or numerical value as a valid "non-empty" argument; in case you also want to allow to search for NULL (without quotes) you must choose another "impossible" default value, e.g., [], and you must anyway use a distinct query without the single quotes which however are very important in the general case), or even:
use function doQuery($item = NULL) { if($item === NULL) $query = "SELECT ..."; else $query = "SELECT ... WHERE item = '$item' "; ...}, which is more to type but probably faster since it will avoid an additional string manipulation (concatenation of the first and second part).
I think the 2nd & 3rd options are better than the first one. You should explain why you want to avoid these better solutions.
PS: always take care of not forgetting the quotes in the SQL, and even to properly escape any special characters (quotes, ...) in arguments which can depend on user input, as to avoid SQL injections. You may be keen on finding shortest possible solutions (as I am), but neglecting such aspects is a no-no: it's not a valid solution, so it's not the shortest solution!
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.