Issue sorting inside while loop - php

I have a strange issue happening. I've got a table where I want to order the number of times a product was sold. I'll post the query, but the issue is inside the while loop.
Query:
$cat = $db->query("SELECT *, COUNT(id_produto) as quantos FROM produtos p JOIN pedidos m ON p.id_prod = m.id_produto GROUP BY id_produto ORDER BY quantos +0 DESC");
$cat->execute();
Now the loop:
while($res_cat = $cat->fetch(PDO::FETCH_ASSOC)){
$quantidade_ok = $res_cat['quantos'] * $res_cat['qtde'];
$quanti = array($quantidade_ok);
rsort($quanti);
foreach($quanti as $ord){
echo $ord."<br>";
}
The output is:
40
50
4
1
3
2
10
But I want it to be:
50
40
10
4
3
2
1
I'll be happy for any help.

You're sorting within a loop (so your sorting already happened), and you're sorting an array with just 1 value $quanti, so your sort does nothing.
You have 2 ways to approach this properly: edit your query to actually sort how you wish, or sort the PHP array before looping it.
Option 1: Edit your query
Based on your code it seems clear that you wish to sort by the product of quantos times qtde. So you can simply edit your query as follows:
SELECT *, COUNT(id_produto) as quantos
FROM produtos p JOIN pedidos m ON p.id_prod = m.id_produto
GROUP BY id_produto
ORDER BY (quantos*qtde) DESC
Option 2: Sort via PHP
If you prefer to sort via PHP as you don't want to change your query, you can simply populate a temporary array, the product of quantos times qtde as key and then use krsort to sort the array.
In code:
$array = [];
while ($res_cat = $cat->fetch(PDO::FETCH_ASSOC)) {
$key = $res_cat['quantos'] * $res_cat['qtde'];
$array[$key] = $res_cat;
}
krsort($array);
foreach ($array as $ord => $res_cat) {
echo $ord."<br>";
}

You overwrite $quanti each time so it always has a single value.
Try this:
$quanti = [];
while($res_cat = $cat->fetch(PDO::FETCH_ASSOC)) {
$quantidade_ok = $res_cat['quantos'] * $res_cat['qtde'];
$quanti[] = $quantidade_ok;
}
rsort($quanti);
foreach($quanti as $ord){
echo $ord."<br>";
}

Related

Finding a value in a php array

I've been banging my head hard over this problem for the last 2-3 days trying to see the problem from as many different angles as possible but to no avail. I'm turning to the SO community for extra perspectives. Below is the code I have which prints all 9 product plans. I'm wanting to find and print the plan with pricing equals or closest to a given user input. How can I do this?
//arrays of productnames
$productnames=array(1=>"Beginner","Advanced","Expert");
//arrays of productlevels
$productlevels=array(1=>"Bronze","Silver","Gold");
//Get The Length of Product Name Array
$planname_array_length=count($productnames);
//Get The Length of Product Level Array
$planlevel_array_length=count($productlevels);
for ($prn=1; $prn <= $planname_array_length; $prn++) {//loop to create plan name indicators
for ($prl=1; $prl <= $planlevel_array_length; $prl++) {//loop to create plan level indicators
$getpoductsql = " SELECT name, level,productNameId,productLevelId,finalProductPrice
FROM (
SELECT wspn.productName AS name, wspl.productLevel AS level, wsp.productNameId AS productNameId, wsp.productPlanLevel AS productLevelId,
ROUND(SUM(`Price`) * 1.12) AS finalProductPrice,
FROM `products` ws
left join product_plan wsp on wsp.productId = ws.wsid
left join product_plan_level wspl on wsp.productPlanLevel = wspl.wsplid
left join product_plan_name wspn on wspn.wspnid = wsp.productNameId
WHERE wspn.productName = '$planname_array_length[$pn]' AND wspl.productLevel = '$planlevel_array_length[$pl]'
)
AS x ORDER BY ABS(finalProductPrice - $compareprice)"
$resultproducts = $conn->query($getpoductsql);
$prodArray = mysqli_fetch_array($resultproducts);
//print array of each plan
$resultArr = array('planNameID' => $prodArray['planNameId'],
'planName' => $prodArray['name'],
'planLevelID' => $prodArray['planLevelId'],
'planLevelName' => $prodArray['level'],
'planPrice' => $prodArray['finalProductPrice'];
//print arrays of products
echo json_encode($resultArr);
}
}
This will output 9 plans as follow :
{"planNameID":"1","productName":"Beginner","productLevelID":"1","productLevelName":"Bronze","productPrice":"15"}
Rather than performing a separate query for each product name and product level, do them all in one query, and let MySQL find the one with the closest price.
$getpoductsql = " SELECT name, level,productNameId,productLevelId,finalProductPrice
FROM (
SELECT wspn.productName AS name, wspl.productLevel AS level, wsp.productNameId AS productNameId, wsp.productPlanLevel AS productLevelId,
ROUND(SUM(`Price`) * 1.12) AS finalProductPrice,
FROM `products` ws
left join product_plan wsp on wsp.productId = ws.wsid
left join product_plan_level wspl on wsp.productPlanLevel = wspl.wsplid
left join product_plan_name wspn on wspn.wspnid = wsp.productNameId
WHERE wspn.productName IN ('Beginner', 'Advanced', 'Expert') AND wspl.productLevel IN ('Bronze', 'Silver', 'Gold')
GROUP BY productNameId, productLevelId
)
AS x ORDER BY ABS(finalProductPrice - $compareprice)"
forgive my formatting, I'm on mobile
Like Amr Berag said above, your result should be the first row returned from your query.
If you have a table like this:
ID value
---- ------
A 7
B 12
C 23
...
You can then SELECT from this table to find the closest to some value, like so:
(Assume your desired value is $VALUE)
SELECT id, value, ABS(value - $VALUE) AS diff
FROM your_table
ORDER BY diff ASC
This will return something like this (say $VALUE is 10):
id value diff
-- ------ ----
B 12 2
A 7 3
C 23 13
...
You can just pick the first row.
You may also be able to add a WHERE clause to only select the row with the least difference using the MIN function:
SELECT id, value, ABS(value - $VALUE) AS diff
FROM your_table
WHERE diff = MIN(diff)
The way you are doing it will produce invalid json, do it like this:
$result=array();
for ($prn=1; $prn <= $planname_array_length; $prn++) {
for ($prl=1; $prl <= $planlevel_array_length; $prl++) {
. . . // the other code
//print array of each plan
$resultArr = array('planNameID' => $prodArray['planNameId'],
'planName' => $prodArray['name'], 'planLevelID' => $prodArray['planLevelId'],
'planLevelName' => $prodArray['level'],
'planPrice' => $prodArray['finalProductPrice'];
//print arrays of products
$resul[]=$resultArr;
}//loop1
}//loop2
echo json_encode($result);
you should also add the limit 1 and do the rest in JS in the front end

ORDER BY not working in MySQL

while ($categories = mysql_fetch_array($category_result)) {
$item_result = mysql_query("SELECT * FROM zw_".$categories['Category']."s WHERE ItemId = '".$categories['Id']."' ORDER BY Level");
$item = mysql_fetch_assoc($item_result);
echo $item['Level'];
The output of this is
15
35
55
75
95
115
135
150
15
27
48
68
83
11
40
62
80
95
110
125
I cant really find a pattern here. I want it to go from the lowest number to highest number, which ORDER BY is supposed to do, right? Level is always INT and this is inside a while loop.
Check this
while ($categories = mysql_fetch_array($category_result)) {
$item_result = mysql_query("SELECT * FROM zw_".$categories['Category']."s WHERE ItemId = '".$categories['Id']."' ORDER BY Level ASC");
$item = mysql_fetch_assoc($item_result);
echo $item['Level'];
Try iterate over the result of the inner query .. eg:
while ($categories = mysql_fetch_array($category_result)) {
$item_result = mysql_query("SELECT * FROM zw_".$categories['Category']."s WHERE ItemId = '".$categories['Id']."' ORDER BY Level");
wwhile($item = mysql_fetch_assoc($item_result)) {
echo 'Category : ' . $categories['Id'] . ' Level : ' . $item['Level'];
}
}
I think you are constructing the table name dynamically, using data you have read from some other table (or maybe elsewhere). Hence, you want records from a collection of separate tables, and then to sort the complete set.
Perhaps you could build your SQL to create a "UNION" for each unique table, so the query runs only once and does its sorting on the entire result set. Possibly, a union clause (OK, the first clause is not introduced with "UNION")!) for each ($categories['Category'], $categories['Id']) combination will be too much for your RDBMS to handle. So, you could stick to one clause per $categories['Category'] and build all the associated $categories['Id']s into an "IN" condition.
Worth considering whether it's better to stick with what you have, and write some code to sort the results you're getting.
The field in database is numeric ? Try to specify the type of sort,... order by Level asc for example.
Checkout http://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html

MySQL SELECT WHERE id IN() get num_rows

I use this code to show category from database
$select_newscats = $mysqli->query("SELECT * FROM news_cats order by ord_show asc");
while ($rows_newscats = $select_newscats->fetch_array(MYSQL_ASSOC)){
$id_newscats = $rows_newscats ['id'];
$title_newscats = $rows_newscats ['title'];
$ord_show_newscats = $rows_newscats ['ord_show'];
$icon_newscats = $rows_newscats ['icon'];
$kind_newscats = $rows_newscats ['kind'];
$description_newscats = $rows_newscats ['description'];
//here is my data
}
i have in news table row for categoies it's name is cats and i insert data inside it like that 1,5,6,8
and i use this code to count news inside each cat
$select_newsnum = $mysqli->query("SELECT id FROM news where $id_newscats IN (cats)");
$rows_newsnum = $select_newsnum->fetch_array(MYSQL_ASSOC);
$num_newsnum = $select_newsnum->num_rows;
it gets only first value for example if i have this values 1,5,6,8 it gets only 1 the first value
I would do the counting in a single sql call, not with php logic and separate sql calls. For this I would join the 2 tables using left join and use a join condition instead of an in clause:
SELECT nc.id, nc.title, nc.ord_show, nc.icon, nc.king, nc.description, count(n.id) as newsnum
FROM news_cats nc
LEFT JOIN news n ON nc.id=n.cats
GROUP BY nc.id, nc.title, nc.ord_show, nc.icon, nc.king, nc.description
ORDER BY nc.ord_show asc
Obviously, make sure that the join condition is the right one. When you loop through the resultset, the number of news per category will be in the newsnum field.
$select_newsnum = $mysqli->query("SELECT id FROM news where $id_newscats IN (cats)");
$rows_newsnum = $select_newsnum->fetch_array(MYSQL_ASSOC);
$num_newsnum = $select_newsnum->num_rows;
Here $rows_newsnum will only return the first row in the database.
Fetch Array only returns one row at a time, and then moves the row pointer forward. For example the following code on the dataset you provided (1, 5, 6, 8).
$rows_newsnum = $select_newsnum->fetch_array(MYSQL_ASSOC);
echo $rows_newsnum["id"]; // Will print 1
$rows_newsnum = $select_newsnum->fetch_array(MYSQL_ASSOC);
echo $rows_newsnum["id"]; // Will print 5
What you need to do is move it into a while loop (like your first example) to get to access each row, like below:
while($row = $select_newsnum->fetch_array(MYSQL_ASSOC)) {
echo $rows_newsnum["id"] . ", ";
}
// Will produce:
// 1, 5, 6, 8,
If you just want to get a count
Your existing code should work fine. And you can omit the call to fetch_array.
$num_newsnum = $select_newsnum->num_rows;
echo $num_newsnum; // Will display 4
Read more about fetch_array on the PHP documentation:
http://php.net/manual/en/mysqli-result.fetch-array.php
Hope this helps.

Unique value count of comma separated field (PHP - MySQL)

I have mysql table that looks like this:
id place interest
1 place1 a,b,c
2 place2 c,d,e
3 place1 a,e
4 place2 f
5 place2 f
6 place3 g,h
I need to get unique "place" and "interest" values sorted as per the count.
So, the output for "place" would be
place2(3)
place1(2)
place3(1)
So, the output for "interest" would be
a(2)
c(2)
e(2)
f(2)
b(1)
d(1)
g(1)
h(1)
is there a way to do this in PHP-Mysql?
So, far I have been able to get simple column data
SELECT place,
COUNT( * ) AS num
FROM testtab
GROUP BY place
ORDER BY COUNT( * ) DESC
As mysql is not able to hold arrays, its better to build a new table like this:
interest_id interest_name
1 a
2 b
and another one to keep the relations:
pk id interest_id
1 1 1
2 1 2
which this id is the id of the records in your main table.
With having this, you can easily use:
select count(*) from THIRD_TABLE where id = YOUR_ID
You can do this.
$place = array();
$interests = array();
foreach($rows as $row){
if (!isset($place[$row["place"]])){
$place[$row["place"]] = 0;
}
$place[$row["place"]]++;
$ints = explode(",", $row["interests"]);
foreach($ints as $int){
if (!isset($interests[$int])){
$interests[$int] = 0;
}
$interests[$int]++;
}
}
This will give you the two arrays keyed off of the relevant field with the value being the count. If this is going to be a common action in your application it would make more sense to normalize your data as suggested by AliBZ.
This is for the first result you need
SELECT place,COUNT(interest)
FROM `testtab`
GROUP by place
ORDER BY COUNT(interest) desc
can do this :
$inst_row = '';
foreach($rows as $row){
$inst_row .= $row['interests'];
}
$inst_values = explode(',', $inst_row);
$inst_count = array_count_values($inst_values);
// $inst_count will return you count as you want ,print_r it and format it accordingly

mysql order by issue

if i have a query like :
SELECT * FROM table WHERE id IN (3,6,1,8,9);
this array of the ids is build in php dynamically ,
and the order is important to me.
$my_array = array (3,6,1,8,9) ;
how can i sort the results by the order by which the elements appear in my array ?
its possible to do it in MYSQL query,
or i must to order it after via php ?
You can order by a value derived from a column. You can use a CASE operator to specify the order:
SELECT * FROM table
WHERE id IN (3,6,1,8,9)
ORDER BY CASE id WHEN 3 THEN 1
WHEN 6 THEN 2
WHEN 1 THEN 3
WHEN 8 THEN 4
WHEN 9 THEN 5
END
I haven't tested but this PHP solution should work:
<?php
$my_array = array (3,6,1,8,9) ;
$sql = 'SELECT * FROM table WHERE id IN (3,6,1,8,9)';
$sql .= "\nORDER BY CASE id\n";
foreach($my_array as $k => $v){
$sql .= 'WHEN ' . $v . ' THEN ' . $k . "\n";
}
$sql .= 'END ';
echo $sql;
?>
This generates the following SQL code:
SELECT * FROM table WHERE id IN (3,6,1,8,9)
ORDER BY CASE id
WHEN 3 THEN 0
WHEN 6 THEN 1
WHEN 1 THEN 2
WHEN 8 THEN 3
WHEN 9 THEN 4
END
If you must do it this way you'll have to manipulate the data in PHP. MySQL can only order by natural orderings ascending or descending.
Got to question though - why do you need the data returned in this very specific order? There may be an easier solution to your problem by re-jigging something further up in the code.
SELECT * FROM table WHERE id IN (3,6,1,8,9) ORDER BY FIELD(id,3,6,1,8,9);
You can load the results into an array with IDs as indexes:
while ($row = mysql_fetch_array($l)) $items[$row['id']] = $row;
and then simply iterate it in your order
foreach ($my_array as $id) { $current_row = $items[$id]; ... }

Categories