views:

195

answers:

4

Hi,

I need to get 5 random records from a table plus a further record based on data from the users preferences as stored in a second table.

Here are the two statements i have created so far:

Gets favourite charity based on key set in TBL_MEMBERS:

SELECT DISTINCT TBL_CHARITIES.* FROM TBL_CHARITIES JOIN TBL_MEMBERS ON TBL_CHARITIES.cha_Key = TBL_MEMBERS.members_Favourite WHERE TBL_MEMBERS.members_Id = 16

Gets 5 random charities:

SELECT TOP 5 * FROM TBL_CHARITIES WHERE cha_Active = 'TRUE' AND cha_Key != '1' ORDER BY NEWID();

When used in a stored procedure it only returns the first SELECT statement to my .Net page. How can i combine the two statements whilst ensuring that no results are repeated (Eg the favourite is not present in the 5 random records?

Many Thanks!


Ok! So now ive updated things and got the following:

CREATE PROCEDURE web.getRandomCharities ( @tmp_ID bigint --members ID ) AS BEGIN

WITH    q AS
 (
 SELECT  TOP 5 *
 FROM    TBL_CHARITIES
 WHERE   cha_Active = 'TRUE'
         AND cha_Key != '1'
 ORDER BY NEWID()
 )

SELECT * FROM q 
 UNION ALL 
 SELECT TOP 1 * FROM ( 
         SELECT * FROM TBL_CHARITIES WHERE TBL_CHARITIES.cha_Key IN 
         ( SELECT members_Favourite FROM TBL_MEMBERS WHERE members_Id = @tmp_ID )        EXCEPT SELECT * FROM q ) tc

END

Now i need to be able to the record "cha_Key == '1'" but only if its not the users favourite. Is this possible?

Thanks for everything so far. ITs truly appreciated.

+1  A: 

Just UNION ALL them:

 WITH    q AS
         (
         SELECT  TOP 5 *
         FROM    TBL_CHARITIES
         WHERE   cha_Active = 'TRUE'
                 AND cha_Key != '1'
         ORDER BY NEWID()
         )
 SELECT  *
 FROM    q
 UNION ALL
 SELECT  TOP 1 *
 FROM    (
         SELECT  *
         FROM    TBL_CHARITIES
         WHERE   TBL_CHARITIES.cha_Key IN
                 (
                 SELECT  members_Favourite
                 FROM    TBL_MEMBERS
                 WHERE   members_Id = 16
                 )
         EXCEPT
         SELECT  *
         FROM    q
         ) tc

Update:

Unfortunately, the query above will not work as intended, since CTE's are reevaluated in SQL Server, and the second instance of q will give different records.

See this post in my blog for more detail:

You need to rewrite the query as this:

 WITH    q AS
         (
         SELECT  TOP 5 *
         FROM    TBL_CHARITIES
         WHERE   cha_Active = 'TRUE'
                 AND cha_Key != '1'
         ORDER BY
                 NEWID()
         ),
         r AS
         (
         SELECT  *
         FROM    TBL_CHARITIES
         WHERE   TBL_CHARITIES.cha_Key IN
                 (
                 SELECT  members_Favourite
                 FROM    TBL_MEMBERS
                 WHERE   members_Id = 16
                 )
         )
 SELECT  TOP 6 *
 FROM    q
 FULL OUTER JOIN
         r
 JOIN    TBL_CHARITIES t
 ON      t.id = COALESCE(q.id, r.id)
 ORDER BY
         q.id

, assuming that id is the PRIMARY KEY of TBL_CHARITIES.

Quassnoi
This doesn't handle the 'no duplicates' part of the specification.
Matt Howells
@Matt: you're right, fixed.
Quassnoi
A: 

I would suggest pulling down a list of IDs to your .Net page and use your background code to randomly select N number of IDs and pass that as a parameter to your query. You can exclude the user's favorite by using where id != BL_MEMBERS.members_Favourite in the query which retrieves the existing IDs,.

This allows you to increase/decrease the number of randomly selected items fairly easily and moves the random generation and checks for unique items to .Net where it is accomplished much more easily.

Rob Allen
A: 

try this

 SELECT  *
 FROM    (
         SELECT  TOP 5 *
         FROM    TBL_CHARITIES
         WHERE   cha_Active = 'TRUE'
                 AND cha_Key != '1'
      AND cha_Key not in(SELECT  TBL_MEMBERS.members_Favourite
            WHERE   TBL_MEMBERS.members_Id = 16)
         ORDER BY NEWID()
         ) q
 UNION ALL
 SELECT  TOP 1 TBL_CHARITIES.*
 FROM    TBL_CHARITIES
 WHERE   TBL_CHARITIES.cha_Key IN
         (
         SELECT  TBL_MEMBERS.members_Favourite
         FROM    TBL_MEMBERS
         WHERE   TBL_MEMBERS.members_Id = 16
         )
SQLMenace
Adding condition into the first query restricts the set beyond what the `@op` is asking for. Random `cha_Key` can be a favourite as well, that's the whole point of constraining the second set.
Quassnoi
And you didn't fix the `FROM` clause when copying the query ;)
Quassnoi
A: 

Create a Stored Procedure with a parameter @Memeber_ID.

Then do the type of code that Quassnoi said with a some modifications.

So, pull the top 5 records, but add a join to TBL_MEMBERS and where clause that the records pulled can't be that's memeber_ID's selection. Then do a UNION to that members selection.

Chad