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/']
I'm taking it that you mean that different "people" that are conducting simultaneous requests should not get the same random row? The most robust way, without testing it, in order to avoid the minute chance of the same record being selected twice in two running requests will probably be to lock the table and perform the read and update in a transaction. You would have to use a storage engine that supports this, such as InnoDB.

The way to accomplish `LOCK TABLES` and `UNLOCK TABLES` with transactional tables, such as InnoDB tables, is to begin a transaction with `SET autocommit = 0`, **not** `START TRANSACTION`, followed by `LOCK TABLES`. Then you should not call `UNLOCK TABLES` until you commit the transaction explicitly. 

For example, if you need to read and write to your table in one go, you can do this:

```
SET autocommit = 0;
LOCK TABLES ad_banner_queue AS ad_banner_queue_w WRITE, ad_banner_queue AS ad_banner_queue_r READ;
... perform your select query on ad_banner_queue_r, then update that row in ad_banner_queue_w with is_sent = 1...
COMMIT;
UNLOCK TABLES;

```

The reason we lock with an alias is that you [cannot refer to a locked table multiple times in a single query using the same name](https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html). So we use aliases instead and obtain a separate lock for the table and each alias.
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.