Folks, I'm writing a query for a report and since it has a lot of parameters, I decided to write a few functions for it (suggestions are welcome).
In one of my where clauses, I wrote a function that will write the beginning of the clause, then write every item in my array and then close the clause below. This is the function:
function checkStatuses() {
global $status;
echo " tl.task_log_status in (";
foreach ($status as $option) {
echo "'$option', ";
}
echo "'60') AND";
}
Below is my query:
$sql = "SELECT co.company_name as EMPRESA,
p.project_name as PROJETO,
p.project_code as CODIGO,
tk.task_name as TAREFA,
concat(c.contact_first_name,' ',c.contact_last_name) as USUARIO,
DATE_FORMAT(tl.task_log_date, '%d/%m/%Y') as DATA,
tl.task_log_description as DESCRICAO,
tl.task_log_hours as HORAS_REPORTADAS,
tl.task_log_costcode as CODIGO_CUSTO
FROM dotp_task_log tl, dotp_companies co, dotp_tasks tk, dotp_projects p, dotp_users u, dotp_contacts c
WHERE tk.task_id = tl.task_log_task
AND
p.project_id = tk.task_project
AND
u.user_id = tl.task_log_creator
AND
c.contact_id = u.user_contact
AND
co.company_id = p.project_company
AND
co.company_id = $company
AND
$project_code
AND
$status_code
tl.task_log_date BETWEEN '$initial_date' AND '$end_date'
ORDER BY
tl.task_log_date";
Right below this code I echoed $sql to see what's going on, and it shows like this:
tl.task_log_status in ('0', '1', '3', '2', '60') ANDSELECT co.company_name as EMPRESA,
p.project_name as PROJETO,
p.project_code as CODIGO,
As you can see, the where clause is being written before the rest of the $sql variable. Why's that? In my example, I declared variable $status_code = checkStatuses();, but that didn't work. Neither calling the function directly, neither changing from single to double quote. The only way I got to show a part of the where clause in the right location was to replace echo in my function for a return, but I can't have multiple returns in there (the function will end execution and part of the clause will be missing). Any ideas?
It's happening because you're echoing stuff instead of returning it...
function checkStatuses() {
global $status;
$return = "";
$return .= " tl.task_log_status in (";
foreach ($status as $option) {
$return .= "'$option', ";
}
$return .= "'60') AND";
return $return;
}
Related
I've got a form with several different fields used for a search function in my application. There can be any combination for the search parameters, all could be filled or just 1 (or any other).
As of now, the relevant part of the PHP code looks like this (which actually works - but I fear and thinks is a terribly bad design/implementation):
$whereClause = "";
if (!empty($_POST['searchAlias'])) {
$searchAlias = "%{$_POST['searchAlias']}%";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
} else {
$searchAlias = "";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
}
if (!empty($_POST['searchLink'])) {
$searchLink = "%{$_POST['searchLink']}%";
$whereClause .= " AND (posts.homepage LIKE ? OR posts.homepage LIKE ?)";
} else {
$searchLink = "";
$whereClause .= " AND (posts.homepage LIKE ? OR ? = '')";
}
if (!empty($_POST['searchComment'])) {
$searchComment = "%{$_POST['searchComment']}%";
$whereClause .= " AND (posts.comment LIKE ? OR posts.comment LIKE ?)";
} else {
$searchComment = "";
$whereClause .= " AND (posts.comment LIKE ? OR ? = '')";
}
if (!empty($_POST['searchCategory'])) {
$searchCategory = $_POST['searchCategory'];
$whereClause .= " AND (posts.category LIKE ? OR posts.category LIKE ?)";
} else {
$searchCategory = "";
$whereClause .= " AND (posts.category LIKE ? OR ? = '')";
}
$stmt = $connection->prepare("SELECT users.alias, posts.postId,
categories.category, posts.homepage, posts.comment, posts.timestamp,
posts.upvotes FROM ((posts INNER JOIN categories ON posts.category =
categories.id) INNER JOIN users ON posts.userId = users.userId)
WHERE 1=1 $whereClause ORDER BY postId DESC LIMIT 300");
$stmt->bind_param("ssssssss", $searchAlias,$searchAlias,
$searchLink,$searchLink, $searchComment,$searchComment,
$searchCategory,$searchCategory);
I should add that I also have 2 date input fields (from and to date) which can be included in the search as well, they are not added in the current php code since I haven't fixed them yet.
As you can see I make sure that the parameters set from the form data are appended to the whereClause - always with two ? to make sure the bind_param types and variables can remain the same all the time.
So, is this an "acceptable" solution or is there any way to make this a lot cleaner and simpler? I've tried searching for different solutions but im either not good enough searching, or not smart enough understanding the solutions.
Any help or idea is appreciated!
Kind regards,
Eken
Using PDO with named parameters would make this task a bit easier to maintain if/when additional search parameters are added. It would also accommodate search parameters where the value is compared to multiple columns, or require type casting of the search value. You may want to consider adding '%' before and after the values for LIKE conditions. This could be done by adding the $_POST values to an array and binding the array values instead of the $_POST values.
EDIT
I've modified my first posting to search for a matching date, and to allow adding wildcards to like comparisons. The code could also be easily modified to allow for two value checks like between dates.
$postVals = array();
foreach($_POST as $varname => $varval) {
$postVals[$varname] = $varval;
}
$wherePieces = array();
$tests = array(
"searchAlias" => array("where" => "user.alias LIKE :searchAlias","addWildCard" => false),
"searchLink" => array("where" => "posts.homepage LIKE :searchLink","addWildCard" => true),
"searchComment" => array("where" => "posts.comment LIKE :searchComment","addWildCard" => true),
"searchCategory" => array("where" => "posts.category LIKE :searchCategory","addWildCard" => false),
"searchTimestamp" => array("where" => "CAST(posts.timestamp AS DATE) = CAST(:searchTimestamp AS DATE)","addWildCard" => false)
);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
$wherePieces[] = $wherePart['where'];
}
}
$whereClause = "WHERE " . implode(" AND ",$wherePieces);
$qstr = "SELECT
users.alias,
posts.postId,
categories.category,
posts.homepage,
posts.comment,
posts.timestamp,
posts.upvotes
FROM posts
INNER JOIN categories
ON posts.category = categories.id
INNER JOIN users
ON posts.userId = users.userId)
$whereClause
ORDER BY postId DESC
LIMIT 300";
$stmt = $connection->prepare($qstr);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
if($wherePart["addWildCard"]) {
$postVals[$postname] = '%'.$postVals[$postname].'%';
}
$stmt->bindParam(':'.$postname,$postVals[$postname]);
}
}
$stmt->execute();
NOTE: Not tested, could have typos.
I am using mysql as my database and php as server side language.
As we know that we can select data from database using select query.
Below example is important!!
select * from table
select name from table
select name,salary from table where salary > 10000
etc..........
now, for different select query of a table we need different select method. because every time select * is not good because it takes a huge time.
Now, My Question is how write dynamic single get method of a single table by which we can achieve our requirement (shown in example...)?
I will pass the array of parameters in the argument of the function.. for ex. in php
public get($arr)
{
//code goes here
}
I want to fetch the $arr and want to change the sql dynamically..
Don't want any join query just simple select as shown in above..
Depending on how you want to do it, you can do something like this:
public get($arrfield, $arrtable, $arrwhere)
{
$str = "SELECT " . $arrfield . " FROM " . $arrtable . " WHERE " . $arrwhere;
return $str;
// You can return the query string or run the query and return the results
}
Trust me, to write all three queries is not that too hard a job that have to be avoided at any cost.
Please, do not obfuscate a precious SQL language into unreadable gibberish. Not to mention innumerable security breaches of your approach.
What you should think of is a function that lets you to use parameters. Thus, better make our function like this
function mysqli($mysqli, $query, $params, $types = NULL)
{
$statement = $mysqli->prepare($select);
$types = $types ?: str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
return $statement;
}
and run your every query as is, only providing placeholders instead of variables
select * from table:
you'll never need a query like this
select name from table
$names = mysqli($db, "select name from table")->get_result->fetch_all();
`select name,salary from table:
$stmt = mysqli($db, "select name from table where salary > ?", [10000]);
$names = $stmt->get_result->fetch_all();
See - the query itself is the least code portion. Your concern should be not SQL but useless reprtitive parts of PHP code used to run a query and to fetch the data.
Here is the structure of the dynamic query.Please add required validation.You can add 'Or' clause also.On the basis of parameter or data type you can do it. Like
public SelectTable($arrfield, $table, $arrwhere, $arrgroup)
{
if(!empty($arrfield))
{
$fields = implode('`,`',$arrfield);
}
else
{
$fields = '*';
}
if(!empty($arrwhere))
{
foreach($arrwhere as $fieldName=>$fieldValue)
{
if(is_array($fieldValue))
{
$cond .= "`fieldName` in (". implode(',',$fieldValue) );
}
else
$cond .= "`fieldName` = '" . addslashes($fieldValue)."'";
}
}
else
{
$cond = '1';
}
if(!empty($arrgroup))
{
$groupBy .= " group by ";
foreach($arrgroup as $field=>$value)
{
$groupBy .= $field . " " . $vale;
}
}
}
$str = "SELECT " . $fields . " FROM " . $table . " WHERE " . $cond . $groupBy;
return $str;
// You can return the query string or run the query and return the results
}
I built PHP 2 year ago and now i want to change all about database to PDO,i have some problem with update table. I use this function to update table.
public function update($tabel, $fild = null ,$where = null)
{
$update = 'UPDATE '.$tabel.' SET ';
$set=null; $value=null;
foreach($fild as $key => $values)
{
$set .= ', '.$key. ' = :'.$key;
$value .= ', ":'.$key.'":"'.$values.'"';
}
$update .= substr(trim($set),1);
$json = '{'.substr($value,1).'}';
$param = json_decode($json,true);
if($where != null)
{
$update .= ' WHERE '.$where;
}
$query = parent::prepare($update);
$query->execute($param);
$rowcount = $query->rowCount();
return $rowcount;
}
everything work fine using this
$updatefild = array('count' => 20);
$where = "id = '123'";
echo $db->update("mytable",$updatefild, $where);
but i get problem when i want to update row with existing row, in mysql_query I usually use
mysql_query("update mytable set count=count+1 where id='123'");
how i achieve that use PDO ?
thanks
First, why are you using JSON just to decode it into an array? That is confusing.
Secondly, if you were trying to add a number to an existing field, you don't even need prepare().
You could just do
PDO->query("update mytable set count=count+".intval($int)." where id='123'");
If you were doing prepare, you could do:
$stmt = PDO->prepare("update mytable set count=count+:count where id='123'");
$stmt->execute(array(':count' => 1));
or
$stmt = PDO->prepare("update mytable set count=count+? where id='123'");
$stmt->execute(array(1));
Edit: You wouldn't be able to do it with how your function is written as you can't bind column names. PDO will quote it as a standard string. You would have to find a work around, possibly including the =count in the field somehow.
I used this simple following function for my SQL select query:-
I want to be able to count how many queries is being executed when running this function? If this function has been called 10 times then it will be calling SQL query 10 times. How can I output this as string? I tried using
count($sql);
but this produces..
1111111
Which means 7 times, when I try use
array_sum()
it doesn't add all the ones..
any help with this please?
many thanks
public function select($rows = '*', $table, $where = null, $order = null, $limit = null, $echo = null) {
$sql = "SELECT ".$rows." FROM {".$table."}";
if($where != null) {
$sql .= " WHERE ".$where;
}
if($order != null) {
$sql .= " ORDER BY ".$order;
}
if($limit != null) {
$sql .= " LIMIT ".$limit;
}
if($echo != null) {
echo $sql . '<br />';
}
//echo $sql . '<br />';
echo count($sql);
return $sql;
}
The simplest approach would be to wrap your SQL queries into class/function and plant accounting there. Then you just need to init your counter as very first thing in your script. Increase counter on each query. Display counter at the end of your scripts.
But in your case, if your return string "1111" means 4 queries (like each character means single query), then just do ordinary strlen() on that string and you are done.
you can use static variable inside your function and increase it each time.
You could work with a static variable that can be accessed within and outside the function.
public function select (...) {
static $count_sql;
[your function code]
$count_sql++;
}
I am still trying to learn PHP and have some issues with this code. I have a field $youtubeurl in ID_Vehicles and I am trying to output some code if that field has data in it how do I select that field with this join to output the value like the sample below?
function getDealerSettings($vid)
{
include('db.php');
$query = "SELECT banner, ebay_htmlcss FROM ebay_dealersettings INNER JOIN ID_vehicles ON ebay_dealersettings.did=ID_vehicles.did WHERE vid='".$vid."'";
$result = #mysql_query($query);
if ($result)
{
$row = mysql_fetch_assoc($result);
return array("banner" => trim($row['banner']), "css" => str_replace(array("\n", "\t"), " ",$row['ebay_htmlcss']));
}
return "";
}
function getTemplate($vid)
{
$code = "";
extract($this->getDealerSettings($vid));
if (!empty($youtubeurl))
$code .= "$youtubeurl";
Seems like you just need to add that field to your select statement:
$query = "SELECT banner, ebay_htmlcss, youtubeurl FROM ebay_dealersettings INNER JOIN ID_vehicles ON ebay_dealersettings.did=ID_vehicles.did WHERE vid='".$vid."'";
You need to add youtubeurl to the SELECT statement as well as ensuring it's in your return array, then it should work.
I wasn't returning the value in the array return array("banner" => trim($row['banner']),"youtubeurl" => trim($row['youtubeurl']),
Not necessarily an answer, supplements my comment to the question, I couldn't find a $youtubeurl mentioned before the empty check. If the db does not return anything or the query fails, the needed error handling is also not present. I have added simple error handling to the script. the return array contains ($return_array[0]) $errflag, which can be read to see if there was an error, $errmsg is an array containing the error msg, the third element contains your return array.
function getDealerSettings($vid)
{
$errflag=false;
$errmsg=array();
$return=array();
include('db.php');
$query = "SELECT banner, ebay_htmlcss FROM ebay_dealersettings INNER JOIN ID_vehicles ON ebay_dealersettings.did=ID_vehicles.did WHERE vid='".$vid."'";
$result = #mysql_query($query);
if (!$result){
$errflag=true;
$errmsg[]="Error with db connection". mysql_error();
}else{
$row = mysql_fetch_assoc($result);
$return = array("banner" => trim($row['banner']), "css" => str_replace(array("\n", "\t"), " ",$row['ebay_htmlcss']));
}
$return_array=array($errflag, $errmsg, $return);
return $return_array;
}