I'm trying to rank with the left outer join
My sql is :
SET #rank=0;
SELECT #rank:=#rank+1 AS rank, h.name, COUNT(v.hId) AS votes
FROM users h LEFT OUTER JOIN users_votes v ON h.id = v.hId GROUP BY h.id
ORDER BY rank ASC
;
The right thing would be to return like this
rank | name | votes
1 Luck 4
2 Marc 3
3 Santos 2
4 Matheus 0
But it's returning the wrong way:
rank | name | votes
1 Santos 2
2 Marc 3
3 Luck 4
4 Matheus 0
You are ordering in ASC way, change it to DESC. Like this:
SET #rank=0;
SELECT #rank:=#rank+1 AS rank, h.name, COUNT(v.hId) AS votes
FROM users h LEFT OUTER JOIN users_votes v ON h.id = v.hId GROUP BY h.id
ORDER BY rank DESC
;
In MySQL 8+, you should use row_number():
SELECT ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) as rank,
h.name, COUNT(*) AS votes
FROM users h LEFT OUTER JOIN
users_votes v
ON h.id = v.hId
GROUP BY h.id
ORDER BY rank ASC;
Variables are deprecated in 8+.
In earlier version, you can use variables, but they tend not to respect ORDER BY or GROUP BY. So, with those constructs, you need a subquery:
SELECT (#rn := #rn + 1) as rank, hv.*
FROM (SELECT h.name, COUNT(*) AS votes
FROM users h LEFT OUTER JOIN
users_votes v
ON h.id = v.hId
GROUP BY h.id
ORDER BY rank ASC
) hv CROSS JOIN
(SELECT #rn := 0) params;
Doesn't works, the rank number is wrong. I want to sort by votes and rank the most voted
Related
This question already has answers here:
Rank function in MySQL
(13 answers)
Closed 4 years ago.
SELECT u.user_id, u.user_uid, s.ostats, s.attack, s.defense
FROM stats s JOIN
users u
ON s.id = u.user_id
ORDER BY s.ostats DESC;
So in above data, "ostats"(overall) is just a sum of attack+defense and by using this query I could display users in descending order of their "ostats" values..
But how do I assign and display rank of each user, like the one with most "ostats" valued user as Rank 1 and the second highest "ostats" valued user as Rank 2 and so on..?
What about using a variable to keep track of the row number?
SET #rank = 0;
SELECT
u.user_id,
u.user_uid,
s.ostats,
s.attack,
s.defense,
(#rank:=#rank + 1) AS rank
FROM stats s
JOIN users u on s.id = u.user_id
ORDER BY s.ostats DESC;
You can assign a row number using variables:
SELECT u.user_id,u.user_uid, s.ostats, s.attack, s.defense,
s.ranking
FROM (SELECT s.*, (#rn := #rn + 1) as ranking
FROM (SELECT s.* FROM stats s ORDER BY s.ostats DESC) s CROSS JOIN
(SELECT #rn := 0) params
) s JOIN
users u
ON s.id = u.user_id
ORDER BY s.ostats DESC;
In the event of ties, this will give different users different rankings. If that is an issue, you can use this modified form:
SELECT u.user_id,u.user_uid, s.ostats, s.attack, s.defense,
s.ranking
FROM (SELECT s.*,
(#rn := if(#o = ostats, #rn,
if(#o := ostats, #rn + 1, #rn + 1)
)
) as ranking
FROM (SELECT s.* FROM stats s ORDER BY s.ostats DESC) s CROSS JOIN
(SELECT #rn := 0, #o := -1) params
) s JOIN
users u
ON s.id = u.user_id
ORDER BY s.ostats DESC;
Of course, in MySQL 8.0, you can use row_number(), rank() or dense_rank() for this purpose.
I'm wondering about these queries and I got a work that want to list all users in table user and count for their post photo and video. and can choose to view in sort by these count limit by ASC or DESC.
I've tried them both but see that sub-query is fast than join. i want to know the different between these queries. Why sometimes join is slower that a sub-query. is join best for only two tables? Is this both best for my work? or you can suggest another better solution.
SUB-QUERY
select
user.*,
(select count(*) from post where post.userid = user.id) postCount,
(select count(*) from photo where photo.userid = user.id) photoCount,
(select count(*) from video where video.userid = user.id) videoCount
from user order by postCOunt desc limit $starrow 20
JOIN
SELECT u.id,
COUNT(DISTINCT p.id) AS postCount,
COUNT(DISTINCT ph.id) AS photoCount,
COUNT(DISTINCT v.id) AS videoCount
FROM user u
LEFT JOIN post p
ON p.userid = u.id
LEFT JOIN photo ph
ON ph.userid = u.id
LEFT JOIN video v
ON v.userid = u.id
GROUP BY u.id
ORDER BY postCount LIMIT $startrow 20
Example in HTML page that order by postCount DESC and have paging.
userid postCount photoCount videCount
1 34 5 4
2 30 12 2
3 21 5 6
4 15 8 4
5 12 15 9
6 8 3 10
.. .. .. ..
You can try it this way with JOIN
SELECT u.id, postCount, photoCount, videoCount
FROM user u LEFT JOIN
(
SELECT userid, COUNT(*) postCount
FROM post
GROUP BY userid
) p ON p.userid = u.id LEFT JOIN
(
SELECT userid, COUNT(*) photoCount
FROM photo
GROUP BY userid
) ph ON ph.userid = u.id LEFT JOIN
(
SELECT userid, COUNT(*) videoCount
FROM video
GROUP BY userid
) v ON v.userid = u.id
ORDER BY postCount
LIMIT $startrow, 20
I need to place set #rank:=0; in this query, but where can i place it?
SELECT #rank:=#rank+1 AS rank, p.* FROM points p
inner join distributor d
on p.distributor_id=d.id_distributor
where p.month='$prev_month'
and d.group='$dist_group'
ORDER BY p.tot_point DESC
i have to use mysql_query("set #rank:=0;"); before the main query, it's works. but in another server it won't work.
any ideas ?
SELECT #rank:=#rank+1 AS rank, p.* FROM points p, (SELECT #rank:=0) AS dummy
inner join distributor d
on p.distributor_id=d.id_distributor
where p.month='$prev_month'
and d.group='$dist_group'
ORDER BY p.tot_point DESC
Basicly just add , (SELECT #rank:=0) AS dummy after FROM points p.
My prefered layout on this query:
SELECT #rank := #rank + 1 AS rank, p.*
FROM
points AS p
CROSS JOIN
(SELECT #rank:=0) AS dummy
INNER JOIN
distributor AS d
ON p.distributor_id = d.id_distributor
WHERE p.month = '$prev_month'
AND d.group='$dist_group'
ORDER BY p.tot_point DESC ;
This is my first attempt at a JOIN MySQL statement...
I have 2 tables..games and games_ratings
both tables have an id column. the id represents the id of the game. and i only want to get the average of the ints in the rating column where the id in games_ratings is equal to the id from the games table.
SELECT a.id, a.name, AVG(b.rating) AS average FROM games a LEFT JOIN games_ratings b GROUP BY a.id ORDER BY average DESC LIMIT 50;
any ideas?
Try this:
SELECT a.id, a.name, AVG(b.rating) AS average
FROM games a
LEFT JOIN games_ratings b
ON a.id = b.id # <-- You need this line I believe
GROUP BY a.id
ORDER BY average DESC LIMIT 50;
Edit: This is a bit hard without your complete schema, but you can try something like this.
SELECT a.id, a.name, AVG(b.rating) AS average, COUNT( b.id) as votes
FROM games a
LEFT JOIN games_ratings b
ON a.id = b.id
GROUP BY a.id
ORDER BY votes DESC, average DESC LIMIT 50; # <-- You may need to modify this line
Don't forget the WHERE clause he asked for:
where the id in games_ratings is equal to the id from the games table
> SELECT a.id, a.name, AVG(b.rating) AS average
> FROM games a
> LEFT JOIN games_ratings b
> ON a.id = b.id # <-- You need this line I believe
> **WHERE a.id = b.id**
> GROUP BY a.id
> ORDER BY average DESC LIMIT 50;
this is my query
SELECT a.id,
a.venue_id,
a.user_id,
m1.profilenam AS user_profilename,
m1.photo_thumb AS user_photo_thumb,
m2.profilenam AS venue_profilename,
m2.photo_thumb AS venue_photo_thumb
FROM announce_arrival AS a
INNER JOIN members AS m1
ON a.user_id = m1.mem_id
INNER JOIN members AS m2
ON a.venue_id = m2.mem_id
GROUP BY a.venue_id, a.user_id
LIMIT 0,10
ORDER BY date DESC,
time DESC
How can i use count(*) on this query,i use like this
SELECT DISTINCT COUNT(*)
FROM announce_arrival AS a
INNER JOIN members as m1 ON (a.user_id = m1.mem_id)
INNER JOIN members as m2 ON (a.venue_id= m2.mem_id)
GROUP BY a.venue_id, a.user_id LIMIT 0,10 ORDER BY date DESC,time DESC;
but its showing
COUNT(*)
7
3
1
i want total count .
You can wrap your query into select count(*), like this:
SELECT COUNT(*) FROM
(SELECT a.id,a.venue_id, a.user_id, m1.profilenam as
user_profilename,m1.photo_thumb AS user_photo_thumb,m2.profilenam AS
venue_profilename, m2.photo_thumb AS venue_photo_thumb FROM announce_arrival
AS a INNER JOIN members as m1 ON (a.user_id = m1.mem_id) INNER JOIN members
as m2 ON (a.venue_id= m2.mem_id) GROUP BY a.venue_id, a.user_id)
You can wrap your query in another SELECT:
SELECT COUNT(*) AS total FROM (
SELECT DISTINCT COUNT(*)
FROM announce_arrival AS a
INNER JOIN members as m1 ON (a.user_id = m1.mem_id)
INNER JOIN members as m2 ON (a.venue_id= m2.mem_id)
GROUP BY a.venue_id, a.user_id LIMIT 0,10 ORDER BY date DESC,time DESC) AS t
or if you want sum of all DISTINCT COUNT(*) try:
SELECT SUM(cnt) AS total FROM (
SELECT DISTINCT COUNT(*) AS cnt
FROM announce_arrival AS a
INNER JOIN members as m1 ON (a.user_id = m1.mem_id)
INNER JOIN members as m2 ON (a.venue_id= m2.mem_id)
GROUP BY a.venue_id, a.user_id LIMIT 0,10 ORDER BY date DESC,time DESC) AS t
From docs about found_rows():
To obtain this row count, include a
SQL_CALC_FOUND_ROWS option in the
SELECT statement, and then invoke
FOUND_ROWS() afterward:
mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name WHERE id > 100 LIMIT 10;
mysql> SELECT FOUND_ROWS();
The second SELECT returns a number
indicating how many rows the first
SELECT would have returned had it been
written without the LIMIT clause.
I.e., add SQL_CALC_FOUND_ROWS after SELECT in your first query and replace second query with SELECT FOUND_ROWS().
Get rid of GROUP BY, LIMIT and ORDER. They are useless and don't make sense (especially LIMIT) if you need a total count. DISTINCT doesn't make sense either.
SELECT COUNT(*)
FROM announce_arrival AS a
INNER JOIN members as m1 ON (a.user_id = m1.mem_id)
INNER JOIN members as m2 ON (a.venue_id= m2.mem_id)
Try this
SELECT COUNT(a.user_id)
FROM announce_arrival AS a
INNER JOIN members as m1 ON (a.user_id = m1.mem_id)
INNER JOIN members as m2 ON (a.venue_id= m2.mem_id)
GROUP BY a.user_id LIMIT 0,10;
If you are using count no need to give order by