I've got 4 variables (year, month, projectcode and type).
So if the person submits the year and leave the other 3 variables blank then the select query must be
select * from table where year(trandate) = $var
But if the user supplies the year & month then the query must be select * from table where year(trandate) = $var and month(trandate) = $var1
If the user selects year, month & projectcode and leave type blank then query must be select * from table where year(trandate) = $var and month(trandate) = $var1 and projcode = $var3
And so on. How do I go about programming this, otherwhise I will have an awful lot of combinations?
Hope the question is clear.
For example this is what I have so far but I can see that there is too much combinations:
if (empty($ej1year) && empty($ej1month) && empty($ej1proj) && empty($ej1type)) {
$rows = mysql_query("SELECT a.employee
,a.trandate
,CONCAT(a.workdone, '-', wc.BriefDescription) as WorkCodeActivity
,CONCAT(a.custname, '-', cl.ShortName) as clientdet
,a.qty
,a.rate
,a.amount
,a.ref
,a.projcode
,a.type
,a.qty*a.rate as costrate
FROM transaction as a
LEFT JOIN workcodes as wc ON a.workdone=wc.WorkCodeNo
LEFT JOIN clients as cl On a.custname=cl.EntityNo");
} elseif (empty($ej1year) && !empty($ej1month)) {
$rows = mysql_query("SELECT a.employee
,a.trandate
,CONCAT(a.workdone, '-', wc.BriefDescription) as WorkCodeActivity
,CONCAT(a.custname, '-', cl.ShortName) as clientdet
,a.qty
,a.rate
,a.amount
,a.ref
,a.projcode
,a.type
,a.qty*a.rate as costrate
FROM transaction as a
LEFT JOIN workcodes as wc ON a.workdone=wc.WorkCodeNo
LEFT JOIN clients as cl On a.custname=cl.EntityNo
where month(trandate) = '$ej1month'");
} elseif
Something like this should work:
<?php
$where = array();
$binds = array();
if ($_POST['month'] !== '') {
$where[] = 'month = ?';
$binds[] = $_POST['month'];
}
if ($_POST['year'] !== '') {
$where[] = 'year = ?';
$binds[] = $_POST['year'];
}
...
$query = 'select * from table where ' . implode(' AND ', $where);
$db->execute($query, $binds);
You'd want to add a check to see if any variables are set. If you don't mind if all are empty, you can change
$where = array();
to
$where = array(1);
Which will end up as "where 1" in the query, effectively selecting everything.
EDIT: I see you are using mysql_ functions, that's not ideal as they are deprecated. You should update to PDO or mysqli ASAP. Here's a version that will work with mysql_
<?php
$where = array();
if ($_POST['month'] !== '') {
$where[] = "month = '" . mysql_real_escape_string($_POST['month']) . "'";
}
if ($_POST['year'] !== '') {
$where[] = "year = '" . mysql_real_escape_string($_POST['year']) . "'";
}
...
$query = 'select * from table where ' . implode(' AND ', $where);
$result = mysql_query($query);
Try this.
if (!empty($year) && empty($month) && empty($projectcode) && empty($type)){
$query = 'select * from table where year(trandate) = $var';
}elseif (!empty($year) && !empty($month) && empty($projectcode) && empty($type)){
$query = 'select * from table where year(trandate) = $var and month(trandate) = $var1';
}elseif (!empty($year) && !empty($month) && !empty($projectcode) && empty($type)){
$query = 'select * from table where year(trandate) = $var and month(trandate) = $var1 and projcode = $var3'
}
Related
I created this simple filter for date interval, and different levels (0,1,2). I have this code so far:
if(isset($_POST['filtersubmit'])){
$datex = str_replace('/', '-', $_POST['firstdate']);
$date1 = date("Y-m-d", strtotime($datex));
$datey = str_replace('/', '-', $_POST['lastdate']);
$date2 = date("Y-m-d", strtotime($datey));
$projects = $_POST['projekt'];
if(isset($date1) && isset($date2)){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE datum BETWEEN
'$date1' AND '$date2' ORDER BY id DESC");
}
if($projects == 0){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE projekt = '0' ORDER BY id DESC") or die(mysqli_errno($conn). '-'. mysqli_error($conn));
} elseif($projects == 1){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE projekt = '1' ORDER BY id DESC") or die(mysqli_errno($conn). '-'. mysqli_error($conn));
} elseif($projects == 2){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE projekt = '2' ORDER BY id DESC") or die(mysqli_errno($conn). '-'. mysqli_error($conn));
}
}
Now if I select just one of these filters, it works good, but if I want both interval and level filters, it doesn't work. I am not really sure how to do it. I am really grateful for any help.
I would use something along these lines, using a prepared statement to protect you from SQL injection. Basically we form arrays of WHERE clauses, parameters and parameter types from each filter if it is present in the $_POST array. These are then imploded into the query, parameters are bound and the query executed.
if (isset($_POST['filtersubmit'])) {
$params = array();
$paramtypes = array();
$wheres = array();
if (isset($_POST['firstdate'], $_POST['lastdate'])) {
$date1 = date_create_from_format('m/d/Y', $_POST['firstdate']);
$date2 = date_create_from_format('m/d/Y', $_POST['lastdate']);
if (!empty($date1) && !empty($date2)) {
array_push($params, $date1->format('Y-m-d'), $date2->format('Y-m-d'));
array_push($paramtypes, 's', 's');
array_push($wheres, 'datum BETWEEN ? AND ?');
}
}
if (isset($_POST['projekt'])) {
$project = $_POST['projekt'];
if (is_numeric($project) && $project >= 0 && $project <= 2) {
array_push($params, $project);
array_push($paramtypes, 'i');
array_push($wheres, 'projekt = ?');
}
}
$sql = 'SELECT * FROM zapasy';
if (count($wheres)) {
$sql .= ' WHERE ' . implode(' AND ', $wheres);
}
$sql .= ' ORDER BY id DESC';
$stmt = $conn->prepare($sql) or die($conn->error);
if (count($wheres)) {
$stmt->bind_param(implode('', $paramtypes), ...$params);
}
$stmt->execute() or die($stmt->error);
// bind results
$stmt->bind_result(/* variables corresponding to each field in SELECT */);
while ($stmt->fetch()) {
// do something with the data
}
}
The Aim
Hi, I'm trying to shorten my code by building the query dynamically based on the $_GET. Current I have every possible If statement with the relevant SELECT query. However I would like to create a dynamic system for feature updates.
Current Progress
//Set Filter based on url
if ($_GET[GAME] != "") { $gameFilter = $_GET[GAME]; } else { $gameFilter = ''; }
if ($_GET[Region] != "") { $regionFilter = $_GET[Region]; } else { $regionFilter = ''; }
if ($_GET[Console] != "") { $consoleFilter = $_GET[Console]; } else { $consoleFilter = ''; }
$result = get_matchfinder($gameFilter, $regionFilter, $consoleFilter);
//The Function
function get_matchfinder($gameFilter, $regionFilter, $consoleFilter) {
//Set Varibles
$database = 'matchFinder';
$order = 'DESC';
$limit = '20';
//Query Function
$connection = connection();
$sql = 'SELECT * FROM '. $database .' WHERE game = "'.$gameFilter.'" AND region = "'.$regionFilter.'" AND console = "'.$consoleFilter.'" ORDER BY ID '. $order .' LIMIT '. $limit .'';
$response = mysqli_query($connection, $sql);
//Return
return $response;
}
Problem
Currenly it works when all of the filters are active but if one of them isn't the whole query fails, I know thats because it is try to SELECT something matching ''.
So my questions is how do I make it search for all when that filters is not set?
You should build the query parts depending on the length of the filter:
$sql = '
SELECT * FROM '.$database.'
';
$filters = array();
if (strlen($gameFilter) > 0) {
$filters[] = 'game = "'.mysqli_escape_string($connection, $gameFilter).'"';
}
if (strlen($regionFilter) > 0) {
$filters[] = 'region = "'.mysqli_escape_string($connection, $regionFilter).'"';
}
if (strlen($consoleFilter ) > 0) {
$filters[] = 'console= "'.mysqli_escape_string($connection, $consoleFilter).'"';
}
if (count($filters) > 0) {
$sql .= ' WHERE '.implode(' AND ', $filters);
}
if (strlen($oder) > 0) {
$sql .= ' ORDER BY ID '.$order;
}
if ($limit > 0) {
$sql .= ' LIMIT '.$limit;
}
$response = mysqli_query($connection, $sql);
What you're doing there is building up an array of conditions, based on the length of the condition. If the condition's input is an empty string, it isn't added to the array. At the end, if there are any filters, use implode to bind the conditions into a string. The way implode works, if there's only one condition, the glue string isn't used.
It also bears mentioning that you are exposing yourself to SQL injection. The above code shows the use of mysqli_escape_string to escape the input, but you should look in to parameterized queries to take full precaution: http://php.net/manual/en/mysqli.quickstart.prepared-statements.php -- the above sample would only be slightly different if you used paraterized queries, but significantly more safe.
Documentation
strlen - http://php.net/manual/en/function.strlen.php
implode - http://php.net/manual/en/function.implode.php
Mysql parameterized queries - http://php.net/manual/en/mysqli.quickstart.prepared-statements.php
You would have to build your search dynamically
You could start your base query with
$sql='SELECT * FROM '. $database .' WHERE 1=1'
Then, if $gameFilter!="", append to your existing $sql string with "and game=$gameFilter"
The syntax for appending would be like this
if ($gameFilter!="")
{
$sql.=' and game=$gameFitler'
}
and so on checking for all of your search conditions.
Make you string like this
$sql = 'SELECT * FROM '. $database .' WHERE 1=1 {0} {1} {2}'
if ( $gameFilter <> '')
$sql = str_replace("{0}", "AND game = '".$gameFilter."'" , $sql);
else
$sql = str_replace("{0}", "" , $sql);
if ( $regionFilter <> '')
$sql = str_replace("{1}", "AND region = '".$regionFilter."'" , $sql);
else
$sql = str_replace("{1}", "" , $sql);
if ( $consoleFilter <> '')
$sql = str_replace("{2}", "AND console = '".$consoleFilter."'" , $sql);
else
$sql = str_replace("{2}", "" , $sql);
Edit: I've changed the query to this version but I'm still not getting any
results even when I should be.
if (isset($_POST['schbttn'])) {
$breed1 = $_POST['schbreed1'];
$breed2 = $_POST['schbreed2'];
$sex = $_POST['schsex'];
$colour = $_POST['schcolour'];
$age = $_POST['schage'];
include ('inc/dbconn.php');
// If breed2 NULL, search with this query
if ($breed2 == "NULL") {
$search = mysqli_query($dbconn, "SELECT * FROM `lstfnd` WHERE `doglf_stat` = 'Lost' AND `doglf_breed1` = '$breed1' AND `doglf_breed2` IS NULL AND `doglf_sex` = '$sex' AND `doglf_colour` = '$colour' AND `doglf_age` = '$age'");
// Else search with this query
} else {
$search = mysqli_query($dbconn, "SELECT * FROM `lstfnd` WHERE `doglf_stat` = 'Lost' AND `doglf_breed1` = '$breed1' AND `doglf_breed2` = '$breed2' AND `doglf_sex` = '$sex' AND `doglf_colour` = '$colour' AND `doglf_age` = '$age'");
}
$schrow = mysqli_fetch_assoc($search);
}
I'm trying to create a simple search function where a user can search by multiple fields.
I've taken the entries of each field
$breed1 = $_POST['breed1'];
$breed2 = $_POST['breed2'];
$sex = $_POST['sex'];
$colour = $_POST['colour'];
$age = $_POST['age'];
and built the query through if loops
$query = "SELECT * FROM `table` WHERE `stat` = 'Lost'";
// If breed1 is not ALL, add to search
if ($breed1 != "ALL") {
$query = $query." AND `breed1` = '$breed1'";
}
// If breed2 is not ALL, add to search
if ($breed2 != "ALL") {
if ($breed2 == "NULL") {
$query = $query." AND `breed2` IS NULL";
} else {
$query = $query." AND `breed2` = '$breed2'";
}
}
// If sex is not ALL, add to search
if ($sex != "ALL") {
$query = $query." AND `sex` = '$sex'";
}
// If colour is not ALL, add to search
if ($colour != "ALL") {
$query = $query." AND `colour` = '$colour'";
}
// If age is not ALL, add to search
if ($age != "ALL") {
$query = $query." AND `age` = '$age'";
}
$query = $query.";";
and placed the query in a PHP variable to use when running the query.
include ('inc/dbconn.php');
$search = mysqli_query($dbconn, "'.$query.'");
$schrow = mysqli_fetch_assoc($search);
However, when I try to display the results of the search, I get an error code.
mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, null given...
So is what I am attempting possible to accomplish using this method? And if not, any suggestions for alternative methods?
change this line
$search = mysqli_query($dbconn, "'.$query.'");
to
$search = mysqli_query($dbconn, $query);
$query is variable, do not use that as string.
My query is working OK. But I am trying to find out the best way to optimize and not have to repeat my $sqlRecCount and $records_count (and would like to know if it's possible to not need to duplicate the GETs). This is what I have now:
if ((int)$_GET['products_id'] === 13) {
$sqlRecCount = "select count(*) as recTotal from table_sql_1";
$recCnt = $db->Execute($sqlRecCount);
$records_count = $recCnt->fields['recTotal'];
}
elseif ((int)$_GET['products_id'] === 2) {
$sqlRecCount = "select count(*) as recTotal from table_sql_2";
$recCnt = $db->Execute($sqlRecCount);
$records_count = $recCnt->fields['recTotal'];
} else {
$records_count = "Updating...";
}
$id = intval($_GET['products_id']);
if ($id == 13 || $id == 2) {
$sqlRecCount = "select count(*) as recTotal from table_sql_" .
($id==13?'1':'2');
$recCnt = $db->Execute($sqlRecCount);
$records_count = $recCnt->fields['recTotal'];
} else {
$records_count = "Updating...";
}
ps: if you have a set of tables without direct correspondence to the product_id you can rewrite snippet as
$id = intval($_GET['products_id']); // casting to int is not required here
$tables = array('13'=>'1', '2'=>'2', and so on);
if (isset($tables[$id])) {
$sqlRecCount = "select count(*) as recTotal from table_sql_" . $tables[$id];
$recCnt = $db->Execute($sqlRecCount);
$records_count = $recCnt->fields['recTotal'];
} else {
$records_count = "Updating...";
}
ps: #downvoter - any comment?
The right way apparently would be
if ($id = (int)$_GET['products_id']) {
$sql = "SELECT count(*) as total FROM table_sql WHERE products_id=$id";
$res = $db->Execute($sql);
$records_count = $res->fields['total'];
}
or something similar according to your db API syntax
I have the following code:
$sql = "SELECT name, address, city FROM tableA, tableB WHERE tableA.id = tableB.id";
if (isset($price) ) {
$sql = $sql . ' AND price = :price ';
}
if (isset($sqft) ) {
$sql = $sql . ' AND sqft >= :sqft ';
}
if (isset($bedrooms) ) {
$sql = $sql . ' AND bedrooms >= :bedrooms ';
}
$stmt = $dbh->prepare($sql);
if (isset($price) ) {
$stmt->bindParam(':price', $price);
}
if (isset($sqft) ) {
$stmt->bindParam(':price', $price);
}
if (isset($bedrooms) ) {
$stmt->bindParam(':bedrooms', $bedrooms);
}
$stmt->execute();
$result_set = $stmt->fetchAll(PDO::FETCH_ASSOC);
What I notice is the redundant multiple IF statements I have.
Question: is there any way to clean up my code so that I don't have these multiple IF statements for prepared statements?
This is very similar to a question a user asked me recently the forum for my book SQL Antipatterns. I gave him an answer similar to this:
$sql = "SELECT name, address, city FROM tableA JOIN tableB ON tableA.id = tableB.id";
$params = array();
$where = array();
if (isset($price) ) {
$where[] = '(price = :price)';
$params[':price'] = $price;
}
if (isset($sqft) ) {
$where[] = '(sqft >= :sqft)';
$params[':sqft'] = $sqft;
}
if (isset($bedrooms) ) {
$where[] = '(bedrooms >= :bedrooms)';
$params[':bedrooms'] = $bedrooms;
}
if ($where) {
$sql .= ' WHERE ' . implode(' AND ', $where);
}
$stmt = $dbh->prepare($sql);
$stmt->execute($params);
$result_set = $stmt->fetchAll(PDO::FETCH_ASSOC);
Instead of if else just use PHP ternary operator
if (isset($_POST['statusID']))
{
$statusID = $_POST['statusID'];
}
else
{
$statusID = 1;
}
instead of that you can do:
$statusID = (isset($_POST['statusID'])) ? $_POST['statusID'] : 1;
The format of the ternary operator is: $variable = condition ? if true : if false
The beauty of it is that you will shorten your if/else statements down to one line and if compiler ever gives you errors, you can always go back to that line instead of 3 lines.