PHP MYSQL Forum teaser, howto? - php

I like to make an forum teaser for my website. Its easy to just show the latest posts or threads.. I like to get latest threads and posts in the same query, ordered by the last activity. So its going to be ordered by REPLY TO POST date, and THREAD POST date in the same query. I think it has some think to do with how you GROUP it, but I'm not sure.
Tables
threads
id, header, text, date, author
posts
id, text, date, author, thread_id
Example of usage
20 minutes ago - How to make an php/mysql script (2)
17 minutes ago - Pls help me out here (0)
1 hour ago - I need help with PHP (1)
As you see, both answered threads and new threads are on the list. (I need a date of the latest reply or when it was created, header and a count() of replys)
I hope you get, and know how to do this.
Troels
UPDATE:
I have this, and its okay, but i only get threads with replys.
SELECT
threads.*,
posts.*,
(SELECT date FROM posts WHERE thread_id = threads.id ORDER BY date DESC LIMIT 0,1) AS postdate,
(SELECT count(id) FROM threads WHERE thread_id = thread.id) AS replys
FROM
threads,
posts
WHERE
threads.id = posts.thread_id
GROUP BY
thread_id
ORDER BY
postdate DESC,
thread.date
LIMIT
0,15
HOW CAN I DO THIS?
UPDATE
aaaaaaaaaaaaaaaaawwwww Yeah!!!!
I managed to do it myself :-) Took a while to get it right.
SELECT
fisk_debat.id,
fisk_debat.dato,
IF((SELECT count(id) FROM fisk_debat_svar WHERE debatid = fisk_debat.id) < 1, fisk_debat.dato, (SELECT dato FROM fisk_debat_svar WHERE debatid = fisk_debat.id ORDER BY dato DESC LIMIT 0,1)) AS svardato,
fisk_debat.overskrift,
(
SELECT count(fisk_debat_svar.debatid)
FROM fisk_debat_svar
WHERE fisk_debat_svar.debatid = fisk_debat.id
) AS svar
FROM fisk_debat
GROUP BY id
UNION
SELECT
fisk_debat_svar.debatid AS id,
max(fisk_debat_svar.dato) AS dato,
max(fisk_debat_svar.dato) AS svardato,
(
SELECT fisk_debat.overskrift
FROM fisk_debat
WHERE fisk_debat.id = fisk_debat_svar.debatid
) AS overskrift,
(
SELECT count(fisk_debat_svar.debatid)
FROM fisk_debat_svar
WHERE fisk_debat_svar.debatid = id
) AS svar
FROM fisk_debat_svar
WHERE id != id
GROUP BY id
ORDER BY svardato DESC, dato DESC
LIMIT 0,15

If you want to keep the current DB structure, you'll need a Union to get the desired result.
An example can be found at http://www.mysqltutorial.org/sql-union-mysql.aspx
However, I'd still advise to change the structure as explained in the comments to your question.

WHERE clauses only select threads with replies, which is normal. You have to use the LEFT JOIN syntax.
Try this:
SELECT
threads.*,
posts.*,
(SELECT date FROM posts WHERE thread_id = threads.id ORDER BY date DESC LIMIT 0,1) AS postdate,
(SELECT count(id) FROM threads WHERE thread_id = thread.id) AS replys
FROM
threads
LEFT JOIN
posts
ON
threads.id = posts.thread_id
ORDER BY
postdate DESC,
thread.date
LIMIT
0,15

Related

How can I order topics by post.date_written?

I have 2 tables(I'm making kind of forum) I would like to sort topics order by last post that has been written(order by row 'posts.date_written'). I was trying to do it by myself but I couldn't get it working.
Topic table:
ID|id_subforum|owner_id|owner|title|description
Posts table:
ID|id_subforum|id_topic|by|description|date_written
Can somebody show me how should this SQL look like?
SELECT t.*
FROM topics AS t
LEFT JOIN (
SELECT id_topic, id_subforum, MAX(date_written) AS last_date
FROM posts
GROUP BY id_topic, id_subforum
) AS p
ON t.id = p.id_topic AND t.id_subforum = p.id_subforum
WHERE t.id_subforum = '$forumId'
ORDER BY last_date DESC

Select data from a MySQL table where some results from another table depends on a condition, if there are any

With a PHP code, I wish to order some MySQL results in a specific way.
I have two tables:
First table, called "post" with the following non-exhaustive content:
id
released_date
published_date
...
Second table, called "votes" with the following non-exhaustive content:
id
post_id
user_id
status
If a user votes for an existing post, a record is made in the "votes" table, inserting the post id as post_id and the user id as user_id. The status is 1 for an upvote and 2 for a downvote.
One important thing to keep in mind though: some posts might never receive any vote at all, and 0 occurrence would be found in the second table, for instance!
So, now on my first page I order my posts with their amount of votes (upvotes-downvotes) the following way, and it works fine:
$post_req = mysql_query('SELECT * FROM post
WHERE NOW() > released_date
ORDER BY ((SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 1)-(SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 2)) DESC, published_date DESC
LIMIT 0, 5');
But on the next page (i.e a new iteration), I need to continue where I left, in terms of votes. Before I do that, I save the votes amount of the last post of the first page to pass it to the next one, under the variable $last_post_votes.
Now, this where I struggle: I need to look for posts which have a lower amount of votes than this variable in a new request. As follows, my failing attempt:
$post_req_1 = mysql_query('SELECT * FROM post
WHERE NOW() > released_date
AND ((SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 1)-(SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 2)) < "'.$last_post_votes.'"
ORDER BY ((SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 1)-(SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 2)) DESC, published_date DESC
LIMIT 5');
And then I tried something like that, which failed too:
$post_req_1 = mysql_query('SELECT post.*,
((SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 1)-(SELECT COUNT(*) FROM votes WHERE votes.poste_id = post.id AND votes.status = 2)) AS all_votes
FROM post, votes
WHERE NOW() > post.released_date
AND all_votes < "'.$last_post_votes.'"
ORDER BY all_votes DESC, post.published_date DESC
LIMIT 5');
The problem is clearly the condition upon searching results from another table in the SELECT.
Any help is greatly appreciated!
Thanks a lot in advance! :-)
Lois
EDIT:
I managed to make it work as I wished, by using a condition directly in the ORDER BY itself. Not sure it's super proper, but it seems to work:
$post_req_1 = mysql_query('SELECT * FROM post
WHERE NOW() > released_date
ORDER BY ((SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 1)-(SELECT COUNT(*) FROM votes WHERE votes.post_id = post.id AND votes.status = 2)) < "'.$last_post_votes_passed.'" DESC, published_date DESC
LIMIT 5');
If your first statement works fine, why don't you continue with that?
Aou start with the LIMIT clause of LIMIT 0,5 which gives you the first 5 records of the resultset. If you increase the first parameter to LIMIt it will show you the next 5 records, and so on. No need to fiddle around with interim variables...
// first page
SELECT ... LIMIT 0,5
// seond page
SELECT ... LIMIT 5,5
// 10th page
SELECT ... LIMIT 45,5
See also http://dev.mysql.com/doc/refman/5.0/en/select.html
If i am not mistaken is this what you are looking for?
SELECT p.id, IFNULL(COUNT(v.id), 0) - IFNULL(COUNT(v2.id), 0) AS `Votes`
FROM
posts p
LEFT JOIN votes v on v.post_id = p.id AND v.status = 1
LEFT JOIN votes v2 on v2.post_id = p.id and v.status = 2
WHERE NOW() > p.released_date
ORDER BY `Votes` DESC;

Combine two SELECT queries from different tables

Issue
I have one table (posts) with articles and article meta.
Another table (post_reviews) contains user-submitted ratings (a value out of 5) for each article, referencing posts by the id of the post in question.
I am trying to find the top three posts, by review, of the last 3 days. Therefore I need to:
find all the posts in that time period (3 days)
find the average rating for each post
sort them by average rating (desc)
Code
For the first part, I can successfully use the query:
SELECT * FROM `posts` WHERE `hub_id`=:hub_id AND `date`>=:start_date AND `date`<=:end_date)
To find each individual post's average rating, I use this query:
SELECT SUM(`review`) AS `total` FROM `post_reviews` WHERE `id`=:id
then get the number of rows from this to work out the average:
SELECT * FROM `post_reviews` WHERE `post_id`=:id
How can I combine these three, or process this data so I can order the posts in a time period by the average rating?
ANSWER
The end result looks like this:
SELECT `posts`.`id`, avg(`post_reviews`.`review`) as `average`
FROM `posts`
JOIN `post_reviews` ON (`posts`.`id`=`post_reviews`.`post_id`)
WHERE `hub_id`=:hub_id
AND `posts`.`date`>=:start_date
AND `posts`.`date`<=:end_date
GROUP BY `post_id`
ORDER BY avg(`review`) desc
Not sure what your hub_id represents, but I assume it's necessary; also assume the key field in Posts is posts.post_id and not posts.id:
SELECT `p`.`id`, avg(`pr`.`review`) AS `average`
FROM `posts` AS `p`
JOIN `post_reviews` AS `pr` ON (`p`.`id`=`pr`.`post_id`)
WHERE `hub_id` =:hub_id
AND `p`.`date` BETWEEN CURRENT_DATE-3 AND CURRENT_DATE
GROUP BY `p`.`id`
ORDER BY avg(`review`) DESC;
See Example: sqlfiddle
Not sure about the syntax for MySQL, but the would need a join and a group by.
Something like....
SELECT post_id. avg(review)
FROM Posts P Inner Join Post_reviews PR on (p.post_id = pr.Post_id)
WHERE `hub_id`=:hub_id AND `date`>=:start_date AND `date`<=:end_date)
Group by Post_id
order by 2 desc
Here is a query that works with sqlfiddle to prove it.
SELECT
p.hub_id
,p.post_id
,p.article
,p.articleMeta
,p.date
,IFNULL(AVG(r.ratings), 0) averageRating
FROM posts p
LEFT JOIN post_reviews r ON
r.post_id = p.post_id
WHERE
hub_id = 1
AND date >= CURDATE() - 3
AND date <= CURDATE()
GROUP BY
p.hub_id
,p.post_id
,p.article
,p.articleMeta
,p.date
ORDER BY
p.date DESC
,averageRating DESC
http://sqlfiddle.com/#!2/39315/1

Intermediate mySQL Query - join two tables together and limit the results

Here is my table arrangement:
Posts
post_id
post_votes
Comments
comment_id
post_id
comment_time
I have failed to create a query that does the following:
Select 10 Posts Order By post_votes desc
While getting 5 comments for each post
I will post what I have tried if necessary.
I am just getting into more complicated queries, any help or suggestions is greatly appreciated
The below will retrieve 10 post order by desc and also 5 comments order by desc respectively.
select post_id,post_votes,comment_id,comment_time,
#rn := CASE WHEN #prev_post_id = post_id THEN #rn + 1 ELSE 1 END AS rn,
#prev_post_id := post_id from
(select p.post_id,post_votes,comment_id,comment_time from
(SELECT post_id,post_votes from posts order by post_votes desc limit 10) p
left outer join
comments c on p.post_id=c.post_id order by post_id,comment_time desc )m
having rn<=5
SQL FIDDLE HERE (testing sample of retrieving 3 post order by desc and also 2 comments for each post respectively).

Latest forum posts or replies, with count replies in same query

I want to list latest activity in my forum
UPDATE:
I got this to work now.
SELECT
fisk_debat.*, fisk_debat_svar.*,
(SELECT dato FROM fisk_debat_svar
WHERE debatid = fisk_debat.id
ORDER BY dato DESC LIMIT 0,1) AS svardato,
(SELECT count(id) FROM fisk_debat_svar
WHERE debatid = fisk_debat.id) AS svar
FROM
fisk_debat_svar, fisk_debat
WHERE
fisk_debat.id = fisk_debat_svar.debatid
GROUP BY
debatid
ORDER BY
svardato DESC, fisk_debat.dato
LIMIT
0,15
Now I want to list newly created threads from the forum too and it have to blend into the list like the others. Also ordered by date. Like to different queries merged together. I know UNION but its not the same columns.
Need help.
SELECT
post.id,
post.date,
post.header,
post.username,
COUNT(reply.postid) AS reply,
reply.date AS replydate
FROM
post AS post
INNER JOIN
reply ON post.id = reply.postid
GROUP BY postid
ORDER BY replydate DESC
LIMIT 0,15
Simply add the sorting order

Categories