Reputation: 935
I try to select data from 4 table (last table need to count data)
My MySQL tables structure
users
id
username
images
id
user_id
image
user_follow
id
user_id
follow_id
commentaries
id
user_id
image_id
text
I have got this SQL query:
$sql = "SELECT u.username as user, i.image as user_image, p.image, p.date
FROM users u
LEFT JOIN user_follow f ON u.id = f.follow_id
LEFT JOIN images p ON p.user_id = u.id
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
WHERE f.user_id = 3 OR p.user_id = 3
ORDER BY p.date DESC";
This line return user current image (last image)
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
it returns all images from me and my friends
[0] => Array
(
[user] => 8888
[user_image] => second.jpg
[image] => second.jpg
[date] => 2012-01-24 14:42:27
)
[1] => Array
(
[user] => 8888
[user_image] => second.jpg
[image] => first.jpg
[date] => 2012-01-24 14:42:27
)
[2] => Array
(
[user] => 3333
[user_image] => ax46l7v7vugnesk10whk_339.jpg
[image] => ax46l7v7vugnesk10whk_339.jpg
[date] => 2012-01-24 01:54:19
)
[3] => Array
(
[user] => 3333
[user_image] => ax46l7v7vugnesk10whk_339.jpg
[image] => aaaaaaaa.jpg
[date] => 2012-01-24 01:49:57
)
I tried to add
left join commentaries c ON c.user_id = u.id
and result was
[2] => Array
(
[user] => 3333
[user_image] => ax46l7v7vugnesk10whk_339.jpg
[image] => ax46l7v7vugnesk10whk_339.jpg
[date] => 2012-01-24 01:54:19
[id] => 1
)
[3] => Array
(
[user] => 3333
[user_image] => ax46l7v7vugnesk10whk_339.jpg
[image] => ax46l7v7vugnesk10whk_339.jpg
[date] => 2012-01-24 01:54:19
[id] => 2
)
[4] => Array
(
[user] => 3333
[user_image] => ax46l7v7vugnesk10whk_339.jpg
[image] => aaaaaaaa.jpg
[date] => 2012-01-24 01:49:57
[id] => 1
)
[5] => Array
(
[user] => 3333
[user_image] => ax46l7v7vugnesk10whk_339.jpg
[image] => aaaaaaaa.jpg
[date] => 2012-01-24 01:49:57
[id] => 2
)
Duplicate user if it have commentaries (By the way [user] => 3333 have 2 comments in example)
I am trying to add one more table "commentaries" and count how many commentaries have every picture (from me and my friends) if no commentaries with such $user_id then return 0
Upvotes: 4
Views: 297
Reputation: 753
You really know how to make a question confusing. The issue here is that you're not understanding the consequences of your joins.
Using your example. You have a table (users in this case), that has one to many relationships to two other tables (images and commentaries).
Such as this:
users
/ \
images commentaries
When you try to join both of these related tables to your base table simultaneously, the effect is to produce the equivalent of a full outer join between the two child tables.
This:
SELECT *
FROM users u
LEFT JOIN images p ON p.user_id = u.id
LEFT JOIN commentaries c ON c.user_id = u.id
is precisely the same as this:
SELECT *
FROM images p
LEFT JOIN commentaries c ON c.user_id = p.user_id
(in terms of the number of records produced)
It would be fine if one of the child tables had a 1 to 1 relationship with the parent table, but they don't. Since they both have multiple records in them, the effect is a FULL OUTER JOIN and the result is a multiplication of the number of records produced in the output. The output will contain a number or records equal to the number of matching records in the one table multiplied by the number of matching records in the other table. Thus, since you have two records in each table matching that user_id, the result set contains four records.
It's difficult to understand the last part of your question, so some clarification would be nice. It seems as though you're trying to only count the records from one table or the other, although frankly I'm uncertain which.
The following line is extremely confusing.
count how many commentaries have every picture
If you do, in fact, only wish to count the records from one table or the other, then grouping will solve your multiplication issue.
$sql = "SELECT u.username as user, i.image as user_image, p.image, p.date, c.commentcount
FROM users u
LEFT JOIN user_follow f ON u.id = f.follow_id
LEFT JOIN images p ON p.user_id = u.id
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
LEFT JOIN (SELECT x.user_id, COUNT(*) AS commentcount FROM commentaries x GROUP BY x.user_id) c ON c.user_id = u.id
WHERE f.user_id = 3 OR p.user_id = 3
ORDER BY p.date DESC";
The trouble with this, as was commented earlier, is that it has essentially nothing to do with the images. There is no discernible direct link between images and commentaries. Only a many to many relationship exists between them via the users table. So, it's very difficult for me to be certain this helps you at all.
Essentially, this only gives you the number of comments a user has. It has nothing to do with images. You could use very similar code to tell you how many images a user has, but that has nothing to do with the comments.
If what you wish to do, is determine how many of one the user has, if the user has the other at all, then this will answer that question. You would simply add a test in the WHERE clause to determine if the user has the required related record or not.
If you can clarify your intent, I may be able to help more. Otherwise, I hope this helps.
Upvotes: 2
Reputation: 12356
You need to use GROUP BY
to count rows in groups (in your case comments for every image). This query should do the trick:
SELECT u.username as user, i.image as user_image, p.image, p.date,
COALESCE ( imgcount.cnt, 0 ) as comments
FROM users u
LEFT JOIN user_follow f ON u.id = f.follow_id
LEFT JOIN images p ON p.user_id = u.id
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
LEFT JOIN
( SELECT image_id, COUNT(*) as cnt FROM
commentaries
GROUP BY image_id ) imgcount
ON p.id = imgcount.image_id
WHERE f.user_id = 3 OR p.user_id = 3
ORDER BY p.date DESC
Upvotes: 2