views:

38

answers:

2

Let's say I have the following tables:

TAGS

id: integer
name: string

POSTS

id: integer
body: text

TAGGINGS

id: integer
tag_id: integer
post_id: integer

How would I go about writing a query that selects all posts in order of the post containing the highest number of the following tags (name attribute of tags table): "Cheese", "Wine", "Paris", "Frace", "City", "Scenic", "Art"

See also: http://stackoverflow.com/questions/3876240/need-help-with-sql-query-involving-tagging (note: similar, but not a duplicate!)

+3  A: 

Unlike your linked question, you did not specify here that you needed to match ALL tags. This query works for ANY.

SELECT p.id, p.text, count(tg.id) as TagCount
    FROM Posts p 
        INNER JOIN Taggings tg 
            ON p.id = tg.post_id
        INNER JOIN Tags t 
            ON tg.tag_id = t.id
    WHERE t.name in ('Cheese', 'Wine', 'Paris', 'Frace', 'City', 'Scenic', 'Art')
    GROUP BY p.id, p.text
    ORDER BY TagCount DESC
Joe Stefanelli
correct, they do not need to match all... just return first the one that matchs more than others
tybro0103
In reality, I actually have many more fields on post than just id and text... is there a way to make it return all the fields without specifying each in the query? Maybe p.*? I'm not a sql expert.
tybro0103
Don't use * in your queries. List all the columns you need in both the `SELECT` and the `GROUP BY`.
Joe Stefanelli
Why? I need to use all of the columns.
tybro0103
There are several reasons why `SELECT *` is a bad idea. One of the key ones is that you limit the optimizer's ability to choose an appropriate index. See [here](http://dotnethitman.spaces.live.com/blog/cns!E149A8B1E1C25B14!204.entry). Also, for code stability, if someone should alter the POSTS table in the future and add a new column, your `SELECT *` is going to pick it up and probably break your application that was expecting to get back 2 columns and is now getting 3 returned.
Joe Stefanelli
I see... I'm used to using ruby on rails where sql is usually generated and by default uses *
tybro0103
A: 

Try This:

   Select p.Id, p.Text, Count(*)
   From Posts p 
      Left Join (Taggings tg Join Tags t 
                    On t.Tag_Id = tg.Tag_Id
                       And t.name in     
                        ('Cheese', 'Wine', 'Paris', 
                         'Frace', 'City', 'Scenic', 'Art'))
         On tg.Post_Id = p.Post_Id
   Group By p.Id, p.text  
   Order By Count(*) Desc
Charles Bretana