Pseudocode
$res = Query("SELECT * FROM `table` ORDER BY `date` DESC LIMIT 15");
SortArray(&$res, 'date', 'asc');
If describe in words, then take the last part of the data is sorted in descending order from the database, but to give the data sorted in ascending order.
Try:
$res = Query("SELECT * FROM ( SELECT * FROM `table` ORDER BY `date` DESC LIMIT 15) ORDER BY `date` ASC");
You can use a usort function to sort the array by specific key:
$res_array=array();
while($row=mysql_fetch_row($res))
$res_array[]=$row;
$new_arr = usort($res_array,"my_func");
function my_func($a, $b)
{
if ($a['date'] == $b['date']) {
return 0;
}
return ($a['date'] < $b['date']) ? -1 : 1;
}
*may need some debugging. take the idea.
Instead of making some magical SQL query, you should select 15 first rows in descending order. And then just read the results from the end.
$statement = $pdo->query('SELECT * FROM `table` ORDER BY `date` DESC LIMIT 15');
if ( ! $statement->execute())
{
throw new Exception('query failed !');
}
$data = $statement->fetchAll(PDO::FETCH_ASSOC);
while ( $row = array_pop($data))
{
var_dump( $row );
}
Related
I have a page where I display all products in stock, I want them to be ordered by ID or name or Date etc.
A way to do it is by getting the order by a link on table row title and get it like this
$order_by = $_GET['order'];
if (!empty($order_by)) {
echo "id";
} else {
echo "$order_by";
}
Now we must in some way echo this to the query but I do not know how, the query is like this:
$result = mysqli_query($database,"SELECT * FROM `stock` order by `id` ASC");
$rows = mysqli_num_rows($result);
if (mysqli_num_rows($result) > 0) {
I tried inserting the entire PHP $order_by replacing the order by 'id' but it gives me errors.
Any idea how to echieve this?
First you need to check if $_GET['order'] is valid, to do that use in_array() and check if order received is in an array of allowed values ( whitelist array ). I don't think that mysqli_real_escape_string() is enough to protect order by clause becouse it is a column name, not a value. If validation fails use the default column name ( id ).
$order_whitelist = [ 'id', 'name', 'date' ];
if ( !empty( $_GET['order'] ) && in_array( $_GET['order'], $order_whitelist, true ) )
$order_by = $_GET['order'];
else
$order_by = 'id';
Now it is safe to build a query, for that purpose sprintf() function can be useful.
$result = mysqli_query( $database, sprintf( "SELECT * FROM `stock` order by `%s` ASC", $order_by ) );
The entire "order by " does not need to be replaced. Just insert what you want order by.
<?php
$order_by = $_GET['order'];
if(!empty($order_by)){
$result=mysqli_query($database,"SELECT * FROM `stock` order by `".$order_by."` ASC");
$rows=mysqli_num_rows($result);
if(mysqli_num_rows($result)>0) {do something}
?>
Note that this is not sanitized and can lead to SQL injection.
You can use something like this :-
$order_by = $_GET['order'];
if(empty($order_by)){
$order_by='id';
}
if(!empty($order_by)){
$result=mysqli_query($database,"SELECT * FROM `stock` order by `".$order_by."` ASC");
$rows=mysqli_num_rows($result);
if(mysqli_num_rows($result)>0){
$sql = "SELECT `url`,`title`,`vid` FROM `video` ORDER BY `time` DESC limit 15";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
This SQL can select the top new 15 rows data.
I want display the top new 100, but just show 15
How to select faster?
$sql = "SELECT `url`,`title`,`vid` FROM `video` ORDER BY `time` DESC limit 100";
i assume that $row[0] => gives first record.
--
function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
$numbers = range($min, $max);
shuffle($numbers);
return array_slice($numbers, 0, $quantity);
}
--
foreach (UniqueRandomNumbersWithinRange(0,100,15) as $row_number)
{
$content=$row[$row_number];
echo $content['title'];
}
Well you could try fixing it like:
<?php
//get the max count for the table;
$max="SELECT id FROM video order by time desc LIMIT 1";
$start="SELECT id FROM video order by time desc LIMIT 100, 1";
$page_size=15;
$rand_no=rand(start,$max - page_size);
$result_set="SELECT * FROM video order by time LIMIT $rand_no,page_size";
NB: it's an abstract code explains the logic.
Below is my code
$stmt = $db->prepare("SELECT * FROM inbox ORDER BY `date` DESC ");
$stmt->execute(array());
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
$uniques = count(array_unique($row, SORT_REGULAR));
for ($i=0; $i < $uniques; $i++) {
$inbox_id = $row[$i]["inbox_id"];
$stmt = $db->prepare("SELECT * FROM messages WHERE inbox_id=? AND seen=? ORDER BY `date` DESC");
$stmt->execute(array($inbox_id, 0));
$row_msg = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
return $row_msg;
But this is nor returning all data.It is only returning values got from first iteration only.
you can use:
$row_msg[$i] = $stmt->fetchAll(PDO::FETCH_ASSOC);
Your PDO statement is prepared every round inside the loop, that is not necessary and i hope the inbox_id column is a primary key in the inbox table:
$stmt1 = $db->query("SELECT `inbox_id` FROM inbox ORDER BY `date` DESC ");
$stmt2 = $db->prepare("SELECT * FROM messages WHERE inbox_id=? AND seen=0 ORDER BY `date` DESC");
while($id = $stmt1->fetchColumn(0)) {
$stmt2->execute(array($id));
$row_msg[$id] = $stmt2->fetchAll(PDO::FETCH_ASSOC);
}
return $row_msg;
If you do not want a multidimensional array you can just add the row to the result array by using array_merge() (PHP Manual: array_merge) inside the loop (instead of the line with $row_msg[$id]):
$row_msg = array_merge($row_msg, $stmt2->fetchAll(PDO::FETCH_ASSOC));
First time using CASE in PDO (mySQL database)
I'm trying to ORDER BY a date, but only if the date is not 0000-00-00 (it can be)
But it seems to ignore the case all together.. What am I doing wrong?
$sql = 'SELECT * FROM mytable WHERE groupid = '.$groupid.' ORDER BY CASE WHEN groupdate != "0000-00-00" THEN groupdate END ASC';
$STH = $conn->query($sql);
if ($STH->rowCount() > 0) {
while ($row = $STH->fetch()) {
// output the rows
}
} else {
echo '<p>No dates found!</p>';
}
What do you want to do with zero-date rows?
Return them after other rows?
Then use this query
SELECT *
FROM mytable
WHERE groupid = $groupid
ORDER BY groupdate = '0000-00-00', groupdate
groupdate = '0000-00-00' is a boolean expresion and returns 1 for matching rows, 0 for non-matching rows. 0 comes before 1 in ascending order.
Non-zero rows are sorted by groupdate.
As you can read in the CASE documentation you should have an ELSE statement in the end. Try something like:
$sql = 'SELECT * FROM mytable WHERE groupid = '.$groupid.' ORDER BY (CASE WHEN groupdate != "0000-00-00" THEN groupdate ELSE groupid END)';
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.