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.
Related
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'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.
In phpbb3 I want to select latest 10 active topics. i.e topics that lastly has posts. In the PHPbb3 schema, the table topics has many posts. In order to achieve this, I tried the following SQL
SELECT DISTINCT (`t_topics`.`topic_id`), `t_topics`.topic_title FROM
`t_topics` , `t_posts` WHERE `t_posts`.topic_id = `t_topics`.topic_id
ORDER BY `t_posts`.post_id DESC LIMIT 10;
However, there is a topic that I'm sure that it has the latest post and it comes at the end of records.
I tried to remove DISTINCT However, I got have the correct order, but there are repeated topics. I want to get the correct order with no repeated topics but I don't know how?
You can use group by clause instead of Distinct on t_topics.topic_id.
Query is : SELECT t_topics.topic_id, t_topics.topic_title FROM t_topics , t_posts WHERE t_posts.topic_id = t_topics.topic_id GROUP BY t_topics.topic_id ORDER BY t_posts.post_id DESC LIMIT 10;
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.
Having a bit of trouble with getting total unique records and grouping by date. The end result is I am getting totals per day but it is not using unique emails based on the distinct function. Here is my query...
SELECT count(distinct(emailaddress)), DATE(EntryDate)
FROM tblentries
group by DATE(EntryDate)
ORDER BY DATE(EntryDate) desc
The results end up not de-duping the count for each day. Thoughts?
Thanks!
Based on the conversation, I believe what you are looking for is the number of distinct never-before-seen email addresses per day:
SELECT
DATE(t.EntryDate) as RecordDate,
COUNT(DISTINCT t.emailaddress) as NewEmailAddresses
FROM
tblentries t
WHERE
NOT EXISTS(
SELECT 1
FROM tblentries t2
WHERE
t2.emailaddress = t.emailaddress
AND DATE(t2.EntryDate) < DATE(t.EntryDate)
)
GROUP BY
DATE(t.EntryDate)
ORDER BY
DATE(t.EntryDate) ASC;
This is off the top of my head, so it may not be right, and it will be slow, but I think this is in the right direction. On a side note, if you plan on running this regularly, an index on emailaddress would be a good idea.
Let me know if this works.