Bind sort attribute in SELECT Statement - php

For a SELECT query with a sort order I prepare this statement :
$direction = 'DESC';
$project_id = 1;
$query = $this->connection->prepare('SELECT text FROM marker WHERE project_id = :project_id ORDER BY time :direction');
$query->bindValue(':project_id', $project_id, PDO::PARAM_INT);
$query->bindValue(':order', $direction, PDO::PARAM_STR);
$success = $query->execute();
But it fails. So I prepare this statement :
$query = $this->connection->prepare('SELECT text FROM marker WHERE project_id = :project_id ORDER BY time '.$direction.'');
$query->bindValue(':project_id', $project_id, PDO::PARAM_INT);
$success = $query->execute();
And it works.
Can one not bind a ORDER attribute ?
How to bind ORDER attributes properly ?

You can express what you want with a case statement. Here is a relatively simple expression:
order by (case when :order = 'DESC' then time end) DESC,
time ASC

Related

Fetch row with the highest id column value [duplicate]

This question already has answers here:
Select the most recent 5 rows based on date
(2 answers)
Closed 2 years ago.
I would like to reuse a query with concatenation but It seems not working.
I have this for counting rows (working):
$q = $db->prepare("SELECT id, image_date, image_link, image_name, image_category FROM image WHERE image_date < NOW() AND image_category= :category";
$q->bindValue(':category', $category, PDO::PARAM_STR);
$q->execute();
$row = $q->fetchColumn();
And I would like to concatenate with that to use data (not working):
$q .= " ORDER BY id DESC LIMIT :limit");
$q->bindValue(':limit', 1, PDO::PARAM_INT);
$q->execute();
I've also test with that form but not working :
$q=$q. " ORDER BY id DESC LIMIT :limit");
The problem with PDO is that you have to prepare a query before you can bind anything, and once prepared, a query obviously cannot be extended anymore.
Besides, your first query does anything but count. So the simpler the better - just run two separate queries without concatenation
$q = $db->prepare("SELECT count(*) FROM image WHERE image_date < NOW() AND image_category= ?";
$q->execute([$category]);
$count = $q->fetchColumn();
And then
$q = $db->prepare("SELECT id, image_date, image_link, image_name, image_category
FROM image WHERE image_date < NOW() AND image_category= ? ORDER BY id DESC LIMIT ?";
$q->execute([$category, $limit]);
$rows = $q->fetchall();
You need to append the second part to the SQL string,
but not to the Prepared Statement variable $q.
$sql = "SELECT id, image_date, image_link, image_name, " .
"image_category FROM image WHERE image_date < NOW() " .
"AND image_category= :category ORDER BY id DESC LIMIT :limit";
$q = $db->prepare($sql);
$q->bindValue(':category', $category, PDO::PARAM_STR);
$q->bindValue(':limit', 1, PDO::PARAM_INT);
$q->execute();
$row = $q->fetchColumn();

Unable to run named placeholder for order by ASC in php pdo

I am new to PHP PDO and trying to use named placeholder at the place of ORDER BY ASC. Sometime in simple query page this run very successfully but unable to run in the following query:
PHP CODE IS:
$price_sort = "ASC";
$keyword = "samsung glaxy";
$limit = 0;
$query = $db->prepare("SELECT *, MATCH(title) against (:keyword) as 'relevence'
FROM view_store_items_grid
WHERE MATCH(title) against(:keyword)
ORDER BY relevence DESC, price :order
LIMIT :limit,25");
$query->bindValue(":keyword",$keyword);
$query->bindValue(":order",$price_sort);
$query->bindValue(":limit", $limit, PDO::PARAM_INT);
$query->execute();
When I remove placeholder :order with ASC this run and gives result but when I use this placeholder, I get empty result.
For Fetching data or to show fetched result I am using
while ($row = $query->fetch(PDO::FETCH_ASSOC)) :
extract($row);
echo "$name";
endwhile;
What I am doing wrong and How I can use many named placeholder in query at different places?
You should not bind ASC/DESC in prepared statement. Parameters are automatically quoted, and ASC/DESC shouldn't be quoted. this is the same reason that table and column names can't be parameters.
Instead you can do like that
$sql_query = "SELECT *, MATCH(title) against (:keyword) as 'relevence'
FROM view_store_items_grid
WHERE MATCH(title) against(:keyword)
ORDER BY relevence DESC, price "
if($price_order == 'ASC'){
$sql_query .= " ASC "
}else{
$sql_query .= " DESC "
}
$sql_query .= " LIMIT :limit,25 "
$query = $db->prepare($sql_query);
Refer How bindValue in LIMIT
Refer pdo binding asc/desc order dynamically
Also do not try to use the same named parameter twice in a single SQL statement, for example
<?php
$sql = 'SELECT * FROM some_table WHERE some_value > :value OR some_value < :value';
$stmt = $dbh->prepare($sql);
$stmt->execute( array( ':value' => 3 ) );
?>
...this will return no rows and no error -- you must use each parameter once and only once. Apparently this is expected behavior (according to this bug report: http://bugs.php.net/bug.php?id=33886) because of portability issues.
This one solved this question by replacing the price_sort variable value with price ASC and removing the price before the placehoder :order
as:
$price_sort = "price ASC";
and the query is as:
$query = $db->prepare("SELECT *, MATCH(title) against (:keyword) as 'relevence'
FROM view_store_items_grid
WHERE MATCH(title) against(:keyword)
ORDER BY relevence DESC, :order
LIMIT :limit,25");
this solved my question with the help of answer of #tamil
Thank you

MySqli LIKE query not matching number of parameter

The following query is resulting in the browser printing a
"does not match number of parameters"
type of error.
Why is this happening?
When I replace with LIKE '%".$country."%' and get rid of the bind_param it does not bring up any errors.
$query = "
SELECT * from (
SELECT link
FROM items
WHERE countries LIKE '%?%'
ORDER BY value DESC
LIMIT 10
) T ORDER BY RAND()
LIMIT 1
";
if ($statement = $mysqli->prepare($query))
{
$statement->bind_param("s", $country);
$statement->execute();
$statement->store_result();
$statement->bind_result($link);
$statement->fetch();
$statement->free_result();
$statement->close();
}
I'd like to prepare the statement instead of inserting raw data into the query.
% must be part of the value :
$query = "
SELECT * from (
SELECT link
FROM items
WHERE countries LIKE ?
ORDER BY value DESC
LIMIT 10
) T ORDER BY RAND()
LIMIT 1
";
if ($statement = $mysqli->prepare($query))
{
$statement->bind_param("s","%".$Country."%");
$statement->execute();
$statement->store_result();
$statement->bind_result($link);
$statement->fetch();
$statement->free_result();
$statement->close();
}
You can use it like
$country = "%{$country}%";
$query = "
SELECT * from (
SELECT link
FROM items
WHERE countries LIKE ?
ORDER BY value DESC
LIMIT 10
) T ORDER BY RAND()
LIMIT 1
";
if ($statement = $mysqli->prepare($query))
{
$statement->bind_param("s", $country);
$statement->execute();
$statement->store_result();
$statement->bind_result($link);
$statement->fetch();
$statement->free_result();
$statement->close();
}

reducing mysql statements that differ only in ORDER BY field name

I'm trying to sort data by different fields ascending and descending. But I have different mysql pdo statements for the 4 fields I have (8 queries total):
$stmt1 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field1 DESC");
$stmt2 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field1 ASC");
$stmt3 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field2 DESC");
$stmt4 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field3 ASC");
$stmt5 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field3 DESC");
$stmt6 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field3 ASC");
$stmt7 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field4 DESC");
$stmt8 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field4 ASC");
Based on input, I pick the right statement and bind and execute it.
if ($sortcode == 1){
$stmt1->bindParam(':categ', $categ, PDO::PARAM_STR);
$stmt1->execute();
$fetched = $stmt1->fetchAll(PDO::FETCH_ASSOC);
} else if ($sortcode == 2){
$stmt2->bindParam(':categ', $categ, PDO::PARAM_STR);
$stmt2->execute();
$fetched = $stmt2->fetchAll(PDO::FETCH_ASSOC);
} else if ($sortcode == 3){
$stmt3->bindParam(':categ', $categ, PDO::PARAM_STR);
$stmt3->execute();
$fetched = $stmt3->fetchAll(PDO::FETCH_ASSOC);
}
//repeat the block 5 more times, for a total of 8
This doesn't look right at all. Since the select statements only differ int he name of the field and the desc/asc, is there a better way to get the $sortcode and compact the code that follows?
I guess I could state the question more specifically as: is there a way I could have a single statement/single pdo statement that binds the field name and asc/decs dynamically?
Use associative arrays to hold the prepared statements.
Your input is a column and a sorting method, right? So prepare the queries by:
$columns = array("field1", "field2", "field3", "field4");
$orders = array("asc", "desc");
$queries = array();
foreach($columns as $col) {
$queries[$column] = array();
foreach ($orders as $order) {
$queries[$column][$order] = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY $column $order");
}
}
Now, to look up the correct query, you don't need some synthetic code -- you just look it up by column and order directly.
To look up a query, instead of having your users input a number from 1-8, have them input a column and an order. Imagine that the column is in the variable $col and the order is in $ord. Just say $queries[$col][$ord].
If for some reason you have to use the number (why?), then you need a slightly different strategy. In that case, you store the queries by that number.
$columns = array("field1", "field2", "field3", "field4");
$orders = array("asc", "desc");
$queries = array();
$i = 0;
foreach($columns as $col) {
foreach ($orders as $order) {
$i = $i + 1;
$queries[$i] = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY $column $order");
}
}
In other words, you ought to be storing queries according to how you plan to look them up.
You can order by column number, which can be parameterized. Using an ORDER BY in this fashion is usually clearer if you specify the columns in the select clause. I'm not sure if ASC/DESC can be parameterized, though...
You can always build the queries dynamically. Store the map between $sortcode and the columns, the SELECT * FROM tabname WHERE categ=:categ part of the query, get the right column name based on $sortcode and add the ORDER BY ... part.

pdo binding asc/desc order dynamically

Let's say I have 2 pdo statements that differ only in order (asc vs. desc)
$stmt1 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field1 DESC");
$stmt2 = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field1 ASC");
Is there a way I can bind ASC/DESC dynamically so I can have only 1 stmt
$order = "ASC"; //or "DESC"
$stmt = $po->prepare("SELECT * FROM tabname WHERE categ=:categ ORDER BY field1 order=:order");
$stmt->bindParam(':order', $order, PDO::PARAM_STR);
no. parameters are automatically quoted, and ASC/DESC shouldn't be quoted. this is the same reason that table and column names can't be parameters.
What I did was create a variable in $_session called "task_order" and set it to 0 by default. Then, in the sql statement I call a private function/switch statement that determines if ASC or DESC should be added to the sql statement. If it's 0, then it returns "ASC" and sets "task_order" to 1. If it's 1, it does the opposite. So it works like a "toggle" mechanism.
I understand this is an old question/topic, but I stumbled upon it be searching, so maybe someone else will as well. If you have a better idea, please share!
EDIT:found some old code:
$sql = "SELECT * FROM tasks WHERE owner = ? ORDER BY priority " . $this->check_sort_status() . "";
and the method that I call is :
public function check_sort_status() {
switch ($_SESSION["asc"]) {
case 0:
$_SESSION["asc"] = 1;
return "ASC";
case 1:
$_SESSION["asc"] = 0;
return "DESC";
}

Categories