Skip to main content
gamedev.net
🔒 Locked

[web] [SQL] cannot come with a query that does what *I* want

Started by Emmanuel Deloget 11 replies 2.6k views
Original Post
Emmanuel Deloget
Emmanuel Deloget
... and what I want is supposed to take precedence over what MySQL wants. Here is the deal: I have two tables, named threads and posts. I simplify them up to the maximum so that they contain only meaningful information. Out of context information is stripped. threads * thread_id (INT, autoincrement, PK) * forum_id (INT) post * post_id (INT, autoincrement, PK) * thread_id (INT) * post_date (DATETIME) Now, I have a query to write: I want to retrieve the last post of each thread for a known forum_id. The best I cam with is:

SELECT * 
FROM 
  threads as t1,
  (SELECT * 
   FROM 
     posts as st1, threads as st2
   WHERE st2.forum_id=1
     AND st1.thread_id = st2.thread_id
   ORDER BY st1.post_id DESC 
   ) as t2
WHERE t1.forum_id=1
  AND t2.forum_id = t1.forum_id
  AND t2.thread_id = t1.thread_id


And this certainly doesn't give me what I want. Suppose that threads and posts contains the following information:

threads
--------------------------
thread_id   |  forum_id
--------------------------
  1         |    1
  2         |    1
  3         |    2
  4         |    1
  5         |    2

posts
---------------------------------------------
post_id   |  thread_id  |  post_date
---------------------------------------------
  1       |    1        | 2009-04-01 12:00:00
  2       |    2        | 2009-04-01 13:00:00
  3       |    2        | 2009-04-01 14:00:00
  4       |    1        | 2009-04-01 15:00:00
  5       |    3        | 2009-04-01 16:00:00
  6       |    1        | 2009-04-01 17:00:00
  7       |    4        | 2009-04-01 18:00:00
  8       |    5        | 2009-04-01 19:00:00
  9       |    5        | 2009-04-01 20:00:00
What I want is (for example, for forum 1)

------------------------------------------------------------
  forum_id  |  post_id   |  thread_id  |  post_date
------------------------------------------------------------
      1     |    6       |    1        | 2009-04-01 17:00:00
      1     |    3       |    2        | 2009-04-01 14:00:00
      1     |    7       |    4        | 2009-04-01 18:00:00
But I seem unable to find a request that does "just" that. Question can someone here help me? Thanks in advance (cookied are distributed accross teh intartube for every answer).
AlphaCoder
AlphaCoder
I must be missing something here. But couldn't you just do this:

query the thread table for threads matching your known forum id. then for each thread returned, just query the post table for all posts who's thread_id matches the current thread_id, order by post_date DESC, and print out the first one.

Pretty sure that would do what you're looking for.
http://www.sharpnova.com
Emmanuel Deloget
Emmanuel Deloget
Quote:
Original post by AlphaCoder
I must be missing something here. But couldn't you just do this:

query the thread table for threads matching your known forum id. then for each thread returned, just query the post table for all posts who's thread_id matches the current thread_id, order by post_date DESC, and print out the first one.

Pretty sure that would do what you're looking for.


That's practical if you have a small number of thread_id. But if you get a gorwing number of threads, that n+1 requests, and it's going to be slow as hell.

But yes, that would definitely do it, except that it's not feasible in this context :) But thanks anyway.
ToohrVyk
ToohrVyk
I must be missing some obvious problem, but with the data set you've provided a plain old inner join seems to give the right results:

SELECT forum_id, thread_id, MAX(post_date) FROM threads   NATURAL JOIN postsWHERE    forum_id = 1 GROUP BY t.thread_id


EDIT: ah, I see you also need the post_id. Back to work.
krez
krez
Have you looked into the GROUP BY statement? and derived tables / subqueries / whatever MySQL calls them?

SELECT forum_id,
post_id,
thread_id,
post_date
FROM threads t
INNER JOIN posts p
ON p.thread_id = t.thread_id
INNER JOIN (
SELECT thread_id,
MAX(post_id) AS LastPostID
FROM posts
GROUP BY thread_id
) x
ON x.thread_id = p.thread_id
AND x.LastPostID = p.post_id
WHERE t.forum_id = 1


Or something along those lines.

The query in parenthesis will give you each thread_id and the highest post_id for each one (I'm assuming that a higher post_id would correlate to a higher date). Then you can join that back to the main posts table and only get those records.
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
ToohrVyk
ToohrVyk
Yep. Ended up with this myself:

SELECT forum_id, post_id, thread_id, post_date   FROM posts        NATURAL JOIN (SELECT forum_id, thread_id, MAX(post_date) AS post_date                        FROM threads                             NATURAL JOIN posts                        WHERE forum_id = 1                    GROUP BY thread_id) s;
Alpha_ProgDes
Alpha_ProgDes
Quote:
Original post by krez
Have you looked into the GROUP BY statement? and derived tables / subqueries / whatever MySQL calls them?
SELECT forum_id, post_id, thread_id, post_dateFROM   threads tINNER JOIN posts p    ON p.thread_id = t.thread_idINNER JOIN (            SELECT thread_id, MAX(post_id) AS LastPostID            FROM   posts            GROUP BY thread_id           ) x   ON x.thread_id = p.thread_id AND x.LastPostID = p.post_idWHERE   t.forum_id = 1



Or something along those lines.

The query in parenthesis will give you each thread_id and the highest post_id for each one (I'm assuming that a higher post_id would correlate to a higher date). Then you can join that back to the main posts table and only get those records.


Easier for me to read that's all. [smile]

Question. Does Toohrvyk's and krez query do the same thing with the same result?
Beginner in Game Development?  Read here. And read here.  
ToohrVyk
ToohrVyk
Quote:
Original post by Alpha_ProgDes
Question. Does Toohrvyk's and krez query do the same thing with the same result?
Nope. My solution returns the latest post for every thread in a forum, whereas Krez's solution returns the post with the highest identifier for every thread in a forum.

If having a smaller identifier implies being older, then both versions will be equivalent, with his version being faster (since mine has to perform an inner join on a potentially unindexed date field).

Emmanuel Deloget
Emmanuel Deloget
Quote:
Original post by ToohrVyk
Quote:
Original post by Alpha_ProgDes
Question. Does Toohrvyk's and krez query do the same thing with the same result?
Nope. My solution returns the latest post for every thread in a forum, whereas Krez's solution returns the post with the highest identifier for every thread in a forum.

If having a smaller identifier implies being older, then both versions will be equivalent, with his version being faster (since mine has to perform an inner join on a potentially unindexed date field).


post_id begin an auto_increment, having a small post_id means that th post is old - but I tend to prefer logical code over tricky code. And the date is indexed :)
krez
krez
Ah yeah that was just my personal bias against date/time fields hanging out, sorry about that :) I did disclaim that it assumed the higher post_id would imply a later date.
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
ID Merlin
ID Merlin
SQL is such a powerful language. There are always several ways to accomplish the same goal.

SELECT forum_id, post_id, thread_id, post_dateFROM   threads tINNER JOIN posts p    ON p.thread_id = t.thread_id   AND p.post_id = (            SELECT MAX(post_id)            FROM   posts            WHERE p.thread_id = t.thread_id)WHERE t.forum_id = 1


This is basically the same as Krez' query, just easier to read IMO.
evolutional
evolutional
Quote:
Original post by ID Merlin
SQL is such a powerful language. There are always several ways to accomplish the same goal.


And don't forget CTEs in SQL Server ;)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.