Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 3796122
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 19, 20262026-05-19T13:11:15+00:00 2026-05-19T13:11:15+00:00

I have the following query, which retrieves 4 adverts from certain categories in a

  • 0

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
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-19T13:11:16+00:00Added an answer on May 19, 2026 at 1:11 pm

    Note: The solution is the last query at the bottom of this answer.

    Test Schema and Data

    create table adverts (
        advert_id int primary key, title varchar(20), url varchar(20), user_id int, advert_type varchar(10))
    ;
    create table advert_categories (
        advert_id int, category_id int, primary key(category_id, advert_id))
    ;
    create table website_categories (
        website_id int, category_id int, primary key(website_id, category_id))
    ;
    insert website_categories values
        (8,1),(8,3),(8,5),
        (1,1),(2,3),(4,5)
    ;
    insert adverts (advert_id, title, user_id) values
        (1, 'StackExchange', 1),
        (2, 'StackOverflow', 1),
        (3, 'SuperUser', 1),
        (4, 'ServerFault', 1),
        (5, 'Programming', 1),
        (6, 'C#', 2),
        (7, 'Java', 2),
        (8, 'Python', 2),
        (9, 'Perl', 2),
       (10, 'Google', 3)
    ;
    update adverts set advert_type = 'text'
    ;
    insert advert_categories values
        (1,1),(1,3),
        (2,3),(2,4),
        (3,1),(3,2),(3,3),(3,4),
        (4,1),
        (5,4),
        (6,1),(6,4),
        (7,2),
        (8,1),
        (9,3),
       (10,3),(10,5)
    ;
    

    Data properties

    • each website can belong to multiple categories
    • for simplicity, all adverts are of type ‘text’
    • each advert can belong to multiple categories. If a website has multiple categories that are matched multiple times in advert_categories for the same user_id, this causes the advert_id’s to show twice when using a straight join between 3 tables in the next query.

    This query joins the 3 tables together (notice that ids 1, 3 and 10 each appear twice)

    select *
    from website_categories wc
    inner join advert_categories ac on wc.category_id = ac.category_id
    inner join adverts a on a.advert_id = ac.advert_id and  a.advert_type = 'text'
    where wc.website_id='8'
    order by a.advert_id
    

    To make each website show only once, this is the core query to show all eligible ads, each only once

            select *
            from adverts a
            where a.advert_type = 'text'
              and exists (
                select *
                from website_categories wc
                inner join advert_categories ac on wc.category_id = ac.category_id
                where wc.website_id='8'
                  and a.advert_id = ac.advert_id)
    

    The next query retrieves all the advert_id’s to be shown

    select advert_id, user_id
    from (
        select
            advert_id, user_id,
            @r := @r + 1 r
        from (select @r:=0) r
        cross join 
        (
            # core query -- vvv
            select a.advert_id, a.user_id
            from adverts a
            where a.advert_type = 'text'
              and exists (
                select *
                from website_categories wc
                inner join advert_categories ac on wc.category_id = ac.category_id
                where wc.website_id='8'
                  and a.advert_id = ac.advert_id)
            # core query -- ^^^
            order by rand()
        ) EligibleAdsAndUserIDs
    ) RowNumbered
    group by user_id
    order by r
    limit 2
    

    There are 3 levels to this query

    1. aliased EligibleAdsAndUserIDs: core query, sorted randomly using order by rand()
    2. aliased RowNumbered: row number added to core query, using MySQL side-effecting @variables
    3. the outermost query forces mysql to collect rows as numbered randomly in the inner queries, and group by user_id causes it to retain only the first row for each user_id. limit 2 causes 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 adverts to retrieve the required columns.

    1. only once per user_id
    2. feature user’s with more ads proportionally (statistically) to the number of eligible ads they have

    Note: Point (2) works because the more ads you have, the more likely you will hit the top placings in the row numbering subquery

    select a.advert_id, a.title, a.url, a.user_id
    from
    (
        select advert_id
        from (
            select
                advert_id, user_id,
                @r := @r + 1 r
            from (select @r:=0) r
            cross join 
            (
                # core query -- vvv
                select a.advert_id, a.user_id
                from adverts a
                where a.advert_type = 'text'
                  and exists (
                    select *
                    from website_categories wc
                    inner join advert_categories ac on wc.category_id = ac.category_id
                    where wc.website_id='8'
                      and a.advert_id = ac.advert_id)
                # core query -- ^^^
                order by rand()
            ) EligibleAdsAndUserIDs
        ) RowNumbered
        group by user_id
        order by r
        limit 2
    ) Top2
    inner join adverts a on a.advert_id = Top2.advert_id;
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have following query: Select * from Students which retrieves: Id , Name ,
I have following query which take more than a minute to execute, how can
I have the following query which have 1000 rows select staffdiscountstartdate,datediff(day,groupstartdate,staffdiscountstartdate), EmployeeID from tblEmployees
I have following somewhat complex sql query which has horrible performance, 'certainly' due to
I have the following Django Model which retrieves 3 records from a database. The
I have the following code, which retrieves the page slugs from the database which
I have a following method, which retrieves top visited pages from Google Analytics: public
I have the following query which is working fine, but I also want to
I have the following query which works: SELECT ?page ?lat ?long (bif:st_distance(?geo, bif:st_point(42.883, -72.8981)))
I have the following query which returns a list of questions and the possible

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.