2

I have two database tables I am attempting to join (home_comments and profile_img). What I am trying to attempt is matching the user_id from the home_comments database to the profile_img database, in order to get the profile image from the person who commented. The query I wrote is not broken, as it is producing results, however, the queried results are showing all of the images each user_id has in the profile_img database.

Whenever a person uploads a profile_img, I just add it to the database and then simply call for the last one within it to display the profile_img. So, I am looking for the same concept to be implemented. The user's last profile_img to show.

Whenever I add LIMIT 1 to the end of the query it only allows one comment to show, total. All I need is for the last (DESC) profile_img to show for each user, but still showing all of the comments. How could I accomplish this?

Initially I had the following query:

$select_comments_sql = "
    SELECT * 
    FROM home_comments
    ORDER BY id DESC
";

My attempt at the query

$select_comments_sql = "
    SELECT c. *,
    p.user_id, p.img
    FROM home_comments AS c
    INNER JOIN profile_img AS p
    WHERE c.user_id = p.user_id
    ORDER BY id DESC
";

Database setups:

home_comments

id, user_id, username, comment, date

profile_img structure:

id, user_id, img

Edit: I also just noticed that it is showing the same comment for each different photo in the database, so duplicated comments. Not sure if this has to do with the image issue.

SQL with query:

$select_comments_sql = "
    SELECT c.*, p.user_id, p.img
    FROM home_comments AS c
    INNER JOIN (SELECT max(ID) as ID, user_ID  
                FROM profile_img 
                GROUP BY user_ID) PI
      on PI.User_ID = C.USer_ID
    INNER JOIN   profile_Img p
      on PI.user_ID = P.User_ID 
     and PI.ID = P.ID
    ORDER BY C.id DESC
";
  if ($select_comments_stmt = $con->prepare($select_comments_sql)) {
        //$select_comments_stmt->bind_param("s", $user_id);
        $select_comments_stmt->execute();
        if (!$select_comments_stmt->errno) {
            //echo "error";
        }
        $select_comments_stmt->bind_result($comment_id, $comment_user_id, $comment_username, $home_comments, $comment_date, /*$commenter_id,*/ $commenter_user_id, $commenter_img);

        $comment_array = array();
        while ($select_comments_stmt->fetch()) {
            $comment_array[] = $comment_user_id;
            $comment_array[] = $comment_username;
            $comment_array[] = $home_comments;
            $comment_array[] = $comment_date;
            /*$comment_array[] = $commenter_id;*/
            $comment_array[] = $commenter_user_id;
            $comment_array[] = $commenter_img;
            $commenter_img = '<img class="home-profile-pic" src=" '.$commenter_img.'">';
            if ($home_comments === NULL) {
                echo 'No comments found.';
            } else {
                echo $commenter_img;
                echo $comment_username. "<br>";
                echo $home_comments. "<br><br><br>";
            }
9
  • Can we assume the highest profile_img.ID is the most recent image that you want to return? Commented Oct 20, 2016 at 14:41
  • Yes, that would be correct. Commented Oct 20, 2016 at 14:42
  • I also just noticed that it is showing the same comment for each different photo in the database, so duplicated comments. Not sure if this has to do with the image issue. Commented Oct 20, 2016 at 14:43
  • You could join the tables intermediately with select max(id), user_id from profile_img group by user_id Commented Oct 20, 2016 at 14:48
  • @becky the same comment is because of the M-M relationship. You need a 1-M so that comments doesn't repeat. Commented Oct 20, 2016 at 14:52

3 Answers 3

2

One approach would be to use an inline view to generate a set of data consisting of the max ID for each user's photo then use this set to limit the photos for all users..

In the below I generate a dataset called PI containing the max ID of each profile image for each user. Then this is joined back to profile_img entire set to act as a limit; thus only returning the most recent photo for a user. This in essence ensures you have a 1-M relationship between comments and Photo_image. The many-to-many was what was causing the problem.

SELECT c.*, p.user_id, p.img
FROM home_comments AS c
INNER JOIN (SELECT max(ID) as ID, user_ID  
            FROM profile_img 
            GROUP BY user_ID) PI
  on PI.User_ID = C.USer_ID
INNER JOIN   profile_Img p
  on PI.user_ID = P.User_ID 
 and PI.ID = P.ID
ORDER BY C.id DESC
Sign up to request clarification or add additional context in comments.

8 Comments

This seems to be breaking the query, but I cannot figure out where.
Wouldn't I need to select the id from the profile_img database as well? That would determine the most recent image.
I just added id to the p.user_id, p.img and it didn't seem to help.
I can't see why this is breaking. the subquery returns ID, user_ID and is joined to Comments on user_ID. The second join is on profile_Img and joins to the subquery on User_ID and on the Profile_IMG.ID. What error are you getting? or could you post a sample tables/data to SQL FIDDLE (and post link back in your question) so that we could figure out what's wrong? Breaking the query isn't descriptive enough. Is PHP returning an error or is mySQL returning an error? if so what's the error?
Sure, one minute and I will send.
|
1

If you're only running the query for one (or a few) users, the fastest way is probably to have a sub-select in your select instead of using a join, since you're not strictly 'joining' the data.

SELECT c. *,
(
    SELECT p.img 
    FROM profile_img AS p
    WHERE p.user_id = c.user_id
    ORDER BY p.id DESC
    LIMIT 1
) AS img
FROM home_comments AS c
WHERE c.user_id = x

This will avoid computing every user's most recent profile image when you're only ever fetching one (or a few), since having a nested query won't be able to join on an index.

10 Comments

Unfortunately, this is breaking the query.
Did you copy it verbatim? I obviously can't test it but the where clause was just for example..
@calcinai but wouldn't the inline select have to execute every time for each of the records returned? On a small data set I could see this being efficient but on a larger one, I see this taking longer. (guess I need to spend some time testing it)
Exactly, that's why I made the comment about only using this method on a small dataset. I use small as a relative term - if the total users are only 100's there would be negligible difference.
@Becky This query is working with your fiddle - sqlfiddle.com/#!9/0aea16/3
|
0

I would imagine this should work but I have not tested it.

SELECT c.*, p.user_id, p.img, MAX(p.id) /* not sure if you need MAX(p.id) but try it with/without it here */
FROM home_comments c
LEFT OUTER JOIN profile_img p on p.user_id = c.user_id
WHERE p.id = MAX(p.id)
ORDER BY c.id DESC

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.