Order by last row of SELECT subquery - mysql

I have 2 tables: "posts" - for posts that a user post, and all the information it includes. and "messages" - which includes messages for each post.
The tables look like this:
posts:
--------------------------------------------------
| post_id | post_creator_id | post_information |
--------------------------------------------------
messages:
----------------------------------------------------------
| message_id | post_id | user_id | message_text |
----------------------------------------------------------
I want to display a user (user_id) a list of all chats he is engaged in, and order it by the last message sent in any chat.
So there are a few things to be done: first I need to group by the post_id in messages table (so there aren't duplicates) and order by message_id DESC, I tried subquery and joins but neither worked. Here is an example of my subquery attempt:
SELECT posts.post_information FROM posts WHERE posts.post_id in (SELECT
messages.post_id FROM messages ORDER BY message_id DESC)
Can't figure out how make the query display only distinct rows (without duplication of post_id) And whether join is a better option?

Simple change in your query, we can use INNER JOIN with messages table and ORDER BY with message_id instead of using suqbyery (It seems that you want to order output data by message_id in descending order.
SELECT posts.post_information
FROM posts
INNER JOIN (SELECT post_id, max(message_id) mid
FROM messages
GROUP BY post_id) mes ON mes.post_id = posts.post_id
ORDER BY mes.mid DESC

Assuming you have multiple messages per post, you need to use distinct not to include duplicates. Than just join tables and add order by
SELECT distinct posts.post_information
FROM posts, messages where messages.post_id = posts.post_id
ORDER BY messages.message_id DESC

Related

MySQL Frequency of frequency report

Given many users have many posts
I have a table of posts that has a foreign key user_id
I want to generate a report that shows the frequency of users against frequency of posts
e.g.
3 users wrote 2 posts each
2 users wrote 1 post each
1 user wrote 4 posts
Number of users | Number of posts
--------------- | ------------------
1 | 4
2 | 1
3 | 2
My attempt:
SELECT inner_table.frequency_posts,
Count(*) AS frequency_users
FROM posts
INNER JOIN (SELECT user_id,
Count(*) AS frequency_posts
FROM posts
GROUP BY user_id) AS inner_table
ON posts.user_id = inner_table.user_id
GROUP BY inner_table.frequency_posts
I think frequency_posts is working but counting frequency_users isn't giving the right values - when I look at the inner select on it's own and manually add up the posts I don't get the same values
You have to use Group by twice:
SELECT
COUNT(*) AS NumberOfUsers,
foo.NumberOfPosts
FROM
(SELECT
p.UserId AS UserId,
COUNT(*) AS NumberOfPosts
FROM
posts AS p
GROUP BY UserId) as foo
GROUP BY foo.NumberOfPosts

MySQL joining table's maximum row contents

For a simple forum I would like to list the threads in order from most recent post. That I have completed with no issue with the following query:
SELECT t.thread_id, t.title, MAX(m.post_id) as latest_reply
FROM forum_thread as t
LEFT JOIN forum_post as n ON(latest_reply = m.thread_id)
WHERE t.forum_id=:forum_id AND t.sticky=0
GROUP BY t.thread_id
ORDER BY latest_reply DESC
LIMIT :limit_bottom, :limit_top
This works fine, until I want more details from the maximum post row. If I select more info from the post table, the results are random
I would like to also know, the post title, and then the username who posted.
The thread table [forum_thread] looks like the following:
thread_id | forum_id | title | sticky | post_count | view_count | closed
The post table [forum_post] looks like the following:
post_id | user_id | thread_id | timestamp | title | post_body_cache
And the user table [user] looks like the following:
id | username
I need to join the maximum post row to get the title, and than join the user table to get the username. What is the most efficient way of doing this? Everything I have tried has returned a fatal error.
Desired results would be:
[forum_thread] thread_id | [forum_thread] title | [forum_post] MAX post_id | [forum_post] title | [user] username
To get the entire row from the outer table, you have to move the Max to a subquery and use it in the joining criteria:
SELECT t.thread_id, t.title, p.author, p.post_date, p.whatever
FROM forum_thread as t
LEFT JOIN forum_post as p
ON p.thread_id = m.thread_id
and p.post_date =(
select Max( p.post_date )
from forum_post
where thread_id = p.thread_id )
WHERE t.forum_id = :forum_id
AND t.sticky= 0

Joining two tables based upon the highest COUNT(*) from table2?

Okay, so I have two tables that I need to link together with a JOIN query. There is a table called likes and a table called users. The users table looks something like this
id name
----- ------
1 Mark
2 Mike
3 Paul
4 Dave
5 Chris
6 John
The likes table looks like this.
user_one user_two match_id
----- ------ --------
1 2 abc
2 1
1 3 acc
3 1 abb
1 5 aee
5 1
The expected result should be
id name
----- ------
1 Mark
The two tables should only be linked on the rows in the likes table where the users_one column is set to the value that is most commonly found in that column. In this case, the user with the id of 1 is in the likes table with the user_one column 3 times where the match_id isn't empty.
I've thought it out to be written something like this
SELECT users.*, likes.COUNT(*) AS count
FROM users
JOIN likes
ON users.id = likes.user_one
WHERE likes.match_id != ''
But, I know this isn't correct. Is there a way to link two tables with a JOIN only on the most common rows in one of the tables?
Would Grouping work for what you need... ?
SELECT users.id, users.name, count(*) AS count
FROM users
JOIN likes
ON users.id = likes.user_one
WHERE likes.match_id != ''
group by users.id, users.name
should give you something like
1 Mark 3
Should be something like this, if I understood the question
select top 1 user_one, name
from likes
inner join users ON users.id = likes.user_one
where match_id != ''
group by user_one
order by count(*) Desc
Are you looking for something like this?
select u.id, u.name, count(*)
from users u
inner join likes l
on l.id = l.user_one and l.match_id != ''
group by u.id, u.name
order by count(*) desc
limit 1
The limit 1, combined with sorting by the # of likes in descending order will result in getting one user - the one with the most matched likes.
Try:
select *
from users
where id in (
select id
from likes
group by id
order by count(*) desc, id
limit 1
)
The subquery returns the id of the row with the most appearances in the likes table (group by id and order by count(*) desc). I've added id to the order by to give predictable results in case there are multiple with the same number of appearances. This is used to join to the users table to give the resultset required.

Duplicate content in LEFT JOIN query + get count on joined table

I am trying to join two tables with similar ids, then get a sum of two fields as well. let me explain:
test table: id | post | desc | Date
likes_dislikes table: id | song_id | user_ip | like | dislike
on test 'test table', the 'id' matches that of the likes_dislikes 'song_id', so I tried LEFT JOIN since not every post will have an id in the likes_dislikes table, but I got duplicate results .
SELECT *
FROM
test
LEFT JOIN likes_dislikes ON test.song_id = likes_dislikes.page_id
GROUP BY test.song_id
ORDER BY test.id DESC LIMIT $start, $limit
how can I prevent the duplicate content, and also, get the TOTAL likes/dislikes associated with each post as I run through a while loop?
I Assume you are looking for something like this:
SELECT
T.`id`,
T.`post`,
T.`desc`,
T.`Date`,
COUNT(L.`like`) as `LikeCount`,
COUNT(L.`dislike`) as `DislikeCount`
FROM `test` T
LEFT JOIN `likes_dislikes` L
ON T.`Id` = L.`song_id`
GROUP BY T.`Id`, T.`post`, T.`desc`, T.`Date`
ORDER BY T.`id` DESC;

Top Comments,Top Users,Top Users and Comments mysql

I have 2 tables comments | votes.
The `votes` structure is:
[`id` | `user_id` | `comment_id` | `rating`]
and the comments has the comment_id as the primary.
Now I want get the top comments according to the sum of rating.
[rating is 0 or 1]
and I want to get the top users too.
This will return the top 10 comments change the limit for more or less.
Obviously replace the * with the columns you want returned from comments
select *
from comments x
join (select comment_id, sum(rating)
from votes
group by comment_id
order by sum(rating) desc
limit 10 ) z on x.comment_id = z.comment_id
users will be done in the same way just change the comment_id from the user_id and join to you