MySQL LIMIT 1 on second table with INNER JOIN - mysql

I am using this query to print out a forum board and all it's sub forums. What happens, as may be expected, is that all posts in all threads belonging to that forum are displayed. What I would like to happen is only the first post from each thread is displayed along with the forum title.
Query:
SELECT tf_threads.*, tf_posts.*
FROM tf_threads INNER JOIN tf_posts
ON tf_threads.thread_id=tf_posts.thread_id
AND tf_threads.parent_id=54 ORDER BY tf_posts.date ASC
Please note the parent_id field is given a variable in the real query.
So. If I make sense, can anyone help me out as to what query to write to only select the first post from each thread?
If there are no simple(ish) answers, how could I do it if I used a post number field in the second table, for example, the first post in thread has number 1, second post has number 2, etc. If I use this method, I'd obviously only like to select posts with a count number field of 1. I could just expand the original query with a AND post_number=1 right?
Thanks for reading,
James

Something like this?
http://murrayhopkins.wordpress.com/2008/10/28/mysql-left-join-on-last-or-first-record-in-the-right-table/
Edit: I think that it has to be something like this, but I'm also not an SQL expert:
SELECT tf_threads.*, tf_posts_tmp.*
FROM tf_threads
LEFT JOIN (SELECT p1.*
FROM tf_posts as p1
LEFT JOIN tf_posts AS p2
ON p1.postid = p2.postid AND p1.date < p2.date) as tf_posts_tmp
ON (tf_threads.thread_id=tf_posts_tmp.thread_id)

Related

MySQL select all posts + additional data in different groups

I'm trying to select all posts from a specific category along with some additional data from another table.
Despite my efforts none of the sql queries that I've tried have worked out so far.
Here is my code.
SELECT
a.*,
b.*
FROM forum_posts AS a
LEFT JOIN forum_categories AS b ON a.post_category = b.category_id
WHERE category_slug = 'news-and-anouncements'
Here's a screenshot to illustrate the result I'm trying to achieve.
As you can see I'm grabbing posts from the posts table, but I also wish to get the category fields without re-selecting them in each post selection, if that makes sense.
Any ideas on how I should tweak the query?

Turn two queries into one

I'm having some problems with a query I'm writing. This seems like table structure that is very frequent so I'd love some help.
Let's say I have 3 tables similar to a facebook structure. Users, Wall Posts, and Comments. Users can make wall posts, and comment on other wall posts.
On a users page I would like to show a users wall posts and a count of how many comments that post has. This is what I have so far
I query the Wall Post table using the users id as an inner join to the User table. That gives me a result set of wall posts for that user's page. Then I loop through that result set, take the Wall Post id from each result set, and query the Comment table for the Count of comments for that Wall Post Id. This works, however I have to hit the db twice. Can anyone think of a way that I could do this with one query?
First Query Example:
SELECT wallPost.*, user.currentDefault, user.displayName, user.userName
FROM wallPost
INNER JOIN user ON user.id = wallPost.sourceUserId
WHERE wallPost.recipientId = ? ORDER BY wallPost.id DESC
Second Query Example:
SELECT COUNT(id) AS count
FROM comment
WHERE wallPostId = ?
I would add the count as a subquery and join the subquery to the main query
SELECT
wallPost.*,
user.currentDefault,
user.displayName,
user.userName,
wallpost_commentcount.total
FROM
wallPost
INNER JOIN user ON user.id=wallPost.sourceUserId
LEFT JOIN (SELECT wallPostId,COUNT(*) as total FROM comment GROUP BY wallPostId) as wallpost_commentcount ON (wallpost_commentcount.wallPostId=wallPost.id)
WHERE
wallPost.recipientId = ?
ORDER BY wallPost.id DESC
Please make sure you have an index on comment.wallPostId otherwise this query will take a long time.
I used the LEFT JOIN because you always want to get the wallPost even if there are no comments records yet

order by count from another table

I hope itll be legal to post this as i'm aware of other similar posts on this topic. But im not able to get the other solutions to work, so trying to post my own scenario. Pretty much on the other examples like this one, im unsure how they use the tablenames and rows. is it through the punctuation?
SELECT bloggers.*, COUNT(post_id) AS post_count
FROM bloggers LEFT JOIN blogger_posts
ON bloggers.blogger_id = blogger_posts.blogger_id
GROUP BY bloggers.blogger_id
ORDER BY post_count
I have a table with articles, and a statistics table that gets new records every time an article is read. I am trying to make a query that sorts my article table by counting the number of records for that article id in the statistics table. like a "sort by views" functions.
my 2 tables:
article
id
statistics
pid <- same as article id
Looking at other examples im lacking the left join. just cant wrap my head around how to work that. my query at the moment looks like this:
$query = "SELECT *, COUNT(pid) AS views FROM statistics GROUP BY pid ORDER BY views DESC";
Any help is greatly appreciated!
SELECT article.*, COUNT(statistics.pid) AS views
FROM article LEFT JOIN statistics ON article.id = statistics.pid
GROUP BY article.id
ORDER BY views DESC
Ideas:
Combine both tables using a join
If an article has no statistics, fill up with NULL, i.e. use a left join
COUNT only counts non-NULL values, so count by right table to give correct zero results
GROUP BY to obtain exactly one result row for every article, i.e. to count statistics for each article individually

Advanced mysql grouping issue - brainteaser

I have been using stackoverflow vastly during the last year - an excellent source w/ great contributors. Now it's my time to request for help.
The setup is normal:
Orders, OrderArticles and Articles
I want to get the total amount of articles sold during the last year, but only during the best 5 weeks.
Never mind the WEEK-function and UNIXTIME-blah blah - I've got that covered. My question is wether it's possible or not to do without resorting to stored procedures or functions.
I have created a subquery for the summary for each week and article and order the result by the sum descendingly. Now - I only have to LIMIT the query to 5. Easy, but I also have to filter the result on the ArticleID BUT since I'm inside a subquery I don't have access to the outer ArticleID and it doesn't help to JOIN the result - it's too late ;-)
The syntax (hard to understand w/o the actual sql, right...?)
SELECT a.ID, [more fields], omg.total
FROM Articles AS a
LEFT JOIN
(
SELECT weeklytotals.articleID, weeklytotals.total
FROM
(
SELECT SUM(ra.quantity) AS total, ra.articleID AS articleID
FROM OrderArticles ra
INNER JOIN Orders r
ON ra.orderID = r.ID
WHERE r.timeCreated >= UNIX_TIMESTAMP('2011-06-30')
GROUP BY ra.articleID, WEEK(FROM_UNIXTIME(r.timeCreated))
ORDER BY SUM(ra.quantity) DESC
) AS weeklytotals
WHERE omg.articleID = a.ID --<-- THIS IS NOT WORKING BUT NECESSARY!
LIMIT 0, 5
) AS omg
ON omg.articleID = a.ID
WHERE a.isEnabled = 1 --more WHERE-thingys
This here returns the top 5 articles and ties the them to the correct Article. yay.
I have left out the SUM-function (which could go into the omg-SELECT).
Do you understand? Do I understand what I want? Yes, of course we do!
Thanx in advance.
Edit: The conditions have been changed - which makes my life easier, but I still would like to know if there is a solution to the problem.
If you require the omg subquery to use data from the a table, place it into the SELECT part not the FROM part. Using terms from the mysql documentation, you want the result of a correlated subquery to appear as a scalar operand in the outer result set.
You wrote about being interested in the sum, i.e. only a single number per article, although you left out the SUM from your example query. My approach relies on that sum, and would probably break in a bad way if you really needed distinct values for each of the best five weeks.
SELECT a.ID, [more fields], IFNULL(SUM(
(
SELECT SUM(ra.quantity) AS total
FROM OrderArticles ra
INNER JOIN Orders r
ON ra.orderID = r.ID
WHERE ra.articleID = a.ID -- <-- reference a.ID here
AND r.timeCreated >= UNIX_TIMESTAMP('2011-06-30')
GROUP BY WEEK(FROM_UNIXTIME(r.timeCreated))
ORDER BY SUM(ra.quantity) DESC
LIMIT 0, 5
)), 0) AS total
FROM Articles AS a
WHERE a.isEnabled = 1 --more WHERE-thingys
GROUP BY a.ID
I'm not saying anything about performance here. Placing the subquery this way, it will be executed for every row of the result set. So it might be too slow for practical use if you have a large number of articles. But if that should happen, I doubt that stored procedures or similar tricks would fare any better.
Edit: I found out that my original suggestion, which used subquerys nested two levels deep, doesn't allow access the innermost subquery to use a column of the outermost. But toying with this on sqlfiddle I also found out that one may safely pass the result of a subquery to sum, thus avoiding one level of nesting. So the above code nos has actually been checked and executed by a MySQL server, and should therefore work as intended.

Help building a sql query that uses inner join

I am trying to build a sql query that I think it involves inner joins, but I can't figure it out. Here's the model:
There's two tables: comments, posts
Among many columns, there's the following important ones: comments.id, comments.user_id (owner), comments.post_id (reference to posts table), posts.id, posts.editor_id (which is the person, ie, owner of post).
I want to get the comments that either
1) current user has written, so something like:
select * from comments where user_id = <<current_user_id>>
2) (Assume current_user is editor). Get all comments that belong to a post that you have created.
This is what I have, but I get multiple lines....what am I missing?
select * FROM comments INNER JOIN posts ON comments.post_id = <<test_id>>
WHERE posts.editor_id = <<current_user.editor_id>>;
If you could give me a sql query that includes both of these things, that would be amazing.
Thanks!
Im not sure what you mean by "multiple lines" as you would return a row for each comment.
This should do it.
SELECT comments.*
FROM comments
INNER JOIN posts
ON comments.post_id = posts.id
WHERE posts.editor_id = #editorID;
I want to get the comments that either 1) current user has written, so something like: select * from comments where user_id = <>
That's correct. What's wrong with that?
Get all comments that belong to a post that you have created. This is what I have, but I get multiple lines
Well... you're supposed to. Looking at the schema it's indeed a post could contain many comments. The query given by tyrongower should do what you want.
Going with your requirements, this should work for you:
SELECT * FROM comments
WHERE (user_id = 1)
OR (post_id IN (SELECT id FROM post WHERE editor_id = 1))
In the above query "1" is used as a sample and should be replace with the id of current user.