MySQL - ordering images by votes - mysql

I haven't used pure mySQL for a while now and looks like I forgot it. Sad story.
Now I have 2 tables - images and votes. Images have a unique id, among others. The votes table only has 2 fields - image id and user id.
I'm trying to get the list of images ordered by number of votes and I'm kinda stuck here. The closest I got is this:
SELECT i.uname AS author, i.title, i.time, i.description, i.id, i.extension, v.uid
FROM images as i
LEFT JOIN
votes as v ON i.id = v.iid
Which returns all images with the voter ID. If an image has multiple votes, than it's returned more than once.
Can someone please help me with this query ?

You need to use COUNT and GROUP BY:
SELECT i.uname AS author, i.title, i.time, i.description, i.id, i.extension, COUNT(v.uid)
FROM images as i
LEFT JOIN votes as v ON i.id = v.iid
GROUP BY i.uname, i.title, i.time, i.description, i.id, i.extension
ORDER BY Count(v.uid) DESC
As suggested, you don't have to GROUP BY all your output fields in MySQL -- just use your unique identifier, in this case, i.id.

Try:
SELECT i.uname AS author, i.title, i.time, i.description, i.id, i.extension, count(*) votes
FROM images as i
LEFT JOIN votes as v ON i.id = v.iid
group by i.id
order by 7
(from lowest to highest - add desc after order by 7 to change the sort order to be from highest to lowest.)

Related

How can I count number of entries in two other tables with MYSQL?

I have three tables.
Posts
Images
Votes
I want to be able to get all the data in the posts along with the the sum of the votes and the number of images associated with the post. I can get one or the other, but not both at once.
This code works for getting the score of a post
SELECT
posts.*,
COALESCE(SUM(votes.value), 0) as score
FROM posts
LEFT JOIN votes ON posts.post_id = votes.target_id
GROUP BY posts.post_id
and this code works for getting the number of images alongside posts
SELECT
posts.*,
COALESCE(COUNT(images.image_id), 0) as num_images
FROM posts
LEFT JOIN images ON posts.post_id = images.belongs_to_post
GROUP BY posts.post_id
but if I combine the two to get
SELECT
posts.*,
COALESCE(COUNT(images.image_id), 0) as num_images,
COALESCE(SUM(votes.value), 0) as score
FROM posts
LEFT JOIN votes ON posts.post_id = votes.target_id
LEFT JOIN images ON posts.post_id = images.belongs_to_post
GROUP BY posts.post_id
the score is multiplied by the number of images. How can I effectively stop this? Do I have to group by another column?
I'm using MySQL 5.7.31.
I would recommend correlated subqueries:
SELECT p.*,
(SELECT COUNT(*)
FROM images i
WHERE p.post_id = i.belongs_to_post
) as num_images,
(SELECT COALESCE(SUM(v.value), 0)
FROM votes v
WHERE p.post_id = v.target_id
) as score
FROM posts p;
With indexes on images(belongs_to_post) and votes(target_id, value), this is probably much faster than any approach that uses aggregation in the outer query.

Select top 10 posts ordered by quantity of votes

I have two tables, one for image records (posts) and the other one is for likes records. So i made an INNER JOIN from one table to another because i needed to select the image and the quantity of likes that particular image has. but i also need to order them by the quantity of likes so i can make a top 10 of most voted images on the site, so here is my query:
SELECT
COUNT(DISTINCT B.votes),
A.id_image,
A.image,
A.title
FROM likes_images AS B INNER JOIN images AS A ON A.id_image = B.id_image
GROUP BY A.title
ORDER BY COUNT(DISTINCT B.votes) ASC
LIMIT 10
It works, but it's only ordering the images by the title (Alphabetical). I want to order them from the most voted to the less voted.
Any ideas?
In most SQL implementations, GROUP BY criterion implies any ORDER BY clause to be ignored in favor of criterion.
So you might try this:
SELECT L.id_image, A.image, A.title,
* FROM (
SELECT COUNT(votes) AS likes, id_image
FROM likes_images
GROUP BY id_image
) AS L
JOIN images B ON B.id_image = L.id_image
ORDER BY L.likes DESC
LIMIT 10
Note that I set ORDER BY to DESC (since you want top10 I don't understand you chose ASC)!

How to sort by 2 columns when joining 2 tables?

I have 2 tables containing bookmarks and likes of images in my Pinterest-style application. I want to create a SQL Query where I want to select the most popular images, based on bookmarks and likes.
I want to prioritize bookmarks over likes, but I want an image with 100 likes be ranked higher than an image with 1 bookmark. So for example the result would look like:
Image with 100 likes
Image with 75 bookmarks
Image with 75 likes
Image with 30 likes
Image with 20 bookmarks
The tables I got look like the following:
images_bookmarks
id|id_image|id_user|id_board
images_likes
id|id_image|id_user
So I want to create a JOIN where I sort by the count grouped by id_image. I'm aware of how to create a join but I'm unsure of how to make the sorting behave as I am describing.
(Left) join your image table with your like/bookmark tables, then group and count likes and bookmarks for each row. Then order the result by the criteria you have given (100 likes is "higher" than 1 bookmark)
SELECT *, COUNT(b.id) * 100 + COUNT(l.id) AS rank
FROM images i
LEFT JOIN images_bookmarks b
ON i.id = b.image_id
LEFT JOIN images_likes l
ON i.id = l.image_id
GROUP BY i.id
ORDER BY COUNT(b.id) * 100 + COUNT(l.id)
If you want to sort by the sum of bookmarkss and likes, but have images with more bookmarks before images with likes, change the ORDER BY clause to COUNT(b.id) + COUNT(l.id), COUNT(b.id), COUNT(l.id)
To expand over rurouni88 answer, here is how you could do it to sort the bookmarks first when the number of occurences are the same :
SELECT id_image, occurences
FROM (
SELECT id_image, COUNT(id) AS occurences, 2 AS priority
FROM images_bookmarks
GROUP BY id_image
UNION
SELECT id_image, COUNT(id) AS occurences, 1 AS priority
FROM images_likes il
GROUP BY id_image
) AS favorites
ORDER BY occurences DESC, priority DESC
You can see it in action here : http://sqlfiddle.com/#!2/eb14f/7
Try a UNION of those tables :
SELECT id_image, NUM_OC (
SELECT id_image, COUNT(id) AS NUM_OC FROM images_bookmarks GROUP BY id_image
UNION
SELECT id_image, COUNT(id) AS NUM_OC FROM images_likes il GROUP BY id_image
)
ORDER BY NUM_OC
Only issue, which I will figure out, when my the caffeine kicks in, is how to prioritize bookmarks above likes

Combining count from one table and distinct from another

I've setup a contest where video submissions are sent in and then people vote on them. Submissions are sent into a table submissions with this structure:
submission_id, title, videoname
The voting table votes structure is:
video_id, voter_id
The video_id correlates to the submission_id in the submissions table.
I want to get the number of votes for each video like so:
select video_id, count(1) from votes group by submission_id
But I also want to display the title for each video so the result would be:
video_id, count, title
I am a sql noob so please forgive me if this is a simple statement. I have done some research and was not able to come up with something on my own and would appreciate any help.
I would recommend doing a LEFT JOIN instead of an INNER JOIN... and COUNT(v.video_id) instead of COUNT(*). This way you will still return submissions that currently have 0 votes:
select
s.submission_id as video_id,
count(v.video_id) as vote_count,
s.title
from
submissions s
left join votes v on v.video_id = s.submission_id
group by
s.submission_id,
s.title
select s.submission_id, s.title, s.videoname, c.cnt
from
submissions s,
(select video_id, count(1) as cnt from votes group by video_id) c
where
s.submission_id = c.video_id
This will return every video from you submissions table and show the number of votes in the votes table. If there have not been any votes it will show up in the results with a NULL as the Votes column
SELECT video_id, title, COUNT(voter_id) Votes
FROM submissions s
LEFT OUTER JOIN votes v ON s.submission_id = v.video_id
GROUP BY video_id, title,
You have to make a join for retrieve the votes and the video title, between the two tables like this :
SELECT submissions.submission_id
, COUNT(1)
, submissions.videoname
FROM submissions LEFT OUTER JOIN votes
ON votes.video_id = submissions.submission_id
GROUP BY submissions.submission_id, submissions.videoname

How can I use MySQL to COUNT with a LEFT JOIN?

How can I use MySQL to count with a LEFT JOIN?
I have two tables, sometimes the Ratings table does not have ratings for a photo so I thought LEFT JOIN is needed but I also have a COUNT statement..
Photos
id name src
1 car bmw.jpg
2 bike baracuda.jpg
Loves (picid is foreign key with photos id)
id picid ratersip
4 1 81.0.0.0
6 1 84.0.0.0
7 2 81.0.0.0
Here the user can only rate one image with their IP.
I want to combine the two tables in order of the highest rating. New table
Combined
id name src picid
1 car bmw.jpg 1
2 bike baracuda.jpg 2
(bmw is highest rated)
My MySQL code:
SELECT * FROM photos
LEFT JOIN ON photos.id=loves.picid
ORDER BY COUNT (picid);
My PHP Code: (UPDATED AND ADDED - Working Example...)
$sqlcount = "SELECT p . *
FROM `pics` p
LEFT JOIN (
SELECT `loves`.`picid`, count( 1 ) AS piccount
FROM `loves`
GROUP BY `loves`.`picid`
)l ON p.`id` = l.`picid`
ORDER BY coalesce( l.piccount, 0 ) DESC";
$pics = mysql_query($sqlcount);
MySQL allows you to group by just the id column:
select
p.*
from
photos p
left join loves l on
p.id = l.picid
group by
p.id
order by
count(l.picid)
That being said, I know MySQL is really bad at group by, so you can try putting the loves count in a subquery in your join to optimize it:
select
p.*
from
photos p
left join (select picid, count(1) as piccount from loves group by picid) l on
p.id = l.picid
order by
coalesce(l.piccount, 0)
I don't have a MySQL instance to test out which is faster, so test them both.
You need to use subqueries:
SELECT id, name, src FROM (
SELECT photos.id, photos.name, photos.src, count(*) as the_count
FROM photos
LEFT JOIN ON photos.id=loves.picid
GROUP BY photos.id
) t
ORDER BY the_count
select
p.ID,
p.name,
p.src,
PreSum.LoveCount
from
Photos p
left join ( select L.picid,
count(*) as LoveCount
from
Loves L
group by
L.PicID ) PreSum
on p.id = PreSum.PicID
order by
PreSum.LoveCount DESC
I believe you just need to join the data and do a count(*) in your select. Make sure you specify which table you want to use for ambigous columns. Also, don't forget to use a group by function when you do a count(*). Here is an example query that I run on MS SQL.
Select CmsAgentInfo.LOGID, LOGNAME, hCmsAgent.SOURCEID, count(*) as COUNT from hCmsAgent
LEFT JOIN CmsAgentInfo on hCmsAgent.logid=CmsAgentInfo.logid
where SPLIT = '990'
GROUP BY CmsAgentInfo.LOGID, LOGNAME, hCmsAgent.SOURCEID
The example results form this will be something like this.
77615 SMITH, JANE 1 36
29422 DOE, JOHN 1 648
Hope that helps. Good Luck.