max(id) and limit 10, but use them in different places - php

I have two tables, posts and sections. I want to get the last 10 posts WHERE section = 1,
but use the 10 results in different places. I make a function:
function sectionposts($section_id){
mysql_set_charset('utf8');
$maxpost1 ="SELECT max(id) from posts WHERE section_id = $section_id ORDER BY ID DESC LIMIT 20";
$maxpost12 =mysql_query($maxpost1);
while ($maxpost_rows = mysql_fetch_array($maxpost12 ,MYSQL_BOTH)){
$maxpost2 = $maxpost_rows[0];
}
$query = "SELECT * FROM posts WHERE id = $maxpost2";
$query2 = mysql_query($query);
return $query2;
}
$query2 = sectionposts(6);
while ($rows = mysql_fetch_array($query2)){
echo $rows['title'] . "<br/>" . "<br/>";
echo $rows['id'] . "<br/>" . "<br/>";
echo $rows['image_section'] . "<br/>";
echo $rows['subject'] . "<br/>";
echo $rows['image_post'] . "<br/>";
}
How can it take these ten results but use them in different places, and keep them arranged from one to ten.
this was the old case and i solve it but i found another problem, that, if the client had deleted a post as id = 800 "so there aren't id = 800 in DB" so when i get the max id minus $NUM from it, and this operation must be equal id = 800, so i have a programing mistake here, how can i take care of something like that.
function getmax_id_with_minus ($minus){
mysql_set_charset('utf8');
$maxid ="SELECT max(id) FROM posts";
$maxid1 =mysql_query($maxid);
while ($maxid_row = mysql_fetch_array($maxid1)){
$maxid_id = $maxid_row['0'];
$maxid_minus = $maxid_id - $minus;
}
$selectedpost1 = "SELECT * FROM posts WHERE id = $maxid_minus";
$query_selectedpost =mysql_query($selectedpost1);
return ($query_selectedpost);
}
<?php
$ss = getmax_id_with_minus (8);
while ($rows = mysql_fetch_assoc($ss)){
$main_post_1 = $rows;
?>
anyway "really" thanks again :) !

A few thoughts regarding posted code:
First and foremost, you should stop using mysql_ functions as they are being deprecated and are vulnerable to SQL injection.
$maxpost1 ="SELECT max(id) from posts WHERE section_id = $section_id ORDER BY ID DESC LIMIT 20";
When you SELECT MAX, MIN, COUNT, AVG ... functions that only return a single row, you do not need an ORDER BY or a LIMIT.
Given that you are only asking for the MAX(id), you can save work by combining your queries like so:
SELECT * FROM posts
WHERE id = (SELECT MAX(id) from posts WHERE section_id = $section_id)
If I'm understanding what you're trying to do (please correct me if I'm wrong), your function would look something like:
function sectionposts($section_id) {
$link = mysqli_connect("localhost", "my_user", "my_password", "world");
$stmt = mysqli_prepare($link, "SELECT title, id, image_section, subject, image_post FROM posts "
. "WHERE section_id = ? ORDER BY id DESC LIMIT 10");
mysqli_stmt_bind_param($stmt, $section_id);
return mysqli_query($link, $stmt)
}
$result = sectionposts(6);
while ($row = mysqli_fetch_assoc($result)) {
echo $rows['title'] . "<br /><br />";
echo $rows['id'] . "<br /><br />";
echo $rows['image_section'] . "<br />";
echo $rows['subject'] . "<br />";
echo $rows['image_post'] . "<br />";
}

Try this instead, to save yourself a lot of pointless code:
$sql = "SELECT * FROM posts WHERE section_id=$section_id HAVING bar=MAX(bar);"
$result = mysql_query($sql) or die(mysql_error());
$row = mysql_fetch_assoc($result);
echo ...;
echo ...;
The having clause lets you find the max record in a single operation, without the inherent raciness of your two-query version. And unless you allow multiple records with the same IDs to pollute your tables, removing the while() loops also makes things far more legible.

Seems like you want to store them in an array.
$posts = array(); //put this before the while loop.
$posts[] = $row; //put this in the while loop

Related

Fixing performance issues when looping through MySQL results in PHP

I'm working on a virtual game board style game in which players get points on a certain area of the board. (Take it easy on me now as I only do this as a hobby so I might be doing this in the worst way possible)
I have 3 tables. One stores all the player information (eg. id, screenname). A second stores all the Area information (eg. id, x, y) and a third stores how many points each player has in each area (eg. id, playerid, areaid, points). In order to create a "leaderboard" I'm looping through all the players, then within that loop I'm also looping through all the areas, then finally within that second loop, I get the leader of that area and see if that matches the current player in the first loop, if so I increment a counter, then store it into an array. (See code below with some commenting)
I looked into MySQL caching, but I dont have access to a lot of the server options, as well as would like to keep as much of the results as live as possible, so caching may not be the right way to go.
My question is whether or not I'm doing this properly. Currently there is only around 10 players, and approx. 500 areas. I'm finding the below script already takes about 5-8 seconds to run. Potentially there could be millions of areas, so such a long delay in processing could be catastrophic (for the leaderboard anyway). Am I going about this the right way, and/or is there a better way to do this?
<?php
$leaders = array();
//Loop through all the players
$sql = "SELECT * FROM players";
$result = mysqli_query($con, $sql) or die(mysqli_error($con));
while ($row = mysqli_fetch_array($result)) {
//save player information into variables
$playerId = $row['id'];
$playerScreenName = $row['screenname'];
//Reset the area counter
$AreaCount = 0;
$leader = array();
//Loop through all areas
$sql2 = "SELECT * FROM areas";
$result2 = mysqli_query($con, $sql2) or die(mysqli_error($con));
while ($row2 = mysqli_fetch_array($result2)) {
$areaId = $row2['id'];
//Get the player with the most points in that area
$sql3 = "SELECT * FROM points WHERE areaid='$areaId' ORDER BY totalpoints DESC LIMIT 1";
$result3 = mysqli_query($con, $sql3) or die(mysqli_error($con));
while ($row3 = mysqli_fetch_array($result3)) {
$leaderOfArea = $row3['playerid'];
//See if the leader of the area is the same player we are looping through
if ($playerId == $leaderOfArea) {
//if it is, then increment the counter
$AreaCount++;
}
}
}
//Store the leader information into an array to be output later
$leader['screenname'] = $playerScreenName;
$leader['areacount'] = $AreaCount;
$leaders[] = $leader;
}
// sort leaders by score
usort($leaders, 'compare_areacount');
?>
There is overhead of opening database connections, and when you do it in a loop, you exacerbate the problem (and then when you add a loop inside of that, you make it that much worse). Instead, restructure it as one query using a Join or Subquery.
This post has some specifics.
I think this code can help. You might have to change the sql queries with appropriate column names you need.
<?php
$leaders = array();
//Loop through all the players
$sql = "SELECT * FROM players";
$result = mysqli_query($con, $sql) or die(mysqli_error($con));
$players = array();
while ($row = mysqli_fetch_array($result)) {
//save player information into variables
$players[$row['id']] = array($row['screenname'], 0);
// number 0 will be the count of how many times this player is the leader
}
$sql = "SELECT Area.id, Area.name, (SELECT Pts.playerid FROM `points`"
. " AS Pts WHERE Pts.areaid=Area.id ORDER BY totalpoints"
. " DESC LIMIT 1) AS `leader_id` FROM `areas` AS Area";
$result = mysqli_query($con, $sql) or die(mysqli_error($con));
$areas = array();
while ($row = mysqli_fetch_row($result)) {
$areas[$row[0]] = $row;
// $row[2] will contain leader_id
// index 1 corresponds to the second element in player values array
$players[$row[2]][1]++;
}
// now if you want to print:
foreach ($areas as $area_id => $area) {
echo "Area id: " . $area_id . ", name: " . $area[1] . ", leader_id: " . $area[2] . "<br /><br />";
}
foreach ($players as $player_id => $player) {
echo "Player id: " . $player_id . ", name: " . $player[0] . ", No of areas this player is a leader of: " . $player[1] . "<br /><br />";
}

shuffle : Display only one row at the same time

How to display only one row at random at the same time from DB. Everything works fine, but all rows are displayed. thanks
<?php
$sql = "SELECT id,name FROM table ";
$rows = array();
$result = $objCon->query($sql);
while($row = $result->fetch_assoc())
{
$rows[] = $row;
}
shuffle($rows);
echo '<ol>';
foreach($rows as $row)
{
echo '<li><h3>'.$row['id'].' = '.$row['name'].'</h3></li>';
}
echo '</ol>';
?>
Change your SQL request:
SELECT id,name FROM table ORDER BY RAND() LIMIT 1;
You can do it using PHP:
....
shuffle($rows);
$randomRow = reset($rows);
....
But the better way is to change your SQL query:
$query = "SELECT id, name FROM table ORDER BY RAND() LIMIT 1;"
<?php
$sql = "
SELECT id, name
FROM table
ORDER BY RAND()
LIMIT 1 ";
$result = mysql_query($sql);
// As you are only return a single row you do you require the while()
$row = mysql_fetch_array($result);
echo '<ol>';
echo '<li><h3>'.$row['id'].' = '.$row['name'].'</h3></li>';
echo '</ol>';
?>
By adding an ORDER BY RAND() in your sql query you are asking MySQL to randomly order the results then at a LIMIT to restrict the number of rows you would like returned.
The example code is written based on selecting a single row. If you would like more, e.g. 5, you will need to add a while loop.

php sql query changes url, however doesn't change data

I'm trying to make a "next button" for my database, so i can view one image at a time. However the way i have it right now only changes the url and not actually the image check it out here. It sticks to the image with the highest id on it (87) no matter what the url is. How do i fix this?
this is how my db looks
<?php
require("includes/conn.php");
if (isset($_GET["imagecount"]))
$next = (int)$_GET["imagecount"]; //int is for sql injection
else
$next = 0;
$result = mysql_query("select * from people order by id desc limit $next, 1") or die(mysql_error());
?>
<?php
$result = mysql_query("select * from people order by id desc limit 0, 1 ") or die ("haznot DB: " . mysql_error());
while ($row = mysql_fetch_assoc($result))
{
echo "<img src=\"images/" . $row['filename'] . "\" alt=\"\" /><br />";
}
?>
Next
You want WHERE id = $next in your query. Not what you have.
Why do you have two mysql queries...
"Select * FROM people WHERE `id` = $next"
You should select WHERE id=$next. You seem to have fewer than 87 images present, so the limit clause won't behave as you expect.

How to ignore duplicate rows when echoing mysql query result

I trying to make tag cloud system and i enter the tags in one table with "name" and "product_id".
I make that may have multiple same tags everyone for different product.
My problem is that when echo the tags from the table it show me all tags,this is good,but the repeated tags are in that count. I need to echo repeated tags only once, but i don't know how to make that.
Here is and my code that showed and repeated tags.
$id = $_GET['catid'];
$sql = "SELECT * FROM tags_group";
$result = mysql_query($sql) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
//echo $row['name'];
$id = $row['id'];
$sql1 = "SELECT * FROM tags WHERE tag_group='$id'";
$result1 = mysql_query($sql1);
while ($row1 = mysql_fetch_array($result1)) {
$name = $row1['tag_name'];
$sql2 = "SELECT * FROM tags WHERE tag_name='$name'";
$resut2 = mysql_query($sql2);
$rows = mysql_num_rows($resut2);
echo $row1['tag_name'] . '(' . $rows . ')' . '<br>';
// echo $row1['tag_name'].$rows.'<br>';
}
echo '<br>';
}
You have to use the DISTINCT keyword do avoid duplicates:
SELECT DISTINCT * FROM tags_group
As I mentioned in the comments above, you should stop using mysql_* functions. They're being deprecated. Instead use PDO (supported as of PHP 5.1) or mysqli (supported as of PHP 4.1). If you're not sure which one to use, read this article.
UPDATE
It also looks like you're using nested queries, rather than joining your tables and retrieving the results. Try this instead:
$id = $_GET['catid'];
$sql = "SELECT tags.tag_name, count(*) AS name_count FROM tags
INNER JOIN tags_group
ON tags.tag_group = tags_group.id
GROUP BY tag_name";
$result = mysql_query($sql) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
$name = $row['tag_name'];
$rows = $row['name_count'];
echo $name . '(' . $rows . ')' . '<br>';
// echo $row['tag_name'].$rows.'<br>';
}
echo '<br>';
Here I don't use DISTINCT but GROUP BY allows you to aggregate the count for each distinct row (based on the GROUP BY column).
Take a look at this diagram to better understand how joins work.

The Select query I am using is not working.. Can Somebody Guide me to the Correct way?

I am using the Select query as
SELECT id, ordering FROM `jos_menu` WHERE ordering='".$rec['ordering'] -'1' ."' AND parent = '0'
Here I need all the records whose ordering is less than 1 of the selected record's order($rec['ordering'] = getting from other select query ) when I am trying to echo the query I am not getting complete statement but getting only this -1' AND parent = '0'
here is the whole snippet
$where = ' WHERE (id = ' . implode( ' OR id = ', $cid ) . ')';//Pranav Dave Coded
echo $selquery = "SELECT id, ordering FROM `jos_menu`".$where; //Pranav Dave Coded
$db->setQuery( $selquery );//Pranav Dave Coded
$record = $db->loadAssocList(); //Pranav Dave Coded
if ($model->orderItem($id, -1)) {
echo "<pre>";
print_r($model);
/*exit;*/
//echo $updorderup = mysql_escape_string($model->_db->_sql);//Pranav Dave Coded
foreach($record as $rec)//Pranav Dave Coded
{
echo $aboverow = "SELECT id, ordering FROM `jos_menu` WHERE ordering='".$rec['ordering'] -'1' ."' AND parent = '0'";
$db->setQuery( $aboverow );
$above = $db->loadAssoc();
echo "<pre>";
print_r($above);
}//end of foreach
}//end of if
Please suggest me where I am getting wrong.....
It looks like you may need to unwrap the -1 from the quotes:
WHERE ordering='".($rec['ordering'] - 1)."' AND parent = '0'";
Why do you trying to put everything inline?
Why not to make some preparations first?
Why not to compare resulting query with sample one?
Why don't you check every step if it return proper result?
$val = $rec['ordering'] - 1;
//let's see if $cal has proper value:
echo $val."<br>";
$sql = "SELECT id, ordering FROM `jos_menu` WHERE ordering = $val AND parent = 0";
//let's see if query looks good:
echo $sql;
//let's print sampe query to compare:
echo "<br>" ;
echo "SELECT id, ordering FROM `jos_menu` WHERE ordering = 1 AND parent = 0";
As Daniel said, you need to remove the quotes around the -1. Currently its trying to minus a string, which it wouldn't be happy with at all ;)

Categories