php count grouped values - php

I have searched around and have found many solutions to my question, but I am still having one problem. I am trying to create a table that will have four images per row. This has been done. I have told the script to group by rewardid and it does that so now duplicate images do not appear (the steps to do these I have found on the site). What I am having problems with is that I m trying to put a multiplier under each image to count how many was in each group. (i.e. Lets say I have 5 medals. On my page, it only shows one medal, but I really have 5, so I would like for it to say x5 below the image.) This is what I have so far:
print "<div class='style1'><br> <br><h2>User Medals</div></h3><br />
<table width='80%' class='table' border='0' cellspacing='1'><tr bgcolor='gray'><th></th><th></th><th></th><th></th></tr>";
$result=mysql_query("SELECT * FROM awardsearned WHERE userid=$userid group by rewardid");
$count = 0;
while($res=mysql_fetch_array($result))
{
$award = $res['rewardpic'];
$award2 = $res['rewardid'];
$result2=mysql_query("SELECT awardid, count(rewardid) FROM awardsearned WHERE rewardid=$award2 AND userid=$userid");
$count2 = count($result2);
if($count==4) //three images per row
{
print "</tr>";
$count = 0;
}
if($count==0)
print "<tr>";
print "<td>";
print "<center><img src='$award' width='100' height='100'/><br />x$count2</center> ";
$count++;
print "</td>";
}
if($count>0)
print "</tr>";
print "
</table>";
Sorry if this is messed up, never posted here before. Here it is on pastebin if needed http://pastebin.com/iAyuAAzV

Update your query like this:
SELECT *,COUNT(rewardid) no_of_rewards
FROM awardsearned WHERE userid=$userid group by rewardid
$res['no_of_rewards'] will hold your number.
This will also eliminate the need for the second query.
These things are called "aggregate functions". More in the documentation.

To answer your question:
The value of $result2 would only give TRUE(1) or FALSE(0). If your query executed correctly $count2 will return 1, therefore you always get 1 in your code.
Try and change
$result2=mysql_query("SELECT awardid, count(rewardid) FROM awardsearned WHERE rewardid=$award2 AND userid=$userid");
$count2 = count($result2);
TO:
$result = mysql_query("SELECT awardid, count(rewardid) FROM awardsearned WHERE rewardid=$award2 AND userid=$userid");
$arr = mysql_fetch_array($result);
$count2 = count($arr);
This should give you the actual numbes of records from the resultset.
There are better ways of doing this (look at Bart Friederichs answer!) , like doing only SELECT and loop through resultset once. This would be for performance and for flexibility.
Also take in my consideration that mysql_query is deprecated now, and should not be used. (The preferal methods are to use PDO or mysqli instead)

Related

Grouping database entries into dynamic HTML tables

I have a database where teams will have multiple entries each with different locations. Each entry will have a team name. So for example, team1 might appear several times but each time the location will be different.
The structure of the DB is (each of these represents a column header):
team_name, first_name, last_name, location, arrival_time
My current working code creates HTML tables grouped by team name but currently only creates one row to show the first location and the time of arrival for the first location. I need this to dynamically create more rows to show all locations and arrival times for each team.
The desired result would look like this -
https://codepen.io/TheBigFolorn/pen/LqJeXr
But current result looks like this -
https://codepen.io/TheBigFolorn/pen/qgMppx
And here is an example of how the DB table might look -
https://codepen.io/TheBigFolorn/pen/daqJze
I've tried breaking up the echo and adding a second while loop before the row that I want to apply the above logic to but it seems to break everything. Any input on how I get this to work without having to use separate queries for each team would be very much appreciated. I'm new to php so please go easy on me :)
<?php
$leaders = "SELECT *, COUNT(location) FROM my_example_table GROUP BY team_name";
$result = mysqli_query($connect, $leaders) or die ("<br>** Error in database table <b>".mysqli_error($connect)."</b> **<br>$sql");
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "
<div class='red-border'>
<h2>". $row["team_name"]. "<br><small>Total locations visited: ". $row["COUNT(location)"]. "</small></h2>
</div>
<div class='data-holder'>
<table>
<tr>
<th>Location</th>
<th>Time of arrival</th>
</tr>
<tr><td>". $row["location"]. "</td> <td>". $row["arrival_time"]. "</td></tr>
</table>
</div>
";
}
} else {
echo "0 results";
}
?>
Your problem is due to the GROUP BY, as you've probably realised. This is necessary in order to get a count per team, but causes the number of rows output to be only 1 per team - that's what grouping does. Fundamentally, running an aggregate query such as a COUNT or SUM is incompatible with also outputting all of the row data at the same time. You either do one or the other.
Now, you could run two queries - one to get the counts, and one to get all the rows. But actually you don't really need to. If you just select all the rows, then the count-per-team is implicit in your data. Since you're going to need to loop through them all anyway to output them in the HTML, you might as well use that process to keep track of how many rows you've got per team as you go along, and create the "Total number of locations" headings in your HTML based on that.
Two things are key to this:
1) Making the query output the data in a useful order:
SELECT * FROM my_example_table Order By team_name, arrival_time;
2) Not immediately echoing HTML to the page as soon as you get to a table row. Instead, put HTML snippets into variables which you can populate at different times in the process (since you won't know the total locations per team until you've looped all the rows for that team), and then string them all together at a later point to get the final output:
$leaders = "SELECT * FROM my_example_table Order By team_name, arrival_time;";
$result = mysqli_query($connect, $leaders) or die ("<br>** Error in database table <b>".mysqli_error($connect)."</b> **<br>$sql");
$currentTeam = "";
$locationCount = 0;
$html = "";
$teamHtmlStart = "";
$teamHtmlEnd = "";
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{
//run this bit if we've detected a new team
if ($currentTeam != $row["team_name"]) {
//finalise the previous team's html and append it to the main output
if ($currentTeam != "") $html .= $teamHtmlStart.$locationCount.$teamHtmlEnd."</table></div>";
//reset all the team-specific variables
$currentTeam = $row["team_name"];
$teamHtmlStart = "<div class='red-border'><h2>".$currentTeam."<br><small>Total locations visited: ";
$locationCount = 0;
$teamHtmlEnd = "</small></h2>
</div>
<div class='data-holder'>
<table>
<tr>
<th>Location</th>
<th>Time of arrival</th>
</tr>";
}
$teamHtmlEnd .= "<tr><td>". $row["location"]. "</td> <td>". $row["arrival_time"]. "</td></tr>";
$locationCount++;
}
//for the final team (since the loop won't go back to the start):
$html .= $teamHtmlStart.$locationCount.$teamHtmlEnd."</table></div>";
echo $html;
}
else {
echo "0 results";
}
Here's a runnable demo (using some static data in place of the SQL query): http://sandbox.onlinephpfunctions.com/code/2f52c1d7ec242f674eaca5619cc7b9325295c0d4

query to display four random data from database

This is my php code for displaying the data from the database. I am trying to display the random data from table.
<?php
include('connection.php');
$query="SELECT * FROM `banner_ad` ORDER BY RAND() LIMIT 4";
if($query_run=mysql_query($query))
{
$i=4;
$rows=mysql_fetch_array($query_run);
while($rows)
{
echo $rows['banner_no'];
echo $rows['banner_name'];
echo "<a href=\"".$rows['Banner_website_url']. "\">";
echo "<img src=\"".$rows['banner_image_url']."\" width=\"100px\" height=\"100px\">";
echo"</a>";
}
} else {
echo'<font color="red"> Query does not run. </font>';
}
?>
But the problem with this code is:
It is displaying nothing. But whenever I am trying to make a little modification in the above code like:
<?php
include('connection.php');
$query="SELECT * FROM `banner_ad` ORDER BY RAND() LIMIT 4";
if($query_run=mysql_query($query))
{
$i=4;
$rows=mysql_fetch_array($query_run);
while($rows && $i<4)
{
echo $rows['banner_no'];
echo $rows['banner_name'];
echo "<a href=\"".$rows['Banner_website_url']. "\">";
echo "<img src=\"".$rows['banner_image_url']."\" width=\"100px\" height=\"100px\">";
echo"</a>";
$i=$i-1;
}
} else {
echo'<font color="red"> Query does not run. </font>';
}
?>
It is displaying the same single output 4 times. But It has to display the four different output. So, Please tell me where is the bug ... And how am i suppose to display four different random output.
Any help will be appreciated
Thanks in advance
Your first Query is fine, but the while is wrong:
Just look at what you did here:
$rows=mysql_fetch_array($query_run);
while($rows)
{
echo $rows['banner_no'];
echo $rows['banner_name'];
echo "<a href=\"".$rows['Banner_website_url']. "\">";
echo "<img src=\"".$rows['banner_image_url']."\" width=\"100px\" height=\"100px\">";
echo"</a>";
}
this will end in an "infinite Loop" cause $rows will always be set.
What you need is:
while($rows=mysql_fetch_array($query_run))
this will cause myslq_fetch_array to return a new line everytime the while condition is checked. And if all 4 rows are returned, $rows will be false and the loop is stoped.
And to be complete:
In your second Example you are exactly iterating 4 times over the SAME row, you just fetched one time by calling myslq_fetch_array.
A possible solution to that will be to fetch the row again INSIDE the while-loop:
$i=4;
while ($i>0){
$rows = mysql_fetch_array(...);
$i--;
}
However you should prefer the first solution, because then you dont need to take care that the result count matches your iterator variable.
sidenode: Call it $row without the 's', because you always just getting ONE row back.
Try constructing while loop like so
while(($rows=mysql_fetch_array($query_run)) !== false)
Using ORDER BY RAND() is not the best practice because the random value must be generated for every single row. Better way would be to randomly generate primary keys (e.g. ID) in PHP and then select according to them.
$random_id = rand(1,4);
$query="SELECT * FROM `banner_ad` WHERE id = $random_id";
Will select exactly one random row. Similar whould be selecting multiple rows using IN statement.
More info you can find here.
$query_run=mysql_query($query);
if(!$query_run)
{
echo'<span style="color:red">Query did not run.</span>';//font tag is ancient
}
else
{
if(mysql_num_rows($query_run) > 0)
{
while($row = mysql_fetch_assoc($query_run))
{
echo $rows['banner_no'];
echo $rows['banner_name'];
// more...
}
}
}

How to Limit the lines my Php List is showing

I have a submit form that displays into a list format and I'm wondering what I can do to make it so that the list only displays a certain number of the most current submitted info. I'm testing it and currently the list is on a page and just displays 50+ submissions stretching out the page very long.
<?php
$query='select * from article order by `article`.`time` DESC';
$result=mysql_query($query);
echo '<table width="600px">';
while($row = mysql_fetch_array($result))
{
echo "<td><a href='".$row['url']."'>".$row['title']."</a></td> <td>".$row['description']."</td><td>".$row['type']."</td></tr>";
}
echo '<table>';
?>
Welcome to SO! Modify your sql statement as follows:
$query='SELECT * FROM article ORDER BY `article`.`time` DESC LIMIT 10';
Change 10 to however many entries should be displayed.
Even though you only should select the data you need, you might want to take a look at a for-loop, which is useful if you know how many times you want to run something. You might end up with a loop which looks like this:
for($i = 0; $i < 10 && $row = mysql_fetch_array($result); $i++) {
echo "<td><a href='".$row['url']."'>".$row['title']."</a></td> <td>".$row['description']."</td><td>".$row['type']."</td></tr>";
}
This code runs 10 times IF you have enough data.

Can these database calls be optimized?

I'm working on a project to further learn php and how it can be used to interface with a mysql database. The project is a forum, with the page in question displaying all the topics in a category. I'd like to know if I am handling my calls efficiently, and if not, how can I structure my queries so they are more efficient? I know its a small point with a website that isn't used outside of testing, but I'd like to get a handle on this early.
<?php
$cid = $_GET['cid'];
$tid = $_GET['tid'];
// starting breadcrumb stuff
$catname = mysql_query("SELECT cat_name FROM categories WHERE id = '".$cid."'");
$rcatname = mysql_fetch_array( $catname );
$topicname = mysql_query("SELECT topic_title FROM topics WHERE id = '".$tid."'");
$rtopicname = mysql_fetch_array( $topicname );
echo "<p style='padding-left:15px;'><a href='/'> Home </a> » <a href='index.php'> Categories </a> » <a href='categories.php?cid=".$cid."'> ".$rcatname['cat_name']."</a> » <a href='#'> ".$rtopicname['topic_title']. "</a></p>";
//end breadcrumb
$sql = "SELECT * FROM topics WHERE cat_id='".$cid."' AND id='".$tid."' LIMIT 1";
$res = mysql_query($sql) or die(mysql_error());
if (mysql_num_rows($res) == 1) {
echo "<input type='submit' value='Reply' onClick=\"window.location = 'reply.php?cid=".$cid."&tid=".$tid."'\" />";
echo "<table>";
if ($_SESSION['user_id']) { echo "<thead><tr><th>Author</th><th>Topic » ".$rtopicname['topic_title']."</th></thead><hr />";
} else {
echo "<tr><td colspan='2'><p>Please log in to add your reply.</p><hr /></td></tr>";
}
echo "<tbody>";
while ($row = mysql_fetch_assoc($res)) {
$sql2 = "SELECT * FROM posts WHERE cat_id='".$cid."' AND topic_id='".$tid."'";
$res2 = mysql_query($sql2) or die(mysql_error());
while ($row2 = mysql_fetch_assoc($res2)) {
echo "<tr><td width='200' valign='top'>by ".$row2['post_creator']." <hr /> Posted on:<br />".$row2['post_date']."<hr /></td><td valign='top'>".$row2['post_content']."</td></tr>";
}
$old_views = $row['topic_views'];
$new_views = $old_views + 1;
$sql3 = "UPDATE topics SET topic_views='".$new_views."' WHERE cat_id='".$cid."' AND id='".$tid."' LIMIT 1";
$res3 = mysql_query($sql3) or die(mysql_error());
echo "</tbody></table>";
}
} else {
echo "<p>This topic does not exist.</p>";
}
?>
Thanks guys!
Looks like a classic (n+1) query mistake that could die a latent death. You get a key using one round trip, then you loop over the results to get n values based on it. If the first result set is large you'll have a lot of network round trips.
You could bring it all back in one go with a JOIN and save yourself a lot of network latency.
The statements themselves are fairly simple so there's not much you can do to optimize them further that I know of. However, if you create some business objects and cache the data into them on a single call and then access data from the business objects then it could be faster.
In other words, 1 SQL call for 1,000 rows is going to be much faster than 1,000 calls for a single row.
Here are some of extra things I would do when I write a code like above:
Never use * in SELECT statement when you know the columns you are going to use.
Always use or die(mysql_error()) when executing the query.
Unset the result sets once the result sets has served its purpose.
Use mysql_real_escape_string() to escape the injections when using some substitutions in your queries.

Displaying results after MySQL JOIN query with PHP

$sql = "SELECT messages.text, users.name FROM messages INNER JOIN users ON messages.user_id=users.id ORDER BY messages.ms_id DESC LIMIT 10";
$result = mysql_query($sql);
$rows = array();
while($row = mysql_fetch_array($result))
{
$rows[]=$row;
}
echo $rows[0][1].$rows[0][0];
/* for($i=0;$i<=10;$i++)
{
echo $rows[i][1].$rows[i][0];
}
*/
This script is supposed to show the last 10 messages in a chat.What I'm doing is getting the Name of the user from the users table and the text from the message table and I want to display them in my chat window.Right now I have only 4 messages recorded and don't know how this affects the whole script I should implement a check for this too, but the bigger problem is that when i use echo $rows[0][1].$rows[0][0]; the info is displayed correctly, but when I try to make a loop so I can show tha last 10 (I tried the commented one) then nothing is displayed.I thought at least when I use this loop I'll see the 4 recorded messages but what really happen is a blank window.Obvously I have the info recorded in $rows[] and can echo it, but don't understand why this loop don't work at all.I'll appreciate if someone can help me with this and with the check if the messages are less then 10.
Thanks.
Leron
P.S
Here is the edited script, thanks to all of you, I need the array because otherwise the most recent message is shown at the top which is not an opiton when I use it for diplaying chat masseges.
for($i=10;$i>=0;$i--)
{
if($rows[$i][1]!="" || $rows[$i][0]!="")
{
echo $rows[$i][1].' : '.$rows[$i][0];
echo "</br>";
}
}
Your FOR loop was running 11 times even if only 10 records. The second clause should be a < instead of <=. Plus the $ was missing on the i variable.
For example sake, you don't really need to make an array from the rows, and you can refer to the fields by name:
while($row = mysql_fetch_array($result))
{
echo $row['name'] . ' says: ' . $row['message'] . '<BR>';
}
why not just do
while($row = mysql_fetch_array($result))
{
echo $row[1]." ".$row[0];
}
Your query, auto limits it to the last 10, this will then show anything from 0 to 10 which get returned.
PS I added a space between username and message for readability
You need $ symbols on your i variable:
for($i=0;$i<10;$i++)
{
echo $rows[$i][1].$rows[$i][0];
}
A more robust solution would be like this:
$sql = "SELECT messages.text, users.name FROM messages INNER JOIN users ON messages.user_id=users.id ORDER BY messages.ms_id DESC LIMIT 10";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result))
{
echo $row[1].$row[0];
}

Categories