I'm trying to build a simple forum as a learning exercise. At the moment I have a topics(questions) table and a posts table (where the post_thread_id refers to the topic id).
I want to display the topics in the order by which the most recent post in that topic appears. Looking online I used this command:
SELECT topics.topic_title, topics.topic_date, topics.topic_title, max( posts.post_date )
FROM topics
LEFT OUTER JOIN posts ON topics.topic_id = posts.post_thread_id
GROUP BY topics.topic_id
ORDER BY MAX( posts.post_id ) ASC
which seems to work. But it doesn't work if there are no posts linked to a topic (i.e. an empty topic) as NULL comes first every time. I want it so that if no posts exist then the topic date is used to order.
How do I select the topic date if there are no posts?
Thanks (I'd appreciate a simple explanation as to how it is working as I am trying to learn).
ORDER BY
CASE WHEN MAX( posts.post_id ) IS NULL THEN 1 ELSE 0 END ASC
Self explanatory,when MAX(post_Id) is null it will change the order priority.
Related
I have 2 relational tables and I joined them, and I want it to be sorted by the same field.
Tables:
posts fields: id, post, created
reposts fields: id,post_id, created
Here's what I currently have:
SELECT
p.post as post,
p.created as post_created,
rp.created as repost_created
FROM posts p
LEFT JOIN reposts rp
ON rp.post_id = p.id
ORDER BY rp.created DESC, p.created DESC
And here's the result of that code:
{1
But what I want is to sort the whole data, base on the created field as a whole, regarding if it has repost_created or if it's null, it will base on the post_created field. Like this:
[2
Thank you very much!
It looks like you just need to COALESCE the value of rp.created with p.created and sort on that; that way if rp.created is not NULL you'll sort on that date, otherwise you'll sort on p.created:
ORDER BY COALESCE(rp.created, p.created) DESC
Note that you may want an additional criterion to break ties (when two rows have the same datetime value), you could perhaps use
ORDER BY COALESCE(rp.created, p.created) DESC, rp.id IS NULL
this will sort reposts ahead of posts at the same time.
i think your purpose is
SELECT
p.post as post,
p.created as post_created,
rp.created as repost_created
FROM posts p
LEFT JOIN reposts rp
ON rp.post_id = p.id
ORDER BY isnull( p.created ,rp.created)
A forum has topics and in this topics are the posts. The sort order is from old to new. It is possible to rate each post with "helpful".
A default SQL selection looks like this:
SELECT * FROM `posts` WHERE `topic_id` = 5033 ORDER BY `post_id` ASC
The "helpful" field in the posts table has the name "post_helpful".
Is it possible to order the posts in this way:
First post - Contains the question
If a post with more then 3 "post_helpful" exists, display this post as the second post. But only the post with the highest score.
Normal post row without the second post id
I only want the post with the highest score on the second post position. But only if the post has more than 3 rates. If there is no post with more than 3 rates, keep the default order
Thank you
Yes. The first part is a little tricky. You can use multiple expressions in the ORDDER BY:
SELECT p.*
FROM posts p CROSS JOIN
(SELECT MIN(p.post_id) as min_post_id
FROM posts p
WHERE p.topic_id = 5033
) pp
WHERE p.topic_id = 5033
ORDER BY (p.post_id = pp.min_post_id) DESC, -- lowest id first
(case when p.post_helpful > 3 then p.post_helpful else 0 end) DESC, -- helpful next
p.post_id ASC;
EDIT:
To get the posts with the maximum helpful:
SELECT p.*
FROM posts p CROSS JOIN
(SELECT MIN(p.post_id) as min_post_id,
MAX(p.post_helpful) as max_post_helpful
FROM posts p
WHERE p.topic_id = 5033
) pp
WHERE p.topic_id. = 5033
ORDER BY (p.post_id = pp.min_post_id) DESC, -- lowest id first
(pp.max_post_helpful > 3 AND p.post_helpful = pp.max_post_helpful) DESC, -- helpful next
p.post_id ASC;
I believe you want to have more complex sorting for the query
Can you assign a value or weight by the count of rows that were flagged helpful
This would then have a number to sort by
I.e. Query 2 counts the number of rows that show the post was helpful
Query 1 is the main query ordered by the value/count from Query 2
Suppose I have two tables : Topic and Post .
Topic has #OneToMany Set<Post> posts which means one topic may have zero or many replied posts. ( And Post has an #ManyToOne Topic topic link back to Topic )
Both Topic and Post have a created column , storing timestamp.
I want to get a list of topic order by latest replied post time , if one topic has no post replied , it will judge from topic's created time.
Such pseudo JPQL may look like :
select t from Topic t left outer join t.posts p
order by "max(t.created , latest p.created if p exists)" desc
group by t.id
Of course it won't work because I don't know how to write the correct order by clause here.
Can someone give me a hint ? Thanks.
==================== Updated ====================
Thanks to #Utsav SQL example . And this is the working JPQL :
select t
from Topic t
left outer join t.posts p
group by t.id
order by (case when p.id is null then t.created else max(p.created) end ) desc
And I am facing the problem of this :
Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'DBNAME.p.id' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by
This seems something incompatible with MySQL 5.7.x+ with OS/X 10.11 (Yosemite) . My working solution is here Getting this SQL Error: GROUP BY incompatible with sql_mode=only_full_group_by
After modifying my.cnf and restart MySQL , it works.
EDIT: Added group by logic.
I am assuming that posts table has a tid column which references to topic.id.
select t.id,
case when p.id is null
then t.created
else max(p.created)
end
as derived_max_time
From topic t
left join posts p
on t.id=p.tid
group by t.id
order by derived_max_time desc
See Updated MYSQL fiddle demo here
http://sqlfiddle.com/#!9/abbfb/8
I have a table called photos that has hundred of thousands of user uploaded photos.
Each user can obviously upload several photos.
The table schema is:
id,
user_id,
photo,
date_created
I just want to get the latest record that each user_id has posted..
I tried:
SELECT * FROM photos
GROUP BY user_id
ORDER BY date_created desc LIMIT 300
But that is obviously bringing back a lot of strange results.
This seems like an easy query, but I have done hours and hours of research on stack overflow and reading so many different articles on Google, and I can't for the life of me figure this simple query out.
This should get you the latest row for every user:
SELECT p.user_id, photo, date_created FROM photos p
JOIN (
SELECT user_id, MAX(date_created) max_date FROM photos GROUP BY user_id
) max_dates ON p.user_id = max_dates.user_id AND p.date_created = max_dates.max_date
Sample SQL Fiddle
Check this out. I used HAVING MAX(date_created) to retrieve the records which are currently created/uploaded.
SELECT user_id
FROM photos
GROUP BY user_id
HAVING MAX(date_created)
ORDER BY date_created DESC LIMIT 300
I believe what you want is to get rid of that GROUP BY and use a regular 'WHERE user_id = 'something', being the rest correct.
I tried a query like yours and the result was only one record by each 'user_id', lets say. GROUP BY usually uses a WHERE in the sentence...
http://www.w3schools.com/sql/sql_groupby.asp
I hope that helps :) If you get an error, please post it.
select p1.user_id, p1.photo, p1.date_created
from photos p1 left join photos p2
on p1.id < p2.id and p1.user_id = p2.user_id
where p2.id is null
try that
EDIT
forgot table name, my bad. added it in. also, here's a fiddle to see: http://sqlfiddle.com/#!9/a72f6/3
So my database setup is fairly simple.
I have a forum_cat table (a forum category) and forum_post table.
The forum_post has a field fk_forum_cat_id which ties each forum post to a category.
Each forum_post also has a field fk_parent_forum_post_id which basically says it belongs to an original post.
Further more, there is a date_added and date_edited field in forum_post.
Now, I am trying to generate the front page for my forum. I want to show a list of forum categories. Each one category should have a post count and the latest post. Could someone give me some direction with a query that does that all in one. I don't want to run 20 separate queries!
If I read your question correctly, you are seeking the category, the count of posts in the category, and the latest post in that category. Perhaps this simplification of laurent-rpnet's answer will do the trick...
SELECT c.forum_cat_id,
COUNT(p.fk_forum_cat_id),
MAX(p.date_added),
(SELECT p2.post_title
FROM forum_post AS p2
WHERE p2.forum_cat_id = c.forum_cat_id
ORDER BY date_added DESC
LIMIT 1)
FROM forum_cat AS c INNER JOIN
forum_post AS p ON p.fk_forum_cat_id = c.forum_cat_id
GROUP BY c.forum_cat_id;
If forum_post primary key is auto-incremented (should be but we never know...), this will return what you need:
SELECT c.forum_cat_id, COUNT(p.fk_forum_cat_id), MAX(p.date_added),
(SELECT p2.post_title FROM forum_post AS p2
WHERE p2.forum_post_id = (SELECT MAX(p3.forum_post_id) FROM forum_post AS p3
WHERE p3.fk_forum_cat_id = p2.fk_forum_cat_id) AND p2.fk_forum_cat_id = c.forum_cat_id)
FROM forum_cat AS c INNER JOIN
forum_post AS p ON p.fk_forum_cat_id = c.forum_cat_id
GROUP BY c.forum_cat_id;
I had to guess some field names:
forum_cat_id = forum _cat primary key
forum_post_id = forum_post primary key
post_title = post title or begining of post text in forum_post (depends on what you want to show).
The COUNT(p.fk_forum_cat_id) column will contain the post count in category
In addition to what you asked, you will get the date of the lastest post in the category as I think you'll need it if it is a good forum ;).
Obs: I didn't test it so you may need some debugging. If you have problems, let me know.
You can adapt this example to your problem:
SELECT *
FROM `test_post` AS p3
JOIN (
SELECT MAX( id ) AS id
FROM `test_post` AS p1
JOIN (
SELECT MAX( `test_post`.date ) AS DATE, cat
FROM `test_post`
GROUP BY cat
) AS p2 ON p1.date = p2.date
AND p1.cat = p2.cat
GROUP BY p1.cat
) AS p4 ON p3.id = p4.id;
Queries to dynamically count things tend to get slow very quickly and consume a lot of cpu. Even with good indexes, MySQL has to do a lot of work every single time to count all those rows.
An alternative to a query like this would be to summarize the counts of posts in the forum_cat table. Create a column named something like posts_count. Every time a post is created, it's easy enough to run a query increment or decrement the count.
UPDATE forum_cat SET posts_count=posts_count+1;
When you go to create the front page, your query becomes much more simple, and performant.