How to iterate the values of the array in a query? - php

I want to iterate the values of the array $code and $per_sectionfrom the query below. What looping method should i use? Or is this the right thing to do?
//total students
$count_query=mysql_query("select total_students from subject where teacherid = '$get_id'");
while($count_row=mysql_fetch_array($count_query)){
$total += $count_row['total_students'];
}
$query = mysql_query( "Select code,total_students from subject where teacherid='$get_id'");
while($result=mysql_fetch_assoc($query))){
$section = ($result['total_students']/ $total)*30;
$per_section[] = round($section, 0, PHP_ROUND_HALF_UP);
$code[] = $result['code'];
}
//perform this statement for a number of times depending on the number of array of $code..
$user_query=mysql_query("select * from result where subject_id ='$code' and faculty_id = '$get_id'LIMIT $per_section ")or die(mysql_error());
while($row=mysql_fetch_assoc($user_query)){
...
}
Sample data:
Subject table
code total_students teacherid
IT230 45 11-0009
IT213 44 11-0009
IT214 40 11-0009
result table
subject__id faculty_id
IT230 11-0009
IT213 11-0009
IT214 11-0009
Expected Results:
I want to show only 30 records of students that matches the result table.
Since the total students of that teacher are 45, 44, 40 = 129. This is the $per_section
IT230 only needed students = (45/129)*30 = 10.46 or i need only 11 of the results.
IT213 only needed students = (44/129)*30 = 10.23 or i need only 10 of the results.
IT214 only needed students = (40/129)*30 = 9.3 or i need only 9 of the results.
I want to search for the records in IT230 and select only 11 of them.
IT213 for only 10 and IT214 for 9. Since i only have 3 records, only these three records will show up.

As mentioned in the comments on your question, it is much better practice to use prepared statements via PDO and JOIN the two tables:
$dbh = new PDO('mysql:host=localhost;dbname=mydb', 'username', 'password');
$stmt = $dbh->prepare('
SELECT result.*
FROM result
JOIN student ON result.subject_id = student.code
WHERE student.id = :id
');
$stmt->execute(['id' => $id]);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

Use one query that joins the two tables:
SELECT s.total_students, s.code, r.*
FROM students AS s
LEFT JOIN result AS r ON r.subject_id = s.code
WHERE s.teacher_id = '$get_id' AND r.faculty_id = '$get_id'
ORDER BY s.code
Then you can get all the information in a single loop:
while ($result = mysqli_fetch_assoc($query)) {
if (!isset($per_section[$result['code']]) {
$per_section[$result['code']] = round($result['total_student']/$total*30, 0, PHP_ROUND_HALF_UP);
$code[] = $result['code'];
}
if ($result['subject_id'] !== null) {
// do stuff with columns from result table here
}
}

Related

Generate html table based on 2x mysql db queries

I'm trying to show stuff queried from two tables, but on one html table. Data is shown for the last 30 days, based on which, an html table is being generated.
Currently I'm stuck using two queries and generating two html tables:
$query1 = mysqli_query( $con, "SELECT date, stuff* " );
while( $record = mysqli_fetch_array( $query1 ) ){
echo '<html table generated based on query>';
}
$query2 = mysqli_query( $con, "SELECT date, other stuff*" );
while( $record = mysqli_fetch_array( $query2 ) ){
echo '<another html table generated based on query2>';
}
Is there a possibility to show both queries on one html table instead?
Note that it gets tricky since we have dates on one table which are not necessarily found in the second table or vice-versa.
Thanks for the support guys. So far I'm stuck at this:
SELECT * FROM user_visit_logs
LEFT JOIN surfer_stats ON user_visit_logs.date = surfer_stats.date
UNION
SELECT * FROM user_visit_logs
RIGHT JOIN surfer_stats ON user_visit_logs.date = surfer_stats.date
The query completes, but the 2nd table fields are all null:
Furthermore, it breaks when I add additional clause like:
WHERE user_id = '{$_SESSION['user_id']}' ORDER BY date DESC LIMIT 30
I think you are after FULL OUTER JOIN concept:
The FULL OUTER JOIN keyword returns all rows from the left table (table1) and from the right table (table2)
In which you may use common dates as a shared row.
So the query will get to simple one:
$query = "
SELECT table1.date, stuff
FROM table1
LEFT OUTER JOIN table2 ON table1.date = table2.date
UNION
SELECT table2.date, other_stuff
FROM table1
RIGHT OUTER JOIN table2
ON table1.date = table2.date
";
$result = mysqli_query( $con, $query );
while( $record = mysqli_fetch_array( $result ) ){
echo '<html table generated based on query>';
}
Example
This is an schematic diagram of FULL OUTER JOIN concept:
After running into quite a few bumps with this one, I finally managed to merge 2 columns from each table and also to use where and sort clauses on them with the following query:
( SELECT user_visit_logs.user_id,user_visit_logs.date,unique_hits,non_unique_hits,earned,sites_surfed,earnings FROM user_visit_logs
LEFT OUTER JOIN surfer_stats ON user_visit_logs.user_id = surfer_stats.user_id AND user_visit_logs.date = surfer_stats.date where user_visit_logs.user_id = 23 ORDER BY date DESC LIMIT 30 )
UNION
( SELECT surfer_stats.user_id,surfer_stats.date,unique_hits,non_unique_hits,earned,sites_surfed,earnings FROM user_visit_logs
RIGHT OUTER JOIN surfer_stats ON user_visit_logs.user_id = surfer_stats.user_id AND user_visit_logs.date = surfer_stats.date where user_visit_logs.user_id = 23 LIMIT 30 )
Simplified, "user_visit_logs" and "surfer_stats" were the 2 tables needed to be joined.
Absolutely. Just pop them both into a variable:
$data = '';
$query = mysqli_query($con,"SELECT date, stuff* ");
while($record = mysqli_fetch_array($query)) {
$data.= '<tr><td>--Your Row Data Here--</td></tr>';
}
$query2 = mysqli_query($con,"SELECT date, other stuff*");
while($record = mysqli_fetch_array($query2)) {
$data .= '<tr><td>--Your Row Data Here--</td></tr>';
}
echo "<table>$data</table>";
Instead of using echo in your loop, you're just storing the results in $data. Then, you're echoing it out after all data has been added to it.
As for your second point, it's not a big deal if fields don't exist. If they're null, you'll just have a column that doesn't have data in it.
Here's an example with fake column names:
$data = '';
$query = mysqli_query($con,"SELECT date, stuff* ");
while($record = mysqli_fetch_array($query)) {
$data.= "<tr><td>{$record[id]}</td><td>{$record[first_name]}</td><td>{$record[last_name]}</td></tr>";
}
$query2 = mysqli_query($con,"SELECT date, other stuff*");
while($record = mysqli_fetch_array($query2)) {
$data .= "<tr><td>{$record[id]}</td><td>{$record[first_name]}</td><td>{$record[last_name]}</td></tr>";
}
echo "<table><tr><th>ID</th><th>First Name</th><th>Last Name</th></tr>$data</table>";
I have a feeling I may have misunderstood the need. If so, I apologize. If you can elaborate just a bit more I can change my answer :)

how to use PHP function to get ranks for multiple columns in a table more efficent

I am trying to get single rank for a user for each stat "column" in the table. I am trying to do this as more efficiently because i know you can.
So I have a table called userstats. in that table i have 3 columns user_id, stat_1, stat_2, and stat_3. I want to me able to get the rank for each stat for the associated user_id. with my current code below i would have to duplicate the code 3x and change the column names to get my result. please look at the examples below. Thanks!
this is how i currently get the rank for the users
$rankstat1 = getUserRank($userid);
<code>
function getUserRank($userid){
$sql = "SELECT * FROM ".DB_USERSTATS." ORDER BY stat_1 DESC";
$result = mysql_query($sql);
$rows = '';
$data = array();
if (!empty($result))
$rows = mysql_num_rows($result);
else
$rows = '';
if (!empty($rows)){
while ($rows = mysql_fetch_assoc($result)){
$data[] = $rows;
}
}
$rank = 1;
foreach($data as $item){
if ($item['user_id'] == $userid){
return $rank;
}
++$rank;
}
return 1;
}
</code>
I believe there is a way for me to get what i need with something like this but i cant get it to work.
$rankstat1 = getUserRank($userid, 'stat_1'); $rankstat2 =
getUserRank($userid, 'stat_2'); $rankstat3 = getUserRank($userid,
'stat_3');
You can get all the stat ranks using one query without doing all the PHP looping and checking.
I have used PDO in this example because the value of the $userid variable needs to be used in the query, and the deprecated mysql database extension does not support prepared statements, which should be used to reduce the risk of SQL injection.
The function could be adapted to use the same query with mysqli, or even mysql if you must use it.
function getUserRanks($userid, $pdo) {
$sql = "SELECT
COUNT(DISTINCT s1.user_id) + 1 AS stat_1_rank,
COUNT(DISTINCT s2.user_id) + 1 AS stat_2_rank,
COUNT(DISTINCT s3.user_id) + 1 AS stat_3_rank
FROM user_stats f
LEFT JOIN user_stats s1 ON f.stat_1 < s1.stat_1
LEFT JOIN user_stats s2 ON f.stat_2 < s2.stat_2
LEFT JOIN user_stats s3 ON f.stat_3 < s3.stat_3
WHERE f.user_id = ?"
$stmt = $pdo->prepare($sql);
$stmt->bindValue(1, $userid);
$stmt->execute();
$ranks = $stmt->fetchObject();
return $ranks;
}
This should return an object with properties containing the ranks of the given user for each stat. An example of using this function:
$pdo = new PDO($dsn, $user, $pw);
$ranks = getUserRanks(3, $pdo); // get the stat ranks for user 3
echo $ranks->stat_2_rank; // show user 3's rank for stat 2
$sql = "SELECT user_id, stat_1, stat_2, stat_3 FROM ".DB_USERSTATS." ORDER BY stat_1 DESC";
Also, unless there is a reason you need ALL users results, limit your query with a WHERE clause so you're only getting the results you actually need.
Assuming you limit your sql query to just one user, this will get that user's stats.
foreach($data as $item){
$stat_1 = $item['stat_1'];
$stat_2 = $item['stat_2'];
$stat_3 = $item['stat_3'];
}
If you get more than one user's stats with your sql query, consider passing your $data array back to the calling function and loop through the array to match the users stats to particular user id's.

PHP Sort an array

I have an array
$genreQuery = $con ->query ("select distinct(movie_year) from movies");
$movieGenre = array();
$movieTitle = array();
$movieList = array();
while($row = $genreQuery->fetch_object()) {
$movieGenre[] = $row;
}
foreach($movieGenre as $MGenre){
$query = $con ->query
("
select '$MGenre->movie_year' movie_year, IFNULL(count(*)/(select count(*)
from user_movie_ratings where user_id = '$userid'),0) rating
from user_movie_ratings umr,
movies m
where umr.user_id = '$userid'
and umr.movie_id = m.id
and m.movie_year = '$MGenre->movie_year' ORDER BY rating DESC;
");
while($row = $query->fetch_object()) {
$movieTitle[] = $row;
}
}
$text = "";
foreach($movieTitle as $MTitle){
if (empty($text)){
$text = "\"".$MTitle->movie_year."\"";}
else{
$text = $text.",\"".$MTitle->movie_year."\"";
}
}
$list = $con ->query
("
SELECT movie_name, avg_rating, image, id, genre
FROM movies
WHERE id NOT IN (SELECT movie_id FROM user_movie_ratings WHERE user_id = '$userid')
ORDER BY field(movie_year, $text), avg_rating DESC;
");
while($row = $list->fetch_object()) {
$movieList[] = $row;
}
The array is filled by the above query, what I want to do is sort it by the rating so that is looks like this
year rating
2014 0.0001
2015 0.0000
2013 0.0000
1967 0.0000
.... ......
.... ......
etc etc
I have tried adding ORDER BY rating DESC to the query, but that does not work and when I use rsort($movieTitle) it sorts by the year not the rating do I need to do some kind of multidimensional sort, or is there another way?
I would guess that ordering by rating does not work as you seem to be running multiple queries in a foreach loop and each iteration gets one year. So in that case, your order would be by year and then in the year by rating.
You should get rid of that loop and only do one query and then the condition and sort order would be:
...
AND m.movie_year IN (the,years,you,want)
ORDER BY rating DESC
By looping over the $movieGenre like you do now, you can easily generate a comma separated list for the years to use in the IN statement.
Edit: Based on your comment you want all years, so the foreach loop and the year condition in the query are unnecessary.
You probably want something like:
SELECT m.movie_year, IFNULL(count(*)/(select count(*)
from user_movie_ratings where user_id = '$userid'),0) rating
FROM user_movie_ratings umr,
movies m
WHERE umr.user_id = '$userid'
AND umr.movie_id = m.id
ORDER BY rating DESC
Assuming of course that the user ID is safe to use in a query, you should really use a prepared statement to avoid potential sql injection.
Now you have all your results in one query so there is no need for the outer loop any more.

SQL_CALC_FOUND_ROWS not working

so I execute query:
SELECT SQL_CALC_FOUND_ROWS * FROM table l LIMIT 10, 20;
which returns 20 rows from table, and there are a total 553 rows in the table
Then i immediately execute SELECT FOUND_ROWS();
But this instead only returns the number 1, despite the fact that there are 553 rows in my table (it's supposed to return 553, am I correct?)
what did I do wrong?
I suspect you have a syntax error, as names in SQL are not supposed to contain spaces. Try adding square brackets around [table 1], if that is the name of your table.
Remove your limit, I think there it is not showing 20 rows; it is showing only 10 rows.
$sql = "SELECT SQL_CAL_FOUND_ROWS * FROM users "; //don;t write table then table name
$result = mysql_query($sql);
//Use these according to your requirements:
$sql = "SELECT SQL_CAL_FOUND_ROWS * FROM users ";
$result = mysql_query($sql);
$sql = "SELECT FOUND_ROWS() AS `found_rows`";
$rows = mysql_query($sql);
$rows = mysql_fetch_assoc($rows);
$total_rows = $rows['found_rows'];

Total up how many men and how many women in a column. Possibly in order to repopulate the planet

Trying to search through a column in a db, and pull out the total number of males, and total number of females.
This data is stored in the db as f and m in the whatsex column.
$query = "SELECT whatsex, COUNT(*) FROM soberdata GROUP BY whatsex";
$result = mysqli_query($connection,$query) or die(mysql_error());
$sexdb = mysqli_fetch_array($result);
$totalmale = $sexdb['m'];
$totalfemale = $sexdb['f'];
echo $totalfemale." & ".$totalmale;
This code outputs nothing. What am I doing wrong?
$sexdb have only "whatsex" and "COUNT(*)" columns. You should use one of them
try
print_r($sexdb);
and look if some of results meet your needs
Your query is going to return a whatsex value, and a COUNT(*) value, not m or f. Doing a var_dump($sexdb) would show you what's in the array.
You are treating a multi-dimensional array as flat. You could do this to flatten it
$query = "SELECT whatsex, COUNT(*) as total FROM soberdata GROUP BY whatsex";
while ($row = mysqli_fetch_array($result)) {
$$row['whatsex'] = $row['total']; // this makes a variable ($m or $f) using the value of the row
}
$totalmale = !empty($m) ? $m : 0;
$totalfemale = !empty($f) ? $f : 0;
You should empty check the results of the db in case there is no male or female entries to avoid errors.

Categories