Best average rating - php

I have created a simple rating system for news articles. The news articles are stored in the database table called 'articles'. Each article has a unique id, starting from 1.
So I have 2 articles, ID 1 and ID 2.
I also have a table called 'ratings' that takes the users unique ID, the article ID and the rating that the user gave.
If I give an article with ID 2 a 5/5 star rating, it goes into the 'ratings' table, with article ID 2, my user ID and the rating of 5.
I have figured out how to display the average rating of each article, but I would like to find out how to show the BEST average rating of articles in descending order. Is that at all possible? How could this be done?
Here is how I find the average:
<?
$votesForThis = 0;
$sql = "SELECT * FROM ratings WHERE articleID = ".$articleID." ORDER BY id ASC";
// Check if there are results
if ($result = mysqli_query($con, $sql)) {
// Loop through each row in the result set
while($row = mysqli_fetch_assoc($result)) {
$votesForThis++;
}
}
$result = mysqli_query($con, 'SELECT SUM(vote) AS vote_sum FROM ratings WHERE articleID=' . $articleID);
$row = mysqli_fetch_assoc($result);
$voteSum = $row['vote_sum'];
$averageVotes = $voteSum / $votesForThis;
?>

MySQL has an avg function you can use instead of implementing this logic yourself. From there, it's just a matter of grouping by the article ID and ordering by the average:
SELECT articleID, AVG(vote)
FROM ratings
GROUP BY articleID
ORDER BY 2 DESC

The best practice for doing this is to add a new column to your article table called average_rating and update it with a cron job or after every voting.
Keep in mind that after a while your rating table will become giant and calculating average rating on every page refresh will put huge load on your server.

I would use de-normalization in this one.
I would use triggers to update a previously created column on table articles which would store it's average rating.
I would have posted an example of trigger but you haven't posted which database are you using.
Mysql: https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
Postgresql: https://www.postgresql.org/docs/9.1/sql-createtrigger.html
Each time a rating it's done, updated or deleted a trigger would update this column with it's current average using the built-in avg function.
At the end you'll only have to create a select on the articles table ordered by this rating column desc.
And create an index on this average rating column to have even faster results.

SELECT articleID, AVG(vote)
FROM ratings
GROUP BY articleID,vote
ORDER BY DESC
used this Query

Related

in SQL/PHP returning id with the highest and 2nd-5th highest date

As said in the title, I need FIVE queries that returns the ID for rows with the 1st-5th most recent date.
Table: film
id releasedate
232143 2013-06-20
536523 2013-07-20
453554 2013-08-20
098776 2013-09-20
549302 2013-10-20
i.e the first query would return the id 549302
I think this would work for the first query:
$first = $db->query("SELECT id, FROM film WHERE MAX(releasedate)" );
PS: Sorry for the poor formatting of this post, can anyone tell me how to display tables appropriately?
I need to display each id at different points on the web page. Simply returning a list of ids won't suffice. What I really need is for each id to be encapsulated into a unique variable so i can call them at different points on the web page.
No, you don't need five queries.
$first = $db->query("SELECT `id` FROM `film` ORDER BY `releasedate` DESC LIMIT 5" );
This will get the IDs from the database of the five most recent films in your table.
To access each of these just run through a while loop.
while($row = $first->fetch_assoc()) {
$row['id']; # Each ID will be available like this.
}
If you really need to do this in separate queries, you can use the 2-argument form of the LIMIT clause, which is LIMIT offset, count. To get the newest film, use
SELECT id FROM film ORDER BY releasedate DESC LIMIT 0, 1
To get the 2nd most recent film, use
SELECT id FROM film ORDER BY releasedate DESC LIMIT 1, 1
the next one is
SELECT id FROM film ORDER BY releasedate DESC LIMIT 2, 1
and so on.
But it should be better to get them all in one query with
SELECT id FROM film ORDER BY releasedate DESC LIMIT 5
You can then save them all in an array with:
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$ids[] = $row['id'];
}
Then you can use $ids[0] to display the most recent film, $ids[1] for the second most recent, and so on.

How do I select the top three rows in my database for posts

I have created a posting system along with a liking system. I wanted to select the top three posts with the most likes but I don't know how to do that.
I have this code but I can't figure out how to select more than just one row.
$get_pop_posts = mysql_query( "SELECT MAX( likes ) AS popular_posts FROM `posts`;" );
while($fetch_pop_posts = mysql_fetch_array($get_pop_posts)){
$pop_posts = $fetch_pop_posts['popular_posts'];
echo $pop_posts;
}
this piece of code only fetches one row from the database.
SELECT *
FROM posts
order by likes desc
limit 3
SELECT MAX( likes ) AS popular_posts FROM posts
This query return single result because of the function MAX().
Try this
SELECT TOP 3 FROM posts
Firstly give unique id to each post that should be incremented automatically each time a new post comes.
Then,
SELECT id FROM posts order by likes desc limit 3
Pass these id's as arrays to get the complete post.

select 3 rows from mysql table, then get each row's specific column

Select 3 rows from table1
Get a specific column data out of each row.
Then use that each column data obtained , to make a query again to get data from table2.
Store the data obtained in step 4 into a variable for each row.
Then put them in json array (table 1 , 3 rows + table 2's data(each of them).
I am building a rank table, it displays top 3 users with their rank name.
For example:
User1 has 2000 points , user 2 has 4000points , user 3 has 10k points , so the top 3 user is :
user 3 > user 2 > user 1
So , i want the php to go to 'users' table and get the top 3 members using this:
$query = mysql_query("SELECT * FROM users ORDER BY pts DESC LIMIT 3");
$rows = array();
while($r = mysql_fetch_assoc($query)) {
$rows[] = $r;
}
Table structure for 'user':
1.username(varchar)
2.pts(int)
After the rows are put into an array , how can i get 'points' for each of the row in that array.
Then go to 'rank' table to get their ranknames.
Table structure for 'rank':
1.rank(varchar)
2.pts(int)
Inside rank table there is 'pts' to let php choose compare which rank the user is at based on the points from each row of the array.
Normally i would use this if its only for 1 user , but for multiple users , im not sure:
$result = mysql_query("SELECT * FROM rank WHERE pts <= '$upts' ORDER BY pts DESC LIMIT 1")
or die(mysql_error());
Then after getting the rank for the top 3 users , php will now add the ranks to each of the user(row) in that array(of course , add it to the rank owner, not just simply place it in).
Then JSON encode it out.
How can i do this?
I am not sure if this is what you want. That is combine the two query into one query. Please take a look at http://sqlfiddle.com/#!2/ad419/8
SELECT user.username,user.pts,rank.rank
FROM user LEFT JOIN rank
ON user.pts <=rank.pts group by user.id
UPDATED:
For extracting top 3, could do as below;
SELECT user.username,user.pts,rank.rank
FROM user LEFT JOIN rank
ON user.pts <=rank.pts
GROUP BY user.id
ORDER BY pts DESC LIMIT 3
If i understand correctly, you need to get values from Rank and Users tables. In order to do that in just one query You need to add FK (Foreign Key) to the Rank table that points to a specific user in the Users table.
So you need to add userId to the Rank table and then you can run:
SELECT r.rank, u.points from users u,rank r where u.userId = r.userId
This is roughly what you need.
Not quite the answer to your exact question, but this might be of use to you: How to get rank using mysql query. And may even mean that you don't require a rank table. If this doesn't help, I'll check back later.
Use this query
$query = "SELECT
u.pts,
r.rank
FROM users as u
left join ranks as r
on r.pts = u .pts
ORDER BY pts DESC
LIMIT 3";
This will bring what you required without putting into an array
$rec = mysql_query($query);
$results = arrau();
while($row = mysql_fetch_row($rec)){
$results[] = $row;
}
echo json_encode($results);
It looks like what you're trying to do is retrieve the rank with the highest point requirement that the user actual meets, which isn't quite what everyone else is giving here. Fortunately it is easily possible to do this in a single query with a nice little trick:
SELECT
user.username,
SUBSTRING_INDEX(GROUP_CONCAT(rank.rank ORDER BY pts DESC),",",1) AS `rank`
FROM user
LEFT JOIN rank ON user.pts >= rank.pts
GROUP BY user.id
ORDER BY pts DESC
LIMIT 3
Basically what the second bit is doing is generating a list of all the ranks the user has achieved, ordering them by descending order of points and then selecting the first one.
If any of your rank names have commas in then there's another little tweak we need to add on, but I wouldn't have thought they would so I've left it out to keep things simple.

How can i retrieve data from a table?

I am working in PHP. This is my query:
$sql = "SELECT *
from place as s
where checkDistance($lati1,$longi1,s.lat,s.lon)<$dist";
This place table has three fields: placeId, PlaceName and Address. Now I want to calculate rating of placeId which are the result of above query. To calculate the rating I have another table rating in which there are two fields: placeId and noOfPerson.
Rating will be calculated by (noOfPerson/maximum_no_of_person) for each placeId. How can i implement this?
Your query could do majority of work here, this will select values from place table joined with number of person for each place, ordered by ranking you need, top-bottom:
SELECT s.placeid, s.PlaceName, s.Address, r.noOfPerson
FROM place as s JOIN rating as r ON (s.placeid = r.placeid)
WHERE checkDistance($lati1,$longi1,s.lat,s.lon)
ORDER BY r.noOfPerson / ( SELECT MAX(noOfPerson) FROM rating ) DESC

mysql select statement and limiting the number of records

I am coding a blog post kind of thing, where the author will post the article and it will be displayed in the front end, my problem starts for selecting the posts as i have to meet certain conditions for posting the news in the front end,
I have 4 fields in the database namely
title
pic_title
pic_brief
pic_detail
you guessed it right apart from the title table the rest of three will hold the path to the images in varchar datatype, which will be used to display as the post, the format of the front end is such that
a) there will be total of eight post
displaying in the front end (eight
entries from the database)
b) there will be three post on the top which will include the value from
the table title, pic_title and
pic_brief (total of 3 values)
c) and the rest five will contain just the title and pic_title
(excluding the three entries of top)
Please NOTE: i want the second query to exclude the top 3 record
which already exist in the top i.e
(first query = 3 post in descending
order, second query = 8 - first 3 = 5
post)
The Order of the Post i want is by id DESC
EDIT: I took the first query as
SELECT * FROM news ORDER BY id DESC LIMIT 3
Now if i take the same second query and try populating the values by desc order again the same records will be accessed
In simple words i want a query that will skip the last three records order by id DESC
How do i achieve this feat in PHP?
If you just want the SQL, here it is:
First query
SELECT * FROM `table` LIMIT 3
Second query
SELECT * FROM `table` LIMIT 3,5
(where table is the name of your table of course. Of course you may want to add some ORDER BY clause. To execute these queries in PHP, I suggest reading the manual. If you have any specific problems after doing so, then you can post a new question.
This is a situation where I'd likely opt to select all eight records at once - the less trips to the database, the better.
SELECT t.title,
t.pic_title,
t.pic_brief
FROM TABLE t
ORDER BY t.id DESC
LIMIT 8
...because the rest is just presentation:
$query = sprintf("SELECT t.title,
t.pic_title,
t.pic_brief
FROM TABLE t
ORDER BY t.id DESC
LIMIT 8");
// Perform Query
$result = mysql_query($query) or die( mysql_error() );
$rowcount = 1;
// Use result
while ($row = mysql_fetch_assoc($result)) {
if(rowcount <= 3) {
echo $row['title']
echo $row['pic_title']
echo $row['pic_brief']
} else {
echo $row['title']
echo $row['pic_title']
}
++$rowcount;
}
first query will be like this
"select title, pic_title , pic_brief from table_name order by post_id desc limit 0 , 3"
and rest of five will be
"select title, pic_title from table_name order by post_id desc limit 3 , 5"
second query will exclude the three results returned by first query...
If you want more perfection you can collect all three Ids returned by first query and can add NOT IN in second query.
"select title, pic_title from table_name where post_id not in (1,2,3) order by post_id desc limit 0 , 5";

Categories