views:

29

answers:

3

I’m trying to display a list of shops each with 3 random items from their shop, if they have 3 or more listings, that are actively advertising. I have 3 tables: one for the shops – “Shops”, one for the listings – “Listings” and one that tracks active advertisers – “AdShops”.

Using the below statement, the listings returned are random however I’m not getting exactly 3 listings (rows) returned per shop.

SELECT AdShops.ID, Shops.url, Shops.image_url, Shops.user_name AS shop_name,
       Shops.title, L.listing_id AS listing_id, L.title AS listing_title,
       L.price as price, L.image_url AS listing_image_url, L.url AS listing_url
FROM   AdShops INNER JOIN
       Shops ON AdShops.user_id = Shops.user_id INNER JOIN
       Listings AS L ON Shops.user_id = L.user_id
WHERE  (Shops.is_vacation = 0 AND Shops.listing_count > 2 AND 
        L.listing_id IN
            (SELECT TOP 3 L2.listing_id
             FROM   Listings AS L2
             WHERE  L2.listing_id IN 
                 (SELECT TOP 100 PERCENT L3.listing_id
                  FROM   Listings AS L3
                  WHERE  (L3.user_id = L.user_id)
                 )
             ORDER BY NEWID()
            )
       )
ORDER BY Shops.shop_name

I’m stumped. Anyone have any ideas on how to fix it?

The ideal solution would be one record per store with the 3 listings (and associated data) were in columns and not rows – is this possible?

A: 

I had an answer but then saw that you already used my solution, so I'm kinda stumped too!

Younes
@Younes: This answer won't really help. Consider deleting it, since the question will attract more attention without answer...
Peter Lang
This only returns 3 rows, one item per shop. For the purpose of this issue, lests say we're expecting 100 shops to be returned, each with 3 random listings - A total 300 rows expected.Anyone else have any ideas???
GraGra33
+1  A: 

If I'm not mistaken, below query should give you every user_id having at least 3 random listing_id's.

SELECT  user_id
        , listing_id
FROM    (
          SELECT  l.user_id 
                  , l.listing_id
                  , RowNumber = ROW_NUMBER() OVER (PARTITION BY l.user_id ORDER BY NEWID())
          FROM    Listings l
                  INNER JOIN (
                    SELECT  user_id
                    FROM    Listings
                    GROUP BY
                            user_id
                    HAVING  COUNT(*) >= 3
                  ) cnt ON cnt.user_id = l.user_id  
        ) l 
WHERE   l.RowNumber <= 3
Lieven
Brilliant! I've heard of the ROW_NUMBER() OVER (PARTITION method but have never used it before - thanks so much! I'll post the full solution in an answer for those who are interested...
GraGra33
@GraGra33: Glad it works for you. I don't think that posting the full solution will add any value though. Make sure to accept Lievens answer (http://meta.stackoverflow.com/questions/5234/accepting-answers-what-is-it-all-about), and I would also up-vote it :)
Peter Lang
Thanks! Will do...
GraGra33
+1  A: 

Thanks to Lieven for the key to the problem. Full solution is as follows:

SELECT AdShops.ID, Shops.url, Shops.image_url, 
       Shops.user_name AS shop_name, Shops.title, L.listing_id AS listing_id, 
       L.title AS listing_title, L.price as price,
       L.image_url AS listing_image_url, L.url AS listing_url
FROM   AdShops INNER JOIN
       Shops ON AdShops.user_id = Shops.user_id INNER JOIN
       Listings AS L ON Shops.user_id = L.user_id
WHERE  (Shops.is_vacation = 0 AND Shops.listing_count > 2 AND 
        L.listing_id IN
            (SELECT listing_id
             FROM    
                 (SELECT l2.user_id , l2.listing_id, RowNumber = ROW_NUMBER() 
                  OVER   (PARTITION BY l2.user_id ORDER BY NEWID())
                  FROM   Listings l2 INNER JOIN
                      (SELECT   user_id
                       FROM     Listings
                       GROUP BY user_id
                       HAVING   COUNT(*) >= 3
                      ) cnt ON cnt.user_id = l2.user_id  
                 ) l2 
             WHERE l2.RowNumber <= 3 and L2.user_id = L.user_id
            )
       )
ORDER BY Shops.shop_name

Enjoy!

GraGra33