views:

122

answers:

2

I have three tables.

posts
| id      | title     |
+---------+-----------+
| 1       | hello     |
| 2       | goodbye   |
+---------+-----------+

posts_tags
| tag_id  | post_id   |
+---------+-----------+
| 1       | 1         |
| 2       | 1         |
| 2       | 2         |
+---------+-----------+

tags
| id      | name      |
+---------+-----------+
| 1       | news      |
| 2       | photos    |
+---------+-----------+

I want to be able to select the posts, but have this as a result

post.id    post.title    tags
------------------------------------
1          hello         news,photos
2          goodbye       photos

Something like

SELECT *,
       GROUP_CONCAT(tags.name) AS tags
FROM posts
    LEFT JOIN posts_tags
        ON posts.id = posts_tags.post_id
    LEFT JOIN tags
        ON posts_tags.tag_id = tags.id

doesn't seem to work properly. Please advise, thanks for your time :)

+3  A: 

You need to add a GROUP BY clause to your query:

SELECT posts.*,
       GROUP_CONCAT(tags.name ORDER BY tags.name) AS tags
FROM posts
    LEFT JOIN posts_tags
        ON posts.id = posts_tags.post_id
    LEFT JOIN tags
        ON posts_tags.tag_id = tags.id
GROUP BY posts.id

I also added an order to the GROUP_CONCAT above to get the tags concatenated in the order you specified.

Phil Ross
+1  A: 

The better will be storing tags additionally in a string right in posts table too to prevent additional joins and grouping. Just as performance denormalization.

zerkms
I have multilingual tags so I am kind of forced to normalize the tags. Do you perhaps have any other suggestions on how I could denormalize? If so, maybe I can start a question on it
Axsuul
your schema doesn't reflects i18n of tags. did you mean that tag "photo" will be translated into different languages before displaying?where? in presentation layer? if so - then i don't see any difference between proposal above (with GROUP_CONCAT) and mine. both of them produce list of tags as comma-separated string.ps: anyway, i think that tags are not appropriate entities to internationalize...
zerkms
yea i suppose the tag will be translated. I was hoping to store different translations for each tag in the database if it were to be normalized
Axsuul
then there is no difference between my proposal with denormalization (that will be fast) and complex query ;-) in both cases you have to explode string into array using "," as separator. meanwhile - it's possible to store serialized array of tags in the "posts.tags" field. in this case all you have to do - is only unserialize it.
zerkms
hey zerkms, i ended up going with denormalized tags :) thanks for the recommendation
Axsuul