1

I have a problem trying to JOIN an empty table (comments table) to my existing prepared statement.

This is working perfectly:

// prepare images
if ($stmt = $mysqli->prepare("  SELECT uu.*, m.*,
                                                (
                                                    SELECT COUNT(*)
                                                    FROM img_likes AS t
                                                    WHERE t.img_id = uu.imgID AND t.user_id = ?
                                                ) AS user_likes,
                                                (
                                                    SELECT COUNT(*)
                                                    FROM img_likes AS t
                                                    WHERE t.img_id = uu.imgID
                                                ) AS total_likes
                                FROM user_uploads AS uu
                                INNER JOIN members AS m ON m.id = uu.user_id
                                ORDER BY up_time DESC")) {
    $stmt->bind_param('i', $user_id);
    $stmt->execute(); // get imgs

    // foreach print images
    // working as expected
}

And I don't know why if I JOIN another table (img_comments) that is empty, the images are not printed... if I add a row to the table and refresh the page, one image is printed...

The statement that I'm trying and it's not working is this:

SELECT uu.*, m.*, ic.*,
                (
                    SELECT COUNT(*)
                    FROM img_likes AS t
                    WHERE t.img_id = uu.imgID AND t.user_id = ?
                ) AS user_likes,
                (
                    SELECT COUNT(*)
                    FROM img_likes AS t
                    WHERE t.img_id = uu.imgID
                ) AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
INNER JOIN img_comments AS ic ON ic.img_id = uu.imgID
ORDER BY up_time DESC

Why is only printing images based on the number of the table rows?? I also tried LEFT JOIN but I'm not too familiareize with this. I only use INNER JOIN in other scripts and I never had a problem like this.

I would appreciate any optimization to my query.

Chazy Chaz
  • 1,781
  • 3
  • 29
  • 48
  • 1
    view this example of joins - http://stackoverflow.com/a/19267314/689579. As you will see in the center `INNER JOIN` will only produce results where the tables intersect. – Sean Nov 17 '14 at 06:15

2 Answers2

3

What does an inner join do? It joins all records of table a with all matching records of table b. So when there are no records in table b, there is no match for any record of table a, hence no result at all. Why does this surprise you?

A left join is an outer join (short for LEFT OUTER JOIN). It means: Give me all records of table a with all matching records of table b, and when there is no match then give me the record of table a anyhow. This seems to be what you are wanting here. But you say you tried it. I don't see how this would fail in your query.

A typical error for an outer join not to work would be to have some field of b in your where clause (e.g. where b.id > 100). As the outer-joined records have no matching b record, all b fields are null, so that such a where clause would fail. You'd just get matches again, just like with the inner join.

EDIT: As to optimization, you can get the two counts in one pass by counting conditionally:

SELECT 
  uu.*, m.*, ic.*,
  il.count_user AS user_likes,
  il.count_total AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
LEFT OUTER JOIN img_comments AS ic ON ic.img_id = uu.imgID
LEFT OUTER JOIN
(
  select 
    img_id, 
    count(*) as count_total,
    count(case when t.user_id = ? then 1 end) as count_user
  from img_likes
  group by img_id
) AS il ON il.img_id = uu.imgID
ORDER BY uu.up_time DESC;
Thorsten Kettner
  • 89,309
  • 7
  • 49
  • 73
0

As far as I know, INNER JOIN will only retrieve data which have both data. So if let say the table that you join have no data with that join condition. It will not return any data at all.

LEFT JOIN is just a normal join. It will retrieve data on both table. But if the joined table is empty, then only the primary table will have data, the secondary table will have null as its data.

You can just modify your code, replacing INNER JOIN with LEFT JOIN and see if it works/

Nizam
  • 505
  • 1
  • 8
  • 20