I have the following query, which retrieves 4 adverts from certain categories in a random order.
At the moment, if a user has more than 1 advert, then potentially all of those ads might be retrieved – I need to limit it so that only 1 ad per user is displayed.
Is this possible to achieve in the same query?
SELECT a.advert_id, a.title, a.url, a.user_id,
FLOOR(1 + RAND() * x.m_id) 'rand_ind'
FROM adverts AS a
INNER JOIN advert_categories AS ac
ON a.advert_id = ac.advert_id,
(
SELECT MAX(t.advert_id) - 1 'm_id'
FROM adverts t
) x
WHERE ac.category_id IN
(
SELECT category_id
FROM website_categories
WHERE website_id = '8'
)
AND a.advert_type = 'text'
GROUP BY a.advert_id
ORDER BY rand_ind
LIMIT 4
Note: The solution is the last query at the bottom of this answer.
Test Schema and Data
Data properties
This query joins the 3 tables together (notice that ids 1, 3 and 10 each appear twice)
To make each website show only once, this is the core query to show all eligible ads, each only once
The next query retrieves all the advert_id’s to be shown
There are 3 levels to this query
EligibleAdsAndUserIDs: core query, sorted randomly usingorder by rand()RowNumbered: row number added to core query, using MySQL side-effecting @variablesas numberedrandomly in the inner queries, andgroup by user_idcauses it to retain only the first row for each user_id.limit 2causes the query to stop as soon as two distinct user_id’s have been encountered.This is the final query which takes the advert_id’s from the previous query and joins it back to table
advertsto retrieve the required columns.Note: Point (2) works because the more ads you have, the more likely you will hit the top placings in the row numbering subquery