MySQL Select - Help to Select most resent row from 2 columns - mysql

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.

Related

Limiting the count query in MySQL?

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

SQL Query: Order by greatest of two columns

I've tried about a dozen different methods to solve this issue, and everything I try is breaking my query... I have the following code that is used to generate a loop of threads on a message board:
SELECT MB_TOPICS.*, MAX(MB_REPLIES.TIMESTAMP) AS LATEST
FROM MB_TOPICS
LEFT JOIN MB_REPLIES
ON MB_TOPICS.TOPIC_ID = MB_REPLIES.TOPIC_ID
WHERE MB_TOPICS.CATEGORY_ID='$CATEGORY'
GROUP BY MB_TOPICS.TOPIC_ID
ORDER BY MB_TOPICS.STICKY DESC, LATEST DESC, MB_TOPICS.TIMESTAMP DESC
LIMIT $start,$limit";
This is basically pulling all of the topics within the category, and then via a join it is also getting a timestamp of the most recent reply (if any) from the replies table.
On the sort, I want to keep the most recently active threads at the top... currently (after sticky Y/N) it's sorting by most recent reply and then by the timestamp when the thread was created... this is wrong because it means a new thread will appear after an old thread with replies. I've tried things like
GREATEST(LATEST, MB_TOPICS.TIMESTAMP)
or using IIF statements, CASE statements within the ORDER BY, etc., but anything I do is just breaking the query so that no results appear. I just want to make this so that whichever timestamp is most recent (last reply or topic creation), it sorts descending on that largest value. I know this must be simple but it's killing me today. Thank you!
Edit: If it's helpful information here... the 'LATEST' column will be null for threads that have no replies...
OK, I finally got it. I had to use the MAX() function again rather than the alias, and coalesce to deal with the null values, combined with RiggsFolly's suggestion of pulling it as a new column, resulted in this functioning query:
"SELECT MB_TOPICS.*, MAX(MB_REPLIES.TIMESTAMP) AS LATEST,
GREATEST(COALESCE(MAX(MB_REPLIES.TIMESTAMP),0), MB_TOPICS.TIMESTAMP) AS SORT_ORDER
FROM MB_TOPICS
LEFT JOIN MB_REPLIES ON MB_TOPICS.TOPIC_ID = MB_REPLIES.TOPIC_ID
WHERE MB_TOPICS.CATEGORY_ID='$CATEGORY'
GROUP BY MB_TOPICS.TOPIC_ID
ORDER BY MB_TOPICS.STICKY DESC, SORT_ORDER DESC
LIMIT $start,$limit";
Thanks, I wouldn't have gotten there without the discussion here.

grouping and ordering conversation messages with users

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;

How to order a sql query for a ranking system with both average and number of votes?

I'm creating a list for best movies which are based on the users votes like imdb. I have done the list with this sql query:
SELECT data_id, COUNT(point), SUM(point)
FROM voting_table
WHERE data_type='1'
GROUP BY data_id
order by SUM(point)/COUNT(point)
DESC limit 100
This works well but i want also the number of votes(point) affect the order. I mean if a movie gets average of 8 with 10 votes and another movie gets average of 8 but with 5 votes. The one which has more votes should be listed higher than the other one. How can i do it? And is the query i wrote is efficent for server performance?
There is function AGV, I suggest you use that.
sort by avg, then by count or sum
...
ORDER BY AVG(point) DESC, COUNT(point) DESC
...
As of performance, there is not much you can do wihout complicating data structure.
It should be fine as it is unless your site si going to be as popular as imdb.
If your voting table grows past the point where speedup is needed then you need to start precalculating stuff (for real time updates using triggers that update score in movies table or some other intermediate table dedicated for that, other methods)
Just add the second order you want separated by comma .try this
SELECT data_id, COUNT(point), SUM(point)
FROM voting_table
WHERE data_type='1'
GROUP BY data_id
order by SUM(point)/COUNT(point) ,COUNT(point)
DESC limit 100
Try changing your order by clause to be:
order by SUM(point)/COUNT(point) desc, COUNT(point) desc
As it stands, your query appears to be efficient.

PHP + MySQL Forum display

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.