This title is awful, but can't think of a better one. This is twitter specific, but can apply to any similar application where you have private conversations.
I want to display all direct messages a user might have. All messages from/to a specific user should be grouped together.
Here's a SQL Fiddle example.
In this example, I received messages from two users, and replied to one (type of in/out). The first query is simply ordering by date descending. The order is 3 2 1, but what I really want is 3 1 2 because 3 it's the latest, and 1 is related to 3.
The second query gets the correct order, but using GROUP_CONCAT. This makes for very messy query, and I would rather have one message in each row so I don't have to split them in PHP.
The third query was added because I'm not yet sure if I want to order each conversation ASC or DESC. This one does the GROUP_CONCAT ASC correctly, but because the message from user2 is newer than the first message from user1, the two rows are reversed.
Hope this makes sense. The two orders I would like to achieve are 3 1 2 and 1 3 2, each message as its own row, and two different queries. Thanks!
Are you looking for this?
SELECT *
FROM test
ORDER BY "user", date DESC;
EDIT:
You want to order users by the time of their most recent message. That requires something like a join:
select t.*
from test t join
(select user, max(date) as maxdate
from test
group by user
) tu
on t.user = tu.user
order by tu.maxdate desc, user, date desc;
Related
I am trying to do a simple test where I'm pulling from a table the information of a specific part number as such:
SELECT *
FROM table_name
WHERE part_no IN ('abc123')
This returns 25 rows. Now I want to count the number that meet the "accepted" condition in a specific column but the result is limited to only the 10 most recent. My approach is to write it as follows:
Select Count(*)
FROM table_name
WHERE part_no IN ('abc123') AND lot IN ('accepted')
ORDER BY date DESC
LIMIT 10
I'm having a hard time to get the ORDER BY and LIMIT operations to work. I could use help just getting it to limit appropriately, and I can figure out the rest from there.
Edit: I understand that the operations are happening on the COUNT which only returns one row with a value; but I put the second clip to show where I am stuck in my thought process.
Your query SELECT Count(*) FROM ... will always return exactly one row.
It's not 100% clear what exactly you want to do, but if you want to know how many of the last 10 have been accepted, you could use a subquery - something like:
SELECT COUNT(*) FROM (
SELECT lot
FROM table_name
WHERE part_no IN ('abc123')
ORDER BY date DESC
LIMIT 10
)
WHERE lot IN ('accepted')
The inner query will return the 10 most recent rows for part abc123, then the outer query will count the accepted ones.
There are also other solution (for example, you could have the inner query output a field that is 0 when the part is not accepted and 1 when the part is accepted, then take the sum). Depending on which exact dialect/database you are using, you may also have more elegant options.
Select count returns ONE ROW therefore the ORDER BY and the LIMIT will not work on the results
I'm creating a message board. When a topic gets a reply, the entire topic (all rows that has the topicid) must be bumped to the top of the forum. Pinned topics should always be displayed first, then followed by the topic that has the most recent post date because they are bumped to the top when they get a reply.
This is a pic of the table that contains the posts.
DB Table before query
I need 1 query that will do the following:
group all the topicid together (lets call this "group");
within each group sort the rows by parentid ascending, but NULL always is sorted first;
groups that are "pinned" are displayed first
then groups that have the "latest" post displayed first
The query should give the following results
Results of the query
I think this query will do what you want.
SELECT *
FROM messages m
ORDER BY IF(pinned='yes','9999-12-31 23:59:59', (SELECT MAX(date) FROM messages m2 WHERE m2.topicid = m.topicid)) DESC,
topicid, IFNULL(parentid, 0)
The first part of the order by ensures that groups that are pinned are ordered first, followed by groups that have the most recent post. It does this by selecting the maximum possible date when the group is pinned, otherwise the latest date for posts in that group and sorts by that value descending. The second part then sorts those posts by topicid, and the final part sorts by parentid. To ensure that posts with a NULL parentid sort first, we use an IFNULL clause on parentid to set the sorting value to 0 when parentid is NULL.
I've created an SQLFiddle to demonstrate this.
Edit This updated query will also sort pinned topics by latest date instead of just by topicid. It does this by adding 1000 years to the date of pinned posts, thus ensuring that pinned posts sort ahead of non-pinned posts while retaining the ordering between pinned posts as well.
SELECT *
FROM messages m
ORDER BY (SELECT MAX(IF(pinned='yes', date + interval 1000 year, date))
FROM messages m2
WHERE m2.topicid = m.topicid) DESC,
topicid, ifnull(parentid, 0)
Here's an updated SQLFiddle to demonstrate.
I'm afraid I can only answer parts of your question, but I'm giving it a shot and posting it anyway in the hope that it will help you solve your issue.
First, I'd grab the pinned messages (lastest first in this query):
SELECT * FROM messages WHERE pinned = 1 ORDER BY date DESC
Then, you can grab - let's say - the 10 most recent topics:
SELECT MAX(date) AS latest, topicid FROM messages GROUP BY topicid ORDER BY latest DESC LIMIT 10
Now you should know the topicids from which you want to display messages. You could "chain together" the messages with a join:
SELECT * FROM messages AS m1 JOIN messages AS m2 ON m1.postid = m2.parentid WHERE m1.topicid IN <some stuff here> ORDER BY m1.topicid ASC, m1.postid DESC
Sorry for the incomplete answer. Any comments to help me fill the gaps are welcome ;)
I have the following table that stores messages between users:
I need to display a list of all last message for a users (from all users that have had contact with).
You will see to users being 1000000002 & 1000000172 for example. I need to show the last message between them which could be rows 1 to 4 - but would be 4 as last time.
I have tried the query below but its still isn't right:
SELECT sender_userid,receiver_userid,message,message_read,`datetime` FROM messages
WHERE (receiver_userid='1000000172' OR sender_userid='1000000172') AND friendship_status=1 AND receiver_history=1
GROUP BY receiver_userid
ORDER BY `datetime` ASC;
I find the order by doesn't get the most resent - could be because its after the Group By.
Also find it treats the sender_userid & receiver_userid as different rows in the Group By. I'm unsure how to get the most resent out of both.
thankyou so very much
Your GROUP BY should throw you errors, but MySQL just gives you garbage instead :)
You do not even need a group by, you simply want a list of all messages in which user X is involved and you want to sort them, so you have most of the work domn allready:
SELECT *
FROM messages
WHERE (receiver_userid='1000000172' OR sender_userid='1000000172')
AND friendship_status=1 AND receiver_history=1
ORDER BY `datetime` DESC;
Mind that you want to sort descending if you want the most recent ones first!
use DESC instead of ASC. DESC means large one is first.
I am currently building a simple PHP + MySQL forum but I am having problems with getting the information to show in the correct format.
My current SQL code is
SELECT forum_posts.catId, forum_posts.postId, forum_posts.date, forum_posts.message,
forum_posts.userId, users.userId, users.username, forum_thread.threadId, forum_thread.subjectTitle
FROM forum_posts
LEFT JOIN forum_thread ON forum_posts.threadId = forum_thread.threadId
LEFT JOIN users ON users.userId = forum_posts.userId
GROUP BY forum_posts.catId
ORDER BY forum_posts.postId DESC, forum_posts.date DESC, forum_posts.catId ASC
The problem I have is that it brings back everything in the right category but it brings back the first result of the category and not the last one.
I simply want the code to show the last reply in each category.
Any help is much appreciated thank you.
Your query should return a range of rows. Try to limit the result to 1 element. If you sort the results descending, you will get the last item.
ORDER BY ... DESC LIMIT 1
I am not sure whether you find the latest entry by postId or date. If you find it by date, you must start the grouping with the date.
But I don't understand why you are sorting the results so much for getting only one dataset.
ORDER BY forum_posts.date DESC LIMIT 1;
Is this what you want? Additionally this could help you: Select last row in MySQL.
Here is my code:
mysql_query("SELECT * FROM messages WHERE to_user_id = '$user_id' GROUP BY from_user_id ORDER BY read,sent_date DESC")
and here is my table structure
I use the GROUPY BY from_user_id statement to briefly show a list of "conversations" instead of every single message. Like this
But, as you can see in the image, the top two are the wrong way round, the first one says "1 week ago" and the one below says "2 days ago". The reason for these being in the wrong order is due to the GROUP BY from_user_id statement. Because it groups all the messages from that user and it wont have the the most recent time on it.
So my question is:
How can I GROUP BY from_user_id by the most recent record?
You can not SELECT columns not listed in the GROUP BY or otherwise allowed functions. This is how GROUP BY works.
Although most other SQL flavors would fail on such a query, MySQL doesn't. Instead it provides arbitrary results - what you are seeing.
You can solve this a few different ways. For example:
SELECT the ids of the latest user conversations using GROUP BY in a separate query.
Do it all in one query by sub-selecting the ids or JOIN the set of ids.
Since MySQL doesn't support windowing functions like ROW_NUMBER() OVER() you can do something like this:
SELECT *
FROM Messages
where id in (SELECT MAX(ID) FROM messages GROUP BY from_user_id)
ORDER BY sent_date, read
The subquery will only return the newest message id for each user. I'm assuming your auto_increment corresponds with the order the messages are sent in. Even if it's not the exact logic you might want, this is a general technique to get a specific subset of values from grouped records that works in MySQL.
Try with this
SELECT *,MAX(id) as OrderField FROM messages WHERE to_user_id = '$user_id'
GROUP BY from_user_id
ORDER BY OrderField DESC,read