I am aware this is somehow a noobish question, and I already knkow one option of solving it, but still. I have a database and a search form. What I am trying to accomplish is filter rows specific to what user sends me VIA post. I know how to get POST to my php variables, what I am trying to accomplish now is use variable as criteria only if it is not null. So something in the lines of>
SELECT * FROM db
WHERE COL1=ifnotnull($variable from post form)
AND COL# = ifnotnull($anothervariable)
.
.
.
So I want to include in my search only fileds from form which were entered (i.e. are not null)
I am aware this could be done via preprocessing all variables and checking if they are null and then not using them in SQL query, but is there a shorter way doing this on the fly with SQL?
I hope this I explained it thoroughly,
thanks.
I consider preprocessing all variables as the most preferable approach. But here is tricky solution just for your case. (with mysql user defined variables):
...
$dbh = new PDO(...); // a PDO instance representing a connection to a database
$var1 = 0; // sanitized variable from POST array
$var2 = "pen"; // sanitized variable from POST array
$dbh->exec("SET #var1 := $var1; ");
$dbh->exec("SET #var2 := '$var2'; ");
// replace 'id' and 'name' with your column names
$stmt = $dbh->prepare("SELECT * FROM table_name WHERE (id = #var1 OR #var1 = '') AND (name = #var2 OR #var2 = '') ");
$stmt->execute();
....
Such approach takes into account all passed variables which are not empty
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'm using Postgresql 9.2 and PHP 5.5 on Linux. I have a database with "patient" records in it, and I'm displaying the records on a web page. That works fine, but now I need to add interactive filters so it will display only certain types of records depending on what filters the user engages, something like having 10 checkboxes from which I build an ad-hoc WHERE clause based off of that information and then rerun the query in realtime. I'm a bit unclear how to do that.
How would one approach this using PHP?
All you need to do is recieve all the data of your user's selected filters with $_POST or $_GET and then make a small function with a loop to concatenate everything the way your query needs it.
Something like this... IN THE CASE you have only ONE field in your DB to match with. It's a simple scenario and with more fields you'll need to make it so that you add the field you really need in each case, nothing too complex.
<?php
//recieve all the filters and save them in array
$keys[] = isset($_POST['filter1'])?'$_POST['filter1']':''; //this sends empty if the filter is not set.
$keys[] = isset($_POST['filter2'])?'$_POST['filter2']':'';
$keys[] = isset($_POST['filter3'])?'$_POST['filter3']':'';
//Go through the array and concatenate the string you need. Of course, you might need AND instead of OR, depending on what your needs are.
foreach ($keys as $id => $value) {
if($id > 0){
$filters.=" OR ";
}
$filters.=" your_field = '".$value."' ";
}
//at this point $filters has a string with all your
//Then make the connection and send the query. Notice how the select concatenates the $filters variable
$host = "localhost";
$user = "user";
$pass = "pass";
$db = "database";
$con = pg_connect("host=$host dbname=$db user=$user password=$pass")
or die ("Could not connect to server\n");
$query = "SELECT * FROM table WHERE ".$filters;
$rs = pg_query($con, $query) or die("Cannot execute query: $query\n");
while ($row = pg_fetch_row($rs)) {
echo "$row[0] $row[1] $row[2]\n";
//or whatever way you want to print it...
}
pg_close($con);
?>
The above code will get variables from a form that sent 3 variables (assuming all of them correspond to the SAME field in your DB, and makes a string to use as your WHERE clause.
If you have more than one field of your db to filter through, all you need to do is be careful on how you match the user input with your fields.
NOTE: I did not add it here for practical reasons... but please, please sanitize user input.. ALWAYS sanitize user input before using user controlled data in your queries.
Good luck.
Don't do string concatenation. Once you have the values just pass them to the constant query string:
$query = "
select a, b
from patient
where
($x is not null and x = $x)
or
('$y' != '' and y = '$y')
";
If the value was not informed by the user pass it as null or empty. In the above query the x = $x condition will be ignored if $x is null and the y = '$y' condition will be ignored if $y is empty.
With that said, a check box will always be either true or false. What is the exact problem you are facing?
Always sanitize the user input or use a driver to do it for you!
I have created a Where clause builder exactly for that purpose. It comes with the Pomm project but you can use it stand alone.
<?php
$where = Pomm\Query\Where::create("birthdate > ?", array($date->format('Y-m-d')))
->andWhere('gender = ?', array('M'));
$where2 = Pomm\Query\Where::createWhereIn('something_id', array(1, 15, 43, 104))
->orWhere($where);
$sql = sprintf("SELECT * FROM my_table WHERE %s", $where2);
$statement = $pdo->prepare($sql);
$statement->bind($where2->getValues());
$results = $statement->execute();
This way, your values are escaped and you can build dynamically your where clause. You will find more information in Pomm's documentation.
I'm having problems getting $schoolname to read in the "insert into" mysqlcommand.
I'm just creating a small thing for a fan club that spans a few schools. So i created a different database table for each school. Each school has a unique id, and the table name corresponds to that. The code is below. Please help. Well, the problem area is the insert portion.
"insert into $schoolname ('cat','...)
For some reason $schoolname is not catching with the $_POST if statement
the mysql command " insert into .... " passes values if i specify a hard coded table name, but it does not pass values if i specify the variable ($schoolname) in place of the table name. I need to specify the variable because there a number of schools with each having their own tables.
<?php
require_once('include.php');
include('imageupload.php');
$schoolid='';
if(isset($_GET['schoolid']) && isset($_GET['schoolid']) != '')
{
$schoolid .= 'and id ='.$_GET['schoolid'];
}
$sqlschoolid = "select * from schools where status = 'Active' ".$schoolid;
$resschoolid = $obj->sql_query($sqlschoolid);
$school = $resschoolid[0];
$schoolname = $school['parameter'];
$schoolid2 = $school['id'];
if($_POST)
{
(isset($_POST['pr']) && $_POST['pr'] != "") ? $price=mysql_real_escape_string($_POST['pr']) : $pr="" ;
$sqlclass = "insert into $schoolname(`category`,`type`,`price`,`title`,`description`,`weburl`,`image`,`email`,`phone`,`address`,`city`,`state`,`zip`,`postdate`,`sponser`,`status`)
values('".$_POST['subcategory']."','".$_POST['type']."','".$pr."','".mysql_real_escape_string($_POST['title'])."','".mysql_real_escape_string($_POST['description'])."','".mysql_real_escape_string($_POST['weburl'])."','".$imagename."','".mysql_real_escape_string($_POST['email'])."','".mysql_real_escape_string($_POST['phone'])."','".mysql_real_escape_string($_POST['address'])."','".mysql_real_escape_string($_POST['city'])."','".mysql_real_escape_string($_POST['state'])."','".mysql_real_escape_string($_POST['zip'])."','".date('Y-m-d H:i:s')."','0','Active')";
}
?>
Since you haven't specified what problem you're seeing, this is only a guess:
if(isset($_GET['schoolid']) && isset($_GET['schoolid']) != '')
Shouldn't that be
if(isset($_GET['schoolid']) && $_GET['schoolid'] != '')
As a side note, consider what happens if the user entered the following in schoolid:
0; delete from schools
This is known as SQL Injection, and you should be using "bind variables" instead of building the query by concatenating strings.
The problem seems to be the below query:
$sqlschoolid = "select * from schools where status = 'Active' ".$schoolid;
What is $schoolid variable at the end? I see what is $schoolid variable and I assume that the variable isn't set correctly.
From what I understand is that the above query might be throwing an error and therefore $schoolname isn't populated at all. Can you please try to print how that query looks like?
EDIT 1 Reading the past discussions, it is clear that $schoolname variable is empty, i.e. has no value. It is not the scope issue because from your code $schoolname is in the global scope and is therefore available inside the $_POST IF check. So let us try to debug the code to analyse options:
Can you put an echo $sqlschoolid; just after where you have written the query? This will confirm that the query format is correct
Assuming that the query is good, let us now check if the query is returning the right data? I'm not sure what DB class are you using, so I can't say what does $obj->sql_query() returns? Perhaps the MySQL resultset. Anyways, can you put var_dump($resschoolid) right after where it is initialized? And another var_dump($school) below?
This is how I would like you to put the debug statements:
$sqlschoolid = "select * from schools where status = 'Active' ".$schoolid;
echo $sqlschoolid;
$resschoolid = $obj->sql_query($sqlschoolid);
var_dump($resschoolid);
$school = $resschoolid[0];
var_dump($school);
$schoolname = $school['parameter'];
$schoolid2 = $school['id'];
I hope the above will give more insight into the problem. Let me know if you've any questions.
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 have two dynamic tables (tabx and taby) which are created and maintained through a php interface where columns can be added, deleted, renamed etc.
I want to read all columns simulataneously from the two tables like so;-
select * from tabx,taby where ... ;
I want to be able to tell from the result of the query whether each column came from either tabx or taby - is there a way to force mysql to return fully qualified column names e.g. tabx.col1, tabx.col2, taby.coln etc?
In PHP, you can get the field information from the result, like so (stolen from a project I wrote long ago):
/*
Similar to mysql_fetch_assoc(), this function returns an associative array
given a mysql resource, but prepends the table name (or table alias, if
used in the query) to the column name, effectively namespacing the column
names and allowing SELECTS for column names that would otherwise have collided
when building a row's associative array.
*/
function mysql_fetch_assoc_with_table_names($resource) {
// get a numerically indexed row, which includes all fields, even if their names collide
$row = mysql_fetch_row($resource);
if( ! $row)
return $row;
$result = array();
$size = count($row);
for($i = 0; $i < $size; $i++) {
// now fetch the field information
$info = mysql_fetch_field($resource, $i);
$table = $info->table;
$name = $info->name;
// and make an associative array, where the key is $table.$name
$result["$table.$name"] = $row[$i]; // e.g. $result["user.name"] = "Joe Schmoe";
}
return $result;
}
Then you can use it like this:
$resource = mysql_query("SELECT * FROM user JOIN question USING (user_id)");
while($row = mysql_fetch_assoc_with_table_names($resource)) {
echo $row['question.title'] . ' Asked by ' . $row['user.name'] . "\n";
}
So to answer your question directly, the table name data is always sent by MySQL -- It's up to the client to tell you where each column came from. If you really want MySQL to return each column name unambiguously, you will need to modify your queries to do the aliasing explicitly, like #Shabbyrobe suggested.
select * from tabx tx, taby ty where ... ;
Does:
SELECT tabx.*, taby.* FROM tabx, taby WHERE ...
work?
I'm left wondering what you are trying to accomplish. First of all, adding and removing columns from a table is a strange practice; it implies that the schema of your data is changing at run-time.
Furthermore, to query from the two tables at the same time, there should be some kind of relationship between them. Rows in one table should be correlated in some way with rows of the other table. If this is not the case, you're better off doing two separate SELECT queries.
The answer to your question has already been given: SELECT tablename.* to retrieve all the columns from the given table. This may or may not work correctly if there are columns with the same name in both tables; you should look that up in the documentation.
Could you give us more information on the problem you're trying to solve? I think there's a good chance you're going about this the wrong way.
Leaving aside any questions about why you might want to do this, and why you would want to do a cross join here at all, here's the best way I can come up with off the top of my head.
You could try doing an EXPLAIN on each table and build the select statement programatically from the result. Here's a poor example of a script which will give you a dynamically generated field list with aliases. This will increase the number of queries you perform though as each table in the dynamically generated query will cause an EXPLAIN query to be fired (although this could be mitigated with caching fairly easily).
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
function aliasFields($pdo, $table, $delim='__') {
$fields = array();
// gotta sanitise the table name - can't do it with prepared statement
$table = preg_replace('/[^A-z0-9_]/', "", $table);
foreach ($pdo->query("EXPLAIN `".$table."`") as $row) {
$fields[] = $table.'.'.$row['Field'].' as '.$table.$delim.$row['Field'];
}
return $fields;
}
$fieldAliases = array_merge(aliasFields($pdo, 'artist'), aliasFields($pdo, 'event'));
$query = 'SELECT '.implode(', ', $fieldAliases).' FROM artist, event';
echo $query;
The result is a query that looks like this, with the table and column name separated by two underscores (or whatever delimeter you like, see the third parameter to aliasFields()):
// ABOVE PROGRAM'S OUTPUT (assuming database exists)
SELECT artist__artist_id, artist__event_id, artist__artist_name, event__event_id, event__event_name FROM artist, event
From there, when you iterate over the results, you can just do an explode on each field name with the same delimeter to get the table name and field name.
John Douthat's answer is much better than the above. It would only be useful if the field metadata was not returned by the database, as PDO threatens may be the case with some drivers.
Here is a simple snippet for how to do what John suggetsted using PDO instead of mysql_*():
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
$query = 'SELECT artist.*, eventartist.* FROM artist, eventartist LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch()) {
foreach ($row as $key=>$value) {
if (is_int($key)) {
$meta = $stmt->getColumnMeta($key);
echo $meta['table'].".".$meta['name']."<br />";
}
}
}