Mysql order by left join date - mysql

I have two tables, users and sessions. Each user can have multiple sessions. I want to get user name and the date of his most recent session. But I need to do this in such a way as to be able to return the array sorted by date of last session. Also, some of the users may not have sessions so the left join will return nothing for date.
SELECT u.name, max(s.sdate) FROM users u
LEFT JOIN sessions s ON s.uid=u.id
ORDER BY s.sdate
LIMIT 25,25
Clearly this won't work but I'd like something simple. Something similar? Note that I also need to specify which set of rows to return because of pagination. This would be page 2. I did see similar posts but they were overly complex for my use.
I have kept this simplified to keep it easy to understand.

I believe in your case u need only to group your results by user.
try
SELECT u.name, max(s.sdate) AS dt FROM users u
LEFT JOIN sessions s ON s.uid=u.id
GROUP BY u.id
ORDER BY dt
LIMIT 25,25

Related

how can I return multiple row counts

I have three entities, User, Rule, and Activity
with the following relationship, One rule has many activities (bidirectional)
Many users have many activities(bidirectional), the server is with spring using spring jpa
I want to show how many Activities has one user started but not finished from every rule, with SQL this query would return that from one rule
SELECT COUNT(*) FROM user_activity WHERE user_id=userId AND score<10 AND
activity_id IN (SELECT id FROM activity WHERE rule_id=ruleId);
I could do that with JPQL, but how could I return that count from every rule?
so I could have from every rule, how many activities has that User
if someone needs it I can provide java model code too.
tables are User, Activity, Rule and User_Activity
I think this query is probably what you want. It finds all the activities associated with a given rule, then joins the users participating in that activity who have not finished it (I presume that's what score<10 indicates?)
SELECT r.id, u.id, COUNT(a.id)
FROM rule r
JOIN activity a ON a.rule_id = r.id
JOIN user_activity ua ON ua.activity_id = a.id AND ua.score < 10
JOIN user u ON u.id = ua.user_id
GROUP BY r.id, u.id
Obviously you can expand the SELECT to include things like the rule description and the user name etc.
I couldn't see any indication of what "activity complete" means so I've presumed it's that the score is less than 10. If that's not the case, you would need to change the join to user_activity appropriately.

use COUNT(*) values from one table to another

Suppose I have two tables, users and posts. Posts has the following fields, userid, postid, etc and userid can appear multiple times as one user can write multiple posts....I'm just trying sort the users table based off the # of occurrences per userid in the posts table. I can get the # of occurrences per user using this
SELECT userid, COUNT(*)
FROM posts
GROUP BY userid;
I would like to use the values under COUNT(*) column, maybe add it to my other table because then I can simply to something like this
SELECT * FROM users
ORDER BY newcolumn ASC;
but I'm having trouble doing that. Or can I do it without having to add an extra column? Hints please. Thanks
Left join is the key here!
SELECT users.userid,count(posts.userid) AS total_count
FROM users
LEFT JOIN posts on posts.userid = users.userid
GROUP BY users.userid
ORDER BY total_count DESC;
We are taking the left join on two tables with same user_id and we are counting the total number of posts per user using group by. Finally sort by count and show results.
try an left join:
select users.userid, [user fields],count(postid) as posts_count
from users
left join posts on posts.userid = users.userid
group by users.userid,[user fields]
order by posts_count desc.
You want to select users (FROM users) but you want to sort based on criteria in another table (COUNT(*) FROM posts) -- therefore you need to use a JOIN
Off-hand I can't seem to recall if "JOIN" or "RIGHT JOIN" or "FULL JOIN" is what you need if you wanted to get a cartesian product of the tables then group and aggregate on a single field, but I can avoid the need to remember with a subquery (hopefully someone will soon post a smaller and smarter answer):
SELECT users.* FROM users
JOIN (
SELECT userid, COUNT(*) as count
FROM posts
GROUP BY userid
) as subquery ON users.id = subquery.userid
ORDER BY subquery.count
Note: I haven't tested this query, but it looks good to me. Again: hopefully someone will post a better answer soon as I'm not doing my due dilligence, but you definitely need a JOIN :)
You could add a post_count column to the users table, but you would also have to update that count column every time a user creates a new post and you would have to build that logic into your application.
Otherwise, it looks like the answer from FallAndLearn will get you what you need.

Selecting data from multiple tables, where a specific table does not contain any identifiable columns?

I have a dilemma.
Let's assume(for simplicity's sake) I have four tables, with different numbers of columns and rows, they are: users, mail, events and service.
When I receive a request, I have an ID that links on three of those tables, but with different columns it matches to.
Let's say, users matches on user_id, mail matches on user_ref and events matches on user_ref as well.
That would've been a fine query for me to write up, even with single, multiple or even all IDs.
The problem arrives on the next step I have to take, and that's the *service table.
The service table doesn't conform to the same standards of the others, thus it does not have an user_id, or user_ref that can be pulled.
What it has instead, is a *mail_ref* column, and it has the potential to contain duplicates.
My current method is trying to use an IN() method, but it only works for selecting a single user/row.
Here's my current query:
SELECT
u.Name as Name,
COUNT(m.user_ref) AS Mail_total,
e.mail_id,
COUNT(e.user_ref) AS Event_total,
COUNT(s.mail_ref) AS service_total
FROM
users u
LEFT JOIN
mail m ON m.user_ref = u.user_id
LEFT JOIN
service s ON s.mail_ref IN(e.mail_id)
LEFT JOIN
events e ON e.user_ref = u.user_id
WHERE u.user_id IN(my,list,of,ids)
GROUP BY s.mail_ref
The problem I have with it currently, is that although it's selecting the correct data, it's not selecting unique data for every id I specify.
It works marginally fine when given a single id, but as mentioned above, not when it has to retrieve multiple rows.
If anyone could help me out it would be much appreciated.
Do a subquery in the left join for service. Instead of:
LEFT JOIN
service s ON s.mail_ref IN(e.mail_id)
Try
LEFT JOIN
(select TOP 1 mail_ref from server) as S on s.mail_ref = e.mail_id
See if that works.
SELECT
u.Name as Name,
(select count(*) from mail m where m.user_ref = u.user_id) AS Mail_total,
e.mail_id,
(select count(*) from events e where e.user_ref = u.user_id) AS Event_total,
(select count(*) from
events e
inner join services s on s.mail_ref = e.mail_id
where
e.user_ref = u.user_id) as service_total
FROM
users u
WHERE u.user_id IN(my,list,of,ids)

Making a user profile activity feed

I need to build an activity feed to go on each users profile page showing what they have been doing on the site.
There is three tables: comments, ratings, users
I want the feed to include the comments and ratings that the user has posted.
in the comments and ratings table it stores the user id of the user who posted it, not the username, so in for each item in the news feed it needs to select from the users table where the user id is the same to retrieve the username.
All the entries in the feed should be ordered by date.
Here is what ive got even though i know it is not correct because it is trying to match both with the same row in the users table.
SELECT comments.date, comments.url AS comment_url, comments.user_id, ratings.date, ratings.url AS rating_url, ratings.user_id, users.id, users.username
FROM comments, ratings, users
WHERE comments.user_id=%s
AND comments.user_id=users.id
AND ratings.user_id=%s
AND ratings.user_id=users.id
ORDER BY ratings.date, comments.date DESC
JOIN. It seems you know that, but here's how:
SELECT * FROM comments LEFT JOIN users ON comments.user_id = users.id
Thus, as far as I can tell, you're trying to order two separate things at the same time. The closest I think I can come up with would be something like:
(SELECT comments.date AS date, users.username AS name, comments.url AS url CONCAT('Something happened: ',comments.url) AS text
FROM comments LEFT JOIN users ON comments.user_id = users.id
WHERE users.id = %s)
UNION
(SELECT ratings.date AS date, users.username AS name, ratings.url AS url CONCAT('Something happened: ',ratings.url) AS text
FROM comments LEFT JOIN users ON comments.user_id = users.id
WHERE users.id = %s)
ORDER BY date DESC LIMIT 0,10
Note that the columns of both parts of the union match up. I'm pretty sure that that is required for something like this to work. That's why I have that CONCAT statement, which lets you build a string that works differently between ratings and comments.

mysql count only for distinct values in joined query

WOW! That's a weird title, but I'm happy you're looking, cause I couldn't find another way to say it.
I have a table of people and a table of links to photos and videos.
I join the people to the media, and of course a person can have more than one piece of media.
I am attempting to grab the first 30 people and all of their media in one query, but when I say LIMIT 0,30. Of course I'll only get the first 30 media files, which could be 10 people.
Before I make the query, I don't know how many media files each person is going to have. Is there a way I can say LIMIT DISTINCT(uid 0,30)????
or something like that?
Can you use subqueries in your version of MySQL?
select *
from media m
inner join
( select uid
from users_tbl
limit 0,30) map
on map.uid = m.uid
inner join users_tbl u
on u.uid = m.uid
FWIW, here's another query that should return the same result:
SELECT *
FROM media m INNER JOIN users_tbl u USING (uid)
WHERE u.uid IN (SELECT uid FROM users_tbl ORDER BY uid LIMIT 0,30);
Note that when you use LIMIT, you should always use an ORDER BY. Otherwise there is no guarantee which thirty users you'll get.