How can I perform these MySQL subqueries in a cleaner way? - php

Using legacy code which uses mysql instead of mysqli/pdo so don't worry about this, I'll update the queries for this later.
Even though my current method works, I'm positive there is a cleaner way of doing this rather than a query and 3 subqueries. I mainly want to learn how to better enhance my queries and minimizing the amount of them.
What I'm trying to do is
echo out all the data for each date with the date displayed on top
Display the count of entries for each user on that particular day next to the user
For each date, at the bottom of the above 2 bits of data, display the user/s with the highest number of entries
$query = mysql_query('SELECT * FROM entries GROUP BY DATE(dt)');
$g = 0;
while ($row = #mysql_fetch_array($query))
{
$group[$g] = date('y-m-d', strtotime($row['dt']));
echo $group[$g] . "<br />";
//display the person's name for today with their count
$dayquery = mysql_query('SELECT *, COUNT(username) as total FROM entries WHERE DATE(dt) = "'.$group[$g].'" GROUP BY username ORDER BY COUNT(username) DESC');
while ($today = #mysql_fetch_array($dayquery))
{
echo $today['first_name'] . " | " . $today['total'] . "<br />";
}
//display the highest count for today
$topquery = mysql_query('SELECT COUNT(username) as highest FROM entries WHERE DATE(dt) = "'.$group[$g].'" GROUP BY username ORDER BY COUNT(username) DESC LIMIT 1');
while ($toptoday = #mysql_fetch_array($topquery))
{
echo "Highest today: " . $toptoday['highest'] . "<br /><br />" ;
}
//display the users with the highest count for today
echo "Highest users: ";
$userstopquery = mysql_query('SELECT *, COUNT(username) as total FROM entries WHERE DATE(dt) = "'.$group[$g].'" AND COUNT(username) = "' . $toptoday['highest'] . '" AND GROUP BY username');
while ($topusers = #mysql_fetch_array($userstopquery))
{
echo $topusers['first_name'] . "<br />" ;
}
$g++;
}
The trouble I'm having is that when I try and reduce these subqueries and use MAX it will only output the highest count but not all the data for each date, which is what I need, including output of the user/s with the most amount of entries for that given day.

You could start with something like this. Note that I'm not using PHP's mysql_ API as it was deprecated 3 or 4 years ago...
require('path/to/mysqli/connection/stateme.nts');
$array = array();
$query = "
SELECT e.dt
, e.username
, COUNT(*) ttl
FROM entries e
GROUP
BY e.dt
, e.username
ORDER
BY e.dt, ttl DESC;
";
$result = mysqli_query($conn,$query);
while ($row = mysqli_fetch_assoc($result))
{
$array[] = $row;
}
print_r($array);

Related

How can I display rank to leaderboard from score

I'm trying to create a leaderboard using a score table from Mysql.
I only use "name" and "score" from my score table.
I can display my leaderboard ordered by best score but can't display the rank with it.
Here is my php file to get datas:
// Connect to server and select database.
$con = mysqli_connect($host, $db_username, $db_password, $db_name);
// Retrieve data from database
$sql = "SELECT *
FROM scores
ORDER BY score DESC
LIMIT 10"; // The 'LIMIT 10' part will only read 10 scores. Feel free to change this value
$result = mysqli_query($con, $sql);
// Start looping rows in mysql database.
while($rows = mysqli_fetch_array($result)){
echo $rows['name'] . "|" . $rows['score'] . "|";
// close while loop
}
// close MySQL connection
mysqli_close($con);
?>
I guess I probably need to have something like this in the end:
while($rows = mysqli_fetch_array($result)){
echo $rows['rank'] . "|" . $rows['name'] . "|" . $rows['score'] . "|";
But can't manage to get it properly…
The result should be displayed like:
<br/> Mardoch 49507
<br/> Gunthylapointe 49504
What am I doing wrong?
Do you want window functions?
select rank() over(order by score desc) rn, s.*
from scores
order by score desc
This adds another column to the resultset, called rn, that contains the rank of each row, ordered by descending score.
Well, I change a bit my code and added this:
// Retrieve data from database
$sql = "SELECT *
FROM scores
ORDER BY score DESC";
//LIMIT 10"; // The 'LIMIT 10' part will only read 10 scores. Feel free to change this value
$result = mysqli_query($con, $sql);
$i = 0;
// Start looping rows in mysql database.
while($rows = mysqli_fetch_array($result)){
$i++;
echo ($i) . "|" . $rows['name'] . "|" . $rows['score'] . "|";
// close while loop
}
It's work a bit better but it stop my leaderboard at a moment and display a lot of 0 after:
screen capture
Seems the problem is because the next score is exactly the same as the previous…So it breaks here

Remaining two rows get skipped in for-loop

I am programming a maintenaince thing for tournaments. Players are divided into "leagues". At the end, the first player of league x gets to play against the losers of league y. Winner of league y meets loser of league z etc. Then this rule gets repeated fot the numbers 2 and second lasts of the next league, 3rds and 3rd lasts of next league and so on. The number of leagues varies every time. Everything works really fine until it comes to the last two remaining players, let's say the middle player of league x don't get connected to the middle player of league y.
I found a way to work around this glitch but I'd rather have it working like it should.
This is my code: (khzz is the total amount of players without regarding leagues). Anybody sees what's wrong? Thanks!
for ($doen=0; $doen<=$hkzz; $doen++) {
$unid2 = "" . $doen . "-" . rand(1600,20000) . "";
$koppelpak = $conn->query ("SELECT * FROM poules WHERE poule='$startmet' AND amsyst='' ORDER BY ABS(ptn) DESC, karma DESC LIMIT 1");
//$kppk = mysqli_fetch_assoc($koppelpak);
while ($kppk = $koppelpak->fetch_array()) {
$conn->query("UPDATE poules SET amsyst='$unid2' WHERE koppel='$kppk[koppel]' ") or die(mysqli_error($conn));
echo "koppel " . $kppk['koppel'] . " uit poule " . $startmet . " tegen ";
$koppelpak2 = $conn->query ("SELECT * FROM poules WHERE poule='$volgende' AND amsyst='' ORDER BY ABS(ptn) ASC, karma ASC LIMIT 1");
while ($kppk2 = $koppelpak2->fetch_array()) {
$conn->query("UPDATE poules SET amsyst='$unid2' WHERE koppel='$kppk2[koppel]' ") or die(mysqli_error($conn));
echo "koppel " . $kppk2['koppel'] . " uit poule " . $volgende . "<br />";
}
$startmet = $startmet + 1;
$werk = $werk + 1;
if ($startmet>$hoep) { $startmet="1"; }
$volgende = $volgende + 1;
if ($volgende>$hoep) { $volgende="1"; }
//$volgen = $volgen + 1;
} // while
} // for

Printing table values in ascending order

I am trying to print out a users name and totalspent value in ascending order of totalspent. I.e, user that has spent the most will be outputed first then the next highest spender etc.
This is my current code, however, this only seems to output a single table row an infinite amount of times.
$query = "SELECT * FROM (
SELECT * FROM `members` ORDER BY `totalspent` DESC LIMIT 10) tmp order by tmp.totalspent asc";
$result = $mysqli->query($query);
while ($row = $result->fetch_assoc()) {
echo $row['name'] . " - $" . $row['totalspent'] . "<br/>";
}
select member_name, totalspent from tmp order by totalspent desc;
still can you show snippet of your table and snippet of answer you desire
The best way I can prefer for you to join two tables. The code should like follows-
$query = "SELECT * FROM temp.tmp, mem.members WHERE temp.totalspend = mem.totalspend ORDER by temp.totalspend ASC";
$result = $mysqli->query($query);
while ($row = $result->fetch_assoc()) {
echo $row['name'] . " - $" . $row['totalspent'] . "<br/>";
}
I believe, it will work for your smoothly... TQ

Can't get score to update with this mysql statement

I'm guessing that I'm just a little rusty or something because it seems like this should be working. Am I missing something here...
Here is the code I am trying to use...
<?php
echo dbConn();
$existing_time = mysql_result(mysql_query("SELECT p_time FROM scores WHERE p_uid=$uid"), 0);
$existing_category = mysql_result(mysql_query("SELECT p_cat FROM scores WHERE p_uid=$uid AND p_cat=$pieces"), 0);
if ($existing_category == "") {
mysql_query(
"INSERT INTO scores VALUES (
'',
'$uid',
'$pusername',
'$time',
'$pieces'
)");
} elseif ($existing_time <= $time) {
echo "No Change! Old Score Was Better (Lower)";
} elseif ($existing_time > $time) {
mysql_query("UPDATE scores SET p_time = " . $time . " WHERE p_uid = " . $uid . " AND p_cat = " . $pieces . "");
};
?>
Now... Here is what I am trying to do...
I am collecting info from the database where the users username AND category match. If the category for that user does not exist, it inserts the latest score. (This much works.)
Then, if the category does exist but the old score is better, it just does nothing. (This part works too)...
However, what I can't seem to do is get it to update the last score, if the current score is better (lower score, since this is a time based game.) It doesn't update the score.
I am trying it this way: By updating a row in "scores" where the USERNAME and the CATEGORY match at the same time.
Please note... where it says "pieces". this is a category. Where it says "time", this is a score. The score is returned as 00:00:00 for hours minutes and seconds.
EXAMPLE: (in parentheses is the database row name)
id (ID) = just KEY id in sequencial order
user id (p_uid) = 123456789
username (p_username) = somename
score (p_time) = 00:01:03
category (p_cat) = 10
Change you update statement to:
mysql_query("UPDATE scores SET p_time = '" . $time . "' WHERE p_uid = " . $uid . " AND p_cat = " . $pieces . "");
You have missed quotes in the update statement around $time.

Retrieving values from several tables in a MySQL database

I have a MySQL database called "bookfeather" with several tables that contain list books. Under each table, each book has a given number of votes. The PHP code below allows the user to enter in a book title ($entry), and then returns the total number of votes that book has in all tables ($sum).
How could I use PHP to make a 2-column, 25-row table that lists the 25 books in the database with the highest value for $sum (in descending order)?
Thanks in advance,
John
mysql_connect("mysqlv10", "username", "password") or die(mysql_error());
mysql_select_db("bookfeather") or die(mysql_error());
// We preform a bit of filtering
$entry = strip_tags($entry);
$entry = trim ($entry);
$entry = mysql_real_escape_string($entry);
$result = mysql_query("SHOW TABLES FROM bookfeather")
or die(mysql_error());
$table_list = array();
while(list($table)= mysql_fetch_row($result))
{
$sqlA = "SELECT COUNT(*) FROM `$table` WHERE `site` LIKE '$entry'";
$resA = mysql_query($sqlA) or die("$sqlA:".mysql_error());
list($isThere) = mysql_fetch_row($resA);
$isThere = intval($isThere);
if ($isThere)
{
$table_list[] = $table;
}
}
//$r=mysql_query("SELECT * , votes_up - votes_down AS effective_vote FROM `$table[0]` ORDER BY effective_vote DESC");
if(mysql_num_rows($resA)>0){
foreach ($table_list as $table) {
$sql = "SELECT votes_up FROM `$table` WHERE `site` LIKE '$entry'";
$sql1 = mysql_query($sql) or die("$sql:".mysql_error());
while ($row = mysql_fetch_assoc($sql1)) {
$votes[$table] = $row['votes_up'];
$sum += $row['votes_up'];
//echo $table . ': "' . $row['votes_up'] . " for $entry from $table\"<br />";
}
}
}
else{
print "<p class=\"topic2\">the book \"$entry\" has not been added to any category</p>\n";
}
//within your loop over the DB rows
//$votes[$table] = $row['votes_up'];
//afterwards
if($sum>0){
print "<table class=\"navbarb\">\n";
print "<tr>";
print "<td class='sitenameb'>".'<a type="amzn" category="books" class="links2b">'.$entry.'</a>'."</td>";
print "</tr>\n";
print "</table>\n";
//echo "<p class=\"topic3\">".''.$entry.''. "</p>\n";
echo "<p class=\"topic4\">". number_format($sum) . ' votes in total.'."</p>\n";
Try something like this. All of this hasn't been tested so please add comments for changes. I'll work with you to get the code right.
// After getting your array of tables formated like
$tableArray = array("`tableA`", "`tableB`", "`tableC`");
// create a table statement
$tableStatement = implode(", ", $tableArray);
// create a join statement
$joinStatement = "";
for ($i = 1; $i < count($tableArray); $i++) {
if ($joinStatement != "")
$joinStatement .= " AND ";
$joinStatement .= $tableArray[0] . ".site = " . $tableArray[$i] . ".site"
}
$firstTable = $tableArray[0];
$sql = "SELECT SUM(votes_up) FROM " . $tableStatement . " WHERE " . $joinStatement . " AND " . $firstTable . ".site LIKE '" . $entry . "' GROUP BY " . $firstTable . ".site ORDER BY SUM(votes_up) DESC";
Edit --------
I now realize that the query above won't work perfectly because votes_up will be ambiguous. Also because you probably want to be doing joins that grab records that are only in one table. I think the concept is the right direction even though the query may not be perfect.
You can do something like
$selectStatement = "SUM(tableA.votes_up) + SUM(tableB.votes_up) as total_votes_up"
I did something like this recently. In your database, you'll have to rename each field to a corresponding book name.php like (TaleofTwoCities.php). Now on your page that will display the vote results, you'll need to include some php files that will drive the database query on each load. I called mine "engine1.php" and "engine2.php." These will do all your sorting for you.
$query1 = mysql_fetch_row(mysql_query("SELECT url FROM pages ORDER BY counter DESC
LIMIT 0,1"));
$query2 = mysql_fetch_row(mysql_query("SELECT url FROM pages ORDER BY counter DESC
LIMIT 1,1"));
$query3 = mysql_fetch_row(mysql_query("SELECT url FROM pages ORDER BY counter DESC
LIMIT 2,1"));
and so on.. then..
$num1 = "$query1[0]";
$num2 = "$query2[0]";
$num3 = "$query3[0]";
That part sorts your listings by the number of votes from highest to lowest, with url, in your case, being the name of the books(remember you want it to end in .php - you'll see why in a second), and counter being the field that logs your votes.
Make your second engine.php file and add something like this:
$vquery1 = mysql_fetch_row(mysql_query("SELECT counter FROM pages WHERE
url='book1.php'"));
$vquery2 = mysql_fetch_row(mysql_query("SELECT counter FROM pages WHERE
url='book2.php'"));
$vnum1 = "$vquery1[0]";
$vnum2 = "$vquery2[0]";
and so on... Until you get to 25 for both this and engine 1.
Now, in your results page, after you put in the require_once(engine.php) and require_once(engine2.php) at the start of your body, start an HTML table. You only want two columns, so it'll be something like..
<table border=1 cellspacing=0 cellpadding=0>
<tr>
<?php include $num1; ?>
</tr>
<tr>
<?php include $num2; ?>
</tr>
And so on... By naming your field with "book1.php" and including the engines, $num1 will change to a different .php file depending on votes from high to low. Now all you have to do is make small php files for each book like so - no headers or anything because you're inserting it into the middle of html code already:
<td style="width:650px;"><center><img src="images/book1.jpg" alt="" border="none"
/></a></center></td>
<td style="width:150px;">Votes: <?php echo $vnum1;?></td>
And there you have it. A code that will dynamically give you results from high to low depending on the number of votes each book has.

Categories