I have one table as ad\_banner\_queue which is i am using to generate the Queue based on weightage of ads. Ads are inserted into advertisement table. Queue will be generated if all existing ads which are in queue delivered to user.

Now the issue is how should i prevent to sending the duplicate ads in case of request came at same time and Rand() returned the same record?

Below is the Code:

```
<?php
/* To Get the random Ad */
public function getBanner($params) {
    /* Fetch the Random from table */
    $ads_queue = (new \yii\db\Query())
            ->select('ad_quque_id, banner_image, unique_code')
            ->from('ad_banner_queue')
            ->join('inner join', 'advertisement', 'ad_banner_queue.ad_id = advertisement.ad_id')
            ->where('is_sent=0')
            ->orderBy('RAND()')
            ->one();

    /* In case of queue is not there generate the new queue */
    if ($ads_queue === false) {
        $output = $this->generateAdQueue();
        //In case of something went wrong while generating the queue
        if ($output == false) {
            return array();
        }

        //Now fetch the record again
        $ads_queue = (new \yii\db\Query())
                ->select('ad_quque_id, banner_image, unique_code')
                ->from('ad_banner_queue')
                ->join('inner join', 'advertisement', 'ad_banner_queue.ad_id = advertisement.ad_id')
                ->where('is_sent=0')
                ->orderBy('RAND()')
                ->one();
    }

    /* Now, marked that one as is_sent */
    Yii::$app->db->createCommand()->update('ad_banner_queue', ['is_sent' => 1], 'ad_quque_id =:ad_quque_id', array(':ad_quque_id' => $ads_queue['ad_quque_id']))->execute();
    return $ads_queue;
}

/**
 * Below will Generate the Queue if not exist
 */
public function generateAdQueue() {
    /* First check thatt there is existing queue, if so don't generate it */
    $data_exist = (new \yii\db\Query())
            ->select('ad_quque_id')
            ->from('ad_banner_queue')
            ->where('is_sent=0')
            ->scalar();
    if ($data_exist === false) {
        /* Delete all other entries */
        (new \yii\db\Query())
                ->createCommand()
                ->delete('ad_banner_queue')
                ->execute();

        /* Fetch all banner */
        $ads = (new \yii\db\Query())
                ->select('ad_id, unique_code, ad_name, banner_image,ad_delivery_weightage')
                ->from('advertisement')
                ->where('status_id in (8)') //Means only fetch Approved ads
                ->all();
        if (!empty($ads)) {
            foreach ($ads as $ad) {
                /* Make entry as per that weightage, example, if weightage is 10 then make entry 10 times */
                $ins_fields = array();
                for ($i = 1; $i <= $ad['ad_delivery_weightage']; $i++) {
                    $ins_fields[] = array($ad['ad_id']);
                }
                Yii::$app->db->createCommand()->batchInsert('ad_banner_queue', ['ad_id'], $ins_fields)->execute();
            }
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

```
['https://Stackoverflow.com/questions/52426582', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/1773177/']
Presumably, the ads are presented from separate pages. HTML is "stateless", so you cannot expect one page to know what ads have previously been displayed. So, you have to either pass this info from page to page, or store it somewhere in the database associated with the individual user.

You also want some randomizing? Let's do both things at the same time.

What is the "state"? There is an "initial state", at which time you randomly pick the first ad to display. And you pass that info on to the next page (in the url or in a cookie or in the database).

The other "state" looks at the previous state and computes which ad to display next. (Eventually, you need to worry about running out of ads -- will you start over? Will you re-randomize? Etc.)

But how to avoid showing the same "random" ad twice in a row?

* You have N ads -- `SELECT COUNT(*) ...`
* You picked add number J as the first ad to display -- simple application of `RAND()`, either in SQL or in the app.
* Pick a number, M, such that M and N are "relatively prime".
* The "next" ad is number (J := (J + M) mod N). This will cycle through all the ads without duplicating until all have been shown. -- Again, this can be done in SQL or in the ap.
* Pass J and M from one page to the next.

To get the J'th row: Either have the rows uniquely *and* consecutively numbered; or use `ORDER BY ... LIMIT 1 OFFSET J`. (Caveat: it may be tricky to fill J into the SQL.)

No table locks, no mutexes, just passing info from one page to the next.
You can use transactions and SELECT FOR UPDATE construction for lock data and consistent executing of queries. For instance:

```
public function getAds()
{
    $db = Yii::$app->db;
    $transaction = $db->beginTransaction(Transaction::REPEATABLE_READ);
    try {
        $ads_queue = (new \yii\db\Query())
            ->select('ad_quque_id, banner_image, unique_code')
            ->from('ad_banner_queue')
            ->join('inner join', 'advertisement', 'ad_banner_queue.ad_id = advertisement.ad_id')
            ->where(new Expression('is_sent=0 FOR UPDATE'))
            ->orderBy('RAND()')
            ->one();
        if ($ads_queue === false) {
            $transaction->commit();
            return null;
        }
        $db->createCommand()->update('ad_banner_queue', ['is_sent' => 1], 'ad_quque_id =:ad_quque_id', array(':ad_quque_id' => $ads_queue['ad_quque_id']))->execute();      
        $transaction->commit();
        return $ads_queue;
    } catch(Exception $e) {
        $transaction->rollBack();
        throw $e;
    }
}

public function getBanner($params)
{
    $ads_queue = $this->getAds();
    if (is_null($ads_queue)) {
        $output = $this->generateAdQueue();        
        if ($output == false) {
            return array();
        }
        $ads_queue = $this->getAds();
    }
    return $ads_queue;
}

```