Sort posts by highest vote count? - php

SELECT
links.id,
links.url,
links.user_id,
links.title,
links.description,
links.nsfw,
links.posted,
links.category_id,
votes.vote
votes.vote_date
FROM links
INNER JOIN votes
ON votes.link_id = links.id
ORDER BY (I want to sort by the count of votes on the links) DESC
If I want to sort my links/posts by votes, how can I then do it with this SQL?
The link with the highest vote count shows first.

You want grouping. Try this:
SELECT
links.id,
links.url,
links.user_id,
links.title,
links.description,
links.nsfw,
links.posted,
links.category_id
FROM
links
INNER JOIN votes ON votes.link_id = links.id
GROUP BY links.id
ORDER BY COUNT(votes.id) DESC
I didn't test it (because I don't have your dataset), but it should be more or less correct.

Group by link id and select thee vot count
SELECT
count(*) as votecount,
links.id,
links.url,
links.user_id,
links.title,
links.description,
links.nsfw,
links.posted,
links.category_id,
votes.vote
votes.vote_date
FROM links
INNER JOIN votes
ON votes.link_id = links.id
GROUP BY links.id
2.) Wrap this in a superquery for sorting
SELECT * FROM (
<as above>
) AS baseview
ORDER BY votecount DESC

You can use a subquery:
SELECT links.id, links.url, votes.vote, votes.vote_date
FROM links
INNER JOIN votes ON votes.link_id = links.id
INNER JOIN (
SELECT links.id AS link_id, COUNT(votes.id) AS num_votes
FROM links
INNER JOIN votes ON votes.link_id = links.id
GROUP BY links.id
) AS votes_per_link ON links.id=votes_per_link.link_id
ORDER BY votes_per_link.num_votes DESC

Since I didn't understand which of these behaviors you are asking for, I post solutions to different cases here:
Get links, order by highest vote:
SELECT votes.link_id, links.url, MAX(votes.vote) AS maxvote
FROM votes INNER JOIN links ON links.id = votes.link_id
GROUP BY votes.link_id ORDER BY `maxvote` DESC;
Get links, order by average vote:
SELECT votes.link_id, links.url, AVG(votes.vote) AS avgvote
FROM votes INNER JOIN links ON links.id = votes.link_id
GROUP BY votes.link_id ORDER BY `avgvote` DESC;
Get links, order by votes count:
SELECT votes.link_id, links.url, COUNT(votes.vote) AS cntvotes
FROM votes INNER JOIN links ON links.id = votes.link_id
GROUP BY votes.link_id ORDER BY `cntvotes` DESC;
Get votes, by highest vote:
SELECT links.id, links.url, votes.vote
FROM links INNER JOIN votes ON links.id = votes.link_id
ORDER BY votes.vote DESC;
(I omitted some fields to shorten queries, of course feel free to add them back again).

Related

Multiple Counts in MYSQL PHP Query

I'm trying to create a leaderboard but i'm not sure how to do the mysql query.
I would like to count all the levels from a player in the skills table and get the total Level and count all the experience from a player in the experience table and get the Total Exp along with displaying the persons name from the users column.
There is 3 tables factions_mcmmo_users, factions_mcmmo_experience, factions_mcmmo_skills.
This is what i have so far but it doesn't work:
$sql = ("SELECT a.id,
(SELECT COUNT(*) FROM factions_mcmmo_experience WHERE user_id = a.id) as TotalXP,
(SELECT COUNT(*) FROM factions_mcmmo_skills WHERE user_id = a.id) as TotalLevel
FROM (SELECT DISTINCT id FROM factions_mcmmo_users) a LIMIT 10;");
Any help would be very appreciated
EDIT: I have it working now but i'm unsure if its the most efficient way to do things so if anyone could help me out if theres a better way, it would mean a lot.
I would also like to know if it's possible to display the total exp and level with commas if the number is in the thousands for example: total level 5,882 and total xp 582,882
EDIT 2:
I have figured out how to format the numbers but still don't know if my code is efficient
$sql = ("SELECT id, user,
(SELECT FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy),0) FROM factions_mcmmo_skills b WHERE b.user_id = a.id) as TotalLevel,
(SELECT FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy),0) FROM factions_mcmmo_experience c WHERE c.user_id = a.id) as TotalXP
FROM (SELECT id, user FROM factions_mcmmo_users) a group by id ORDER BY TotalLevel DESC, TotalXP DESC LIMIT 10;");
EDIT 3
Updated code from scaisEdge but was displaying everyones level as 1 and XP as 1, so i changed count(*) changed to sum, added an order By TotalLevel in Descending order and that seems to have worked but i can't get it to display the persons name (user column) in the user table? not sure if i was supposed to change to sum because it didn't work the other way.
$sql = ("SELECT a.id, b.TotalXP, c.TotalLevel
FROM (SELECT DISTINCT id FROM factions_mcmmo_users) a
INNER JOIN (
SELECT user_id, Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy) as TotalXP
FROM factions_mcmmo_experience
GROUP By user_id
) b on b.user_id = a.id
INNER JOIN (
SELECT user_id, Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy) as TotalLevel
FROM factions_mcmmo_skills
GROUP by user_id
) c on c.user_id = a.id
ORDER BY TotalLevel DESC
LIMIT 10;");
EDIT 4
Everything working but when i try to format the totals using "FORMAT(Sum(Columns), 0) on the inner joins, the EXP Total appears to work but the main Total Level is not displaying results that are over 1,000 and it breaks the leaderboard positioning, it should be sorting them on total level but it appears to be random, when u remove the format,0 it goes back to working
I would like it to display commas if the number number is the thousands for example: Total Level: 5,532 and Total EXP 5882,882
See live demo: http://mcbuffalo.com/playground/leaderboards/server/factions-mcmmo.php
Updated Code trying to use Format:
$sql = ("SELECT a.id, a.user, b.TotalXP, c.TotalLevel
FROM (SELECT id, user FROM factions_mcmmo_users) a
INNER JOIN (
SELECT user_id, FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy), 0) as TotalXP
FROM factions_mcmmo_experience
GROUP By user_id
) b on b.user_id = a.id
INNER JOIN (
SELECT user_id, FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy), 0) as TotalLevel
FROM factions_mcmmo_skills
GROUP by user_id
) c on c.user_id = a.id
ORDER BY TotalLevel DESC;");
EDIT 5
Changed number with PHP, everything works
Original Images
you could use an couple of inner join
$sql = ("SELECT a.id, a.name, b.TotalXP, c.TotalLevel
FROM (SELECT DISTINCT id, name FROM factions_mcmmo_users) a
INNER JOIN (
SELECT user_id, COUNT(*) as TotalXP
FROM factions_mcmmo_experience
GROUP By user_id
) b on b.user_id = a.id
INNER JOIN (
SELECT user_id, COUNT(*) as TotalLevel
FROM factions_mcmmo_skills
GROUP by user_id
) c on c.user_id = a.id
LIMIT 10

how to order data in mysql by join count?

I have two tables :
posts : id,title,content,show,created_at
comments: id,post_id,created_at
I'm trying to order posts by most commented.
SELECT *, COUNT(comments.id) AS total_comments
FROM comments LEFT JOIN posts ON posts.id = comments.post_id
WHERE posts.show = '1'
GROUP BY complains.id
ORDER BY total_comments DESC
The problem is that the posts with 0 comments don't appear.
Any help would be much appreciated.
With your join above, you are incorrectly joining to get commens that have posts
You should have done a right join or swap the tables in left join like below.
Select *, COUNT(comments.id) as total_comments
FROM posts
LEFT outer JOIN comments on posts.id = comments.post_id
WHERE posts.show = '1'
GROUP BY posts.id
ORDER BY total_comments DESC
You need to do a RIGHT JOIN instead of a LEFT JOIN. Or swap the tables in the LEFT JOIN clause.
While there are many ways to solve this, I think this code is easy to read and understand.
The query in the LEFT JOIN can be copied out and run on its own to help debug. Then you join that result set to the posts table and order the results.
SELECT p.*, IFNULL(c.total_comments, 0) as total_comments
FROM posts p
LEFT JOIN (select post_id, count(post_id) as total_comments from comments group by post_id) as c ON p.id = c.post_id
WHERE p.show = '1'
ORDER BY c.total_comments DESC

MySQL query to order results by number of votes in another table for the specifc result/row

Okay, so I have a query below I am trying to get to work.
Basically everything works up until the inner join of the 'votes' table. What I am trying to do is order the results of this query in accordance with the number of votes each content row has in another table called votes. I know I'm not too far off from what I need to do!
Thanks in advance!!
mysql_query("
SELECT content.id, content.type, content.title, content.url, users.username
FROM content
INNER JOIN users ON content.uploaderuid = users.id
INNER JOIN votes ON votes.id = content.id
WHERE (content.type = 'pic')
ORDER BY COUNT(votes.id) DESC");
Try doing:
SELECT content.id, content.type, content.title, content.url, users.username
FROM content
INNER JOIN users ON content.uploaderuid = users.id
INNER JOIN (
SELECT id,COUNT(*) as voteCount
FROM votes
GROUP BY id
) v ON v.id = content.id
WHERE (content.type = 'pic')
ORDER BY v.voteCount DESC
When you do an INNER JOIN with votes table directly, if you have multiple occurrences of the same id, you will get a lot more rows than before you did the JOIN.
If you are only interested in the number of votes for each id, by doing a JOIN with a subquery that calculates the count of votes for each id, will leave your previous query results as they were, and lets you use the voteCount to order by it.
You could try this:
SELECT c.id, c.type, c.title, c.url, u.username, COUNT(v.id) votes
FROM content c
INNER JOIN users u ON c.uploaderuid = u.id
INNER JOIN votes v ON v.id = c.id
WHERE c.type = 'pic'
GROUP BY c.id, c.type, c.title, c.url, u.username
ORDER BY votes DESC
Here is the SQL Fiddle that demonstrates the below query:
SELECT c.id, c.type, c.title, c.url, u.username, COUNT(v.id)
FROM content AS c
INNER JOIN users AS u ON c.uploaderuid = u.id
INNER JOIN votes AS v ON v.id = c.id
WHERE c.type = 'pic'
GROUP BY c.id, c.type, c.title, c.url, u.username
ORDER BY COUNT(v.id) DESC

MySQL query order the results in GROUP BY 3 Tables Count

I'm coding a listing system and I'm trying to get the posts ORDER by number of comments and votes FROM 2 tables.
Table1 : Lists => id, title, detail
Table2 : Votes => voteid, listid
Table3 : Comments => commentid, listid
WHERE MY Current query is
$q = mysql_query("SELECT * FROM zoo_leads
LEFT JOIN Votes ON Lists.id=Votes.listid
LEFT JOIN Comments ON Lists.id=Comments.listid
GROUP BY Lists.id ORDER BY Comments.listid DESC LIMIT 10
it is showing me results perfectly but ORDER BY is Lists.id Instead of number of votes and comments
Try:
SELECT *
FROM zoo_leads
LEFT JOIN votes
ON lists.id = votes.listid
LEFT JOIN comments
ON lists.id = comments.listid
GROUP BY lists.id
ORDER BY COUNT(votes.id) DESC,
COUNT(comments.id) DESC
LIMIT 10
That is because you have ORDER BY Comments.listid in your SQL statement.

mysql - subqueries and joins

I'm not quite sure if this is the right approach, this is my situation:
I'm currently trying to select 15 galleries and then left join it with the user table through the id but I also want to select one random picture from each gallery however from what I know you can't limit the left join (picture) to only pick up one random picture without doing a subquery.
Here is what I got so far but its not working as it should:
SELECT galleries.id, galleries.name, users.username, pictures.url
FROM galleries
LEFT JOIN users ON users.id = galleries.user_id
LEFT JOIN pictures ON (
SELECT pictures.url
FROM pictures
WHERE pictures.gallery_id = galleries.id
ORDER BY RAND()
LIMIT 1)
WHERE active = 1
ORDER BY RAND()
LIMIT 15
I also tried to do this with Active Record but I got stuck after doing two left joins, is it possible to do get a subquery in here:
$this->db->select('galleries.id, galleries.name, users.id as user_id, users.username');
$this->db->from('galleries');
$this->db->join('users', 'users.id = galleries.user_id','left');
$this->db->join('pictures','pictures.gallery_id = galleries.id AND','left');
$this->db->where('active',1);
I hope its not to messy but I'm really starting to get confusing by all the sql queries..
Edit:
Active Record with CodeIgniter
You could fetch a random picture in a subquery:
select
g.name, u.username,
(select url from pictures p where p.gallery_id = g.gallery_id
order by rand() limit 1) as url
from galleries g
left join users u on g.user_id = u.id
where g.active = 1
Based on your comment, you could select a picture for each gallery in a subquery. This is assuming the picture table has an ID column.
select
g.name, u.username, p.url, p.name
from (
select id, user_id, name,
(select id from pictures p
where p.gallery_id = g.gallery_id
order by rand() limit 1) as samplepictureid
from galleries
where g.active = 1
) g
left join users u on g.user_id = u.id
left join pictures p on p.id = g.samplepictureid
SELECT
g.id,
g.name,
u.username,
p.url
FROM
galleries g
INNER JOIN (SELECT DISTINCT
gallery_id,
(SELECT url FROM pictures ss WHERE ss.gallery_id = s.gallery_id
ORDER BY RAND() LIMIT 1) AS url
FROM
pictures s) p ON
g.id = p.gallery_id
LEFT OUTER JOIN users u ON
g.user_id = u.id
WHERE
g.active = 1
This query will go out and select a gallery, then it will find any gallery with a picture (if you want to return galleries without a picture, change INNER JOIN to LEFT OUTER JOIN, and you'll be fine). After that, it joins it up with users. Now, of course, this puppy is going to return every frigging gallery for however many users you have (hoorah!). You may want to limit the user in the WHERE clause (e.g.-WHERE u.id = 123). Otherwise, you're going to get more results than you'd expect. That, or do an INNER JOIN on it.

Categories