I have 3 tables as below in MySQL:
user: id username ...
post: id user_id title ....
user_post_like: id post_id user_id like_date (every like in a separate row)
Every user can send and like posts.
Now I wanna get the specified user daily rank according to the number of likes(from user_post_like table) that the user's posts got in the last 24 hours using an SQL command.
Maybe using count command for counting the users that have more likes than the specified user.
select u.username, count(l.id) as likes
from user_post_like l
join `user` u on u.od = l.user_id
where now() - interval 24 hour >= l.like_date
group by u.id, u.username
order by count(l.id) desc
and if you need a rank number too, you can do
select u.username, count(l.id) as likes, #rank := #rank + 1 as rank
from user_post_like l
join `user` u on u.od = l.user_id
cross join (select #rank := 0) r
where now() - interval 24 hour >= l.like_date
group by u.id, u.username
order by count(l.id) desc
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 have 2 tables;
banner_views (id, b_id, b_date)- this record a banner view every time it gets displayed
banners_dynamic (id, status, static_iname, static_keywords, static_url, static_alt, static_type, static_image, b_views, b_clicks) - stores the banner data
I would like to select 3 banners_dynamic results which have had the least views in the last 7 days.
I did put somethign together (see below) but I realised it was grabbing the total views for all banner rather than uniquely by id.
SELECT *,
(SELECT COUNT(*) FROM banner_views v WHERE v.b_date >= DATE(NOW()) - INTERVAL 7 DAY) as post_count
FROM banners_dynamic b
WHERE static_keywords LIKE '%test%' AND b.status='1' AND b.static_type='1'
ORDER BY post_count ASC LIMIT 3
Can anyone point me in the correct direction?
You must join both banners_dynamic table and your subquery with corresponding banner IDs:
SELECT
b.*, p.b_count
FROM
banners_dynamic b
INNER JOIN (
SELECT
b_id,
COUNT(*) AS b_count
FROM
banner_views v
WHERE
v.b_date >= DATE(NOW() - INTERVAL 7 DAY)
GROUP BY
b_id
) p on p.b_id = b.id
WHERE
b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
ORDER BY
p.b_count ASC
LIMIT 3
UPDATE: You can do it even without subquery:
SELECT
b.*, COUNT(v.b_id) AS b_count
FROM
banners_dynamic b
INNER JOIN banner_views v ON v.b_id = b.id
WHERE
v.b_date >= DATE_ADD(NOW(), INTERVAL - 7 DAY)
AND b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
GROUP BY
v.b_id
ORDER BY
b_count ASC
LIMIT 3;
If you want to include banners without any views (count=0) then you must do a LEFT JOIN:
SELECT
b.*, COUNT(v.b_id) AS b_count
FROM
banners_dynamic b
LEFT JOIN banner_views v ON v.b_id = b.id
AND v.b_date >= DATE_ADD(NOW(), INTERVAL - 7 DAY)
WHERE
b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
GROUP BY
v.b_id
ORDER BY
b_count ASC
LIMIT 3;
Let's say I have two tables like the following:
user_id
1
2
3
post_id user_id
1 2
2 3
3 2
The first table has all of the user information and the second table is a list of posts from users.
With these table, I want to make a ranking of who post the most posts. To do this, I can use the following sql
select user.user_id from user
left join post on user.user_id=post.user_id
order by count(post.post_id)
which will give me
user_id
2
3
1
, but what if I only want a single user's rank? In other words, I want to write a sql statement that will return what place the user is in given the user_id. For example, I want 1 as output if I have user_id of 2, 2 as the output if I have user_id 3, and 3 as the output if I have user_id 1.
Is this possible, or would I have to select the entire table and do a while loop in php until I hit the user and count the rows above?
Unfortunately, for a single user's rank, you pretty much have to calculate the rank of everyone and then pull out the single user. So, the ranking for all users is:
select u.user_id, count(p.post_id), (#rn := #rn + 1) as ranking
from user u left join
post p
on u.user_id = p.user_id cross join
(select #rn := 0) params
group by u.user_id
order by count(p.post_id) desc;
And for one user, use a subquery:
select *
from (select u.user_id, count(p.post_id), (#rn := #rn + 1) as ranking
from user u left join
post p
on u.user_id = p.user_id cross join
(select #rn := 0) params
order by count(p.post_id) desc
) u
where u.user_id = $USERID;
You can use user-defined variables for this:
select rnk
from (
select user.user_id, #rnk:#rnk+1 rnk
from user
left join post on user.user_id=post.user_id
cross join (select #rnk:=0) t
group by user.user_id
order by count(post.post_id) desc
) t
where user_id = ?
BTW -- I believe your query was missing a group by clause. Added above.
I have a query that gets me a users rank in a table of scores.
SELECT
*
FROM
(SELECT
*, #rank:=#rank + 1 rank
FROM
(SELECT
user_id, SUM(round_total) TotalPoints
FROM
sx14sp_mem_picks
GROUP BY user_id) s, (SELECT #rank:=0) init
ORDER BY TotalPoints DESC) r
WHERE
user_id = 22234
There is a problem with ties. I have a table field "pick_date" that i would like to use to break ties with. The user who made his picks first beats the tie.
Any ideas?
If sx14sp_mem_picks.pickdate is the field to break ties then in the order by sx14sp_mem_picks subquery, add
min( pickdate) asc
This will put the earliest pickdate first - you have to use MIN() bc you need to use an aggregate function given the use of "group by".
You need to order by the pick date in addition to the total points. However, you are talking about multiple rows per user. So, let's take the last pick date:
SELECT *
FROM (SELECT *, (#rank:=#rank + 1) as rank
FROM (SELECT user_id, SUM(round_total) as TotalPoints, max(pick_date) as max_pick_date
FROM sx14sp_mem_picks
GROUP BY user_id
) s CROSS JOIN
(SELECT #rank := 0) init
ORDER BY TotalPoints DESC, max_pick_date asc
) r
WHERE user_id = 22234;
I have a table full of entries with DATETIME time stamps, and an ID field. I want to make a MySQL query (in my PHP script) that selects from another table with the matching ID. I want to make some kind of join that will sort by the number of entries in the first table with a timestamp more recent than 24 hours. So basically, if there are 30 entries in the first table with a timestamp of less than 24 hours with the ID "334" then I want to select the row from the second table with the ID of 334. And that should come before an entry with the ID "234" that only has 20 entries within the last 24 hours.
I hope this is clear... I'm really stumped on how to do this, so thanks for any help. :D
Use:
SELECT a.*,
x.num
FROM TABLE_A a
JOIN (SELECT t.id,
COUNT(*) AS num
FROM TABLE_B t
WHERE t.timestamp BETWEEN DATE_SUB(NOW, INTERVAL 1 DAY)
AND NOW()
GROUP BY t.id) x ON x.id = a.id
ORDER BY x.num DESC
Try:
Select b.ColA, b.ColB, b.ColC,-- etc.
Count(*) count
From TableB b
Join TableA a
On a.Id = b.Id
And a.TimeStamp > getDate() - 1
Group By b.ColA, b.ColB, b.ColC -- etc.
Order By Count(*) Desc
If you also want to see the rows from TableB that have no timestamps in the past 24 hours then use an outer join:
Select b.ColA, b.ColB, b.ColC,-- etc.
Count(*) count
From TableB b
Left Join TableA a
On a.Id = b.Id
And a.TimeStamp > getDate() - 1
Group By b.ColA, b.ColB, b.ColC -- etc.
Order By Count(*) Desc